This commit is contained in:
ideaa
2025-05-23 18:22:27 +08:00
parent eb04ace652
commit 57cb28f47e
19 changed files with 538 additions and 1 deletions

9
cmd/aqi/main.go Normal file
View File

@@ -0,0 +1,9 @@
package main
import (
"github.com/wonli/aqi/internal/cli"
)
func main() {
cli.Execute()
}

4
go.mod
View File

@@ -13,11 +13,13 @@ require (
github.com/hibiken/asynq v0.24.1 github.com/hibiken/asynq v0.24.1
github.com/redis/go-redis/v9 v9.0.3 github.com/redis/go-redis/v9 v9.0.3
github.com/shirou/gopsutil/v3 v3.24.4 github.com/shirou/gopsutil/v3 v3.24.4
github.com/spf13/cobra v1.9.1
github.com/spf13/viper v1.19.0 github.com/spf13/viper v1.19.0
github.com/stretchr/testify v1.9.0 github.com/stretchr/testify v1.9.0
github.com/tidwall/gjson v1.17.3 github.com/tidwall/gjson v1.17.3
go.uber.org/zap v1.27.0 go.uber.org/zap v1.27.0
golang.org/x/exp v0.0.0-20240808152545-0cdaa3abc0fa golang.org/x/exp v0.0.0-20240808152545-0cdaa3abc0fa
golang.org/x/time v0.5.0
gopkg.in/natefinch/lumberjack.v2 v2.2.1 gopkg.in/natefinch/lumberjack.v2 v2.2.1
gopkg.in/yaml.v3 v3.0.1 gopkg.in/yaml.v3 v3.0.1
gorm.io/datatypes v1.2.5 gorm.io/datatypes v1.2.5
@@ -48,6 +50,7 @@ require (
github.com/golang/protobuf v1.5.3 // indirect github.com/golang/protobuf v1.5.3 // indirect
github.com/google/uuid v1.6.0 // indirect github.com/google/uuid v1.6.0 // indirect
github.com/hashicorp/hcl v1.0.0 // indirect github.com/hashicorp/hcl v1.0.0 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/jinzhu/inflection v1.0.0 // indirect github.com/jinzhu/inflection v1.0.0 // indirect
github.com/jinzhu/now v1.1.5 // indirect github.com/jinzhu/now v1.1.5 // indirect
github.com/json-iterator/go v1.1.12 // indirect github.com/json-iterator/go v1.1.12 // indirect
@@ -87,7 +90,6 @@ require (
golang.org/x/net v0.32.0 // indirect golang.org/x/net v0.32.0 // indirect
golang.org/x/sys v0.28.0 // indirect golang.org/x/sys v0.28.0 // indirect
golang.org/x/text v0.21.0 // indirect golang.org/x/text v0.21.0 // indirect
golang.org/x/time v0.5.0 // indirect
google.golang.org/protobuf v1.34.2 // indirect google.golang.org/protobuf v1.34.2 // indirect
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/ini.v1 v1.67.0 // indirect

7
go.sum
View File

@@ -32,6 +32,7 @@ github.com/cloudwego/base64x v0.1.4 h1:jwCgWpFanWmN8xoIUHa2rtzmkd5J2plF/dnLS6Xd/
github.com/cloudwego/base64x v0.1.4/go.mod h1:0zlkT4Wn5C6NdauXdJRhSKRlJvmclQ1hhJgA0rcu/8w= github.com/cloudwego/base64x v0.1.4/go.mod h1:0zlkT4Wn5C6NdauXdJRhSKRlJvmclQ1hhJgA0rcu/8w=
github.com/cloudwego/iasm v0.2.0 h1:1KNIy1I1H9hNNFEEH3DVnI4UujN+1zjpuk6gwHLTssg= github.com/cloudwego/iasm v0.2.0 h1:1KNIy1I1H9hNNFEEH3DVnI4UujN+1zjpuk6gwHLTssg=
github.com/cloudwego/iasm v0.2.0/go.mod h1:8rXZaNYT2n95jn+zTI1sDr+IgcD2GVs0nlbbQPiEFhY= github.com/cloudwego/iasm v0.2.0/go.mod h1:8rXZaNYT2n95jn+zTI1sDr+IgcD2GVs0nlbbQPiEFhY=
github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
@@ -103,6 +104,8 @@ github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
github.com/hibiken/asynq v0.24.1 h1:+5iIEAyA9K/lcSPvx3qoPtsKJeKI5u9aOIvUmSsazEw= github.com/hibiken/asynq v0.24.1 h1:+5iIEAyA9K/lcSPvx3qoPtsKJeKI5u9aOIvUmSsazEw=
github.com/hibiken/asynq v0.24.1/go.mod h1:u5qVeSbrnfT+vtG5Mq8ZPzQu/BmCKMHvTGb91uy9Tts= github.com/hibiken/asynq v0.24.1/go.mod h1:u5qVeSbrnfT+vtG5Mq8ZPzQu/BmCKMHvTGb91uy9Tts=
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM= github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM=
github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg= github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
github.com/jackc/pgservicefile v0.0.0-20231201235250-de7065d80cb9 h1:L0QtFUgDarD7Fpv9jeVMgy/+Ec0mtnmYuImjTz6dtDA= github.com/jackc/pgservicefile v0.0.0-20231201235250-de7065d80cb9 h1:L0QtFUgDarD7Fpv9jeVMgy/+Ec0mtnmYuImjTz6dtDA=
@@ -177,6 +180,7 @@ github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs=
github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro= github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro=
github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8=
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/sagikazarmark/locafero v0.6.0 h1:ON7AQg37yzcRPU69mt7gwhFEBwxI6P9T4Qu3N51bwOk= github.com/sagikazarmark/locafero v0.6.0 h1:ON7AQg37yzcRPU69mt7gwhFEBwxI6P9T4Qu3N51bwOk=
github.com/sagikazarmark/locafero v0.6.0/go.mod h1:77OmuIc6VTraTXKXIs/uvUxKGUXjE1GbemJYHqdNjX0= github.com/sagikazarmark/locafero v0.6.0/go.mod h1:77OmuIc6VTraTXKXIs/uvUxKGUXjE1GbemJYHqdNjX0=
github.com/sagikazarmark/slog-shim v0.1.0 h1:diDBnUNK9N/354PgrxMywXnAwEr1QZcOr6gto+ugjYE= github.com/sagikazarmark/slog-shim v0.1.0 h1:diDBnUNK9N/354PgrxMywXnAwEr1QZcOr6gto+ugjYE=
@@ -194,6 +198,8 @@ github.com/spf13/afero v1.11.0/go.mod h1:GH9Y3pIexgf1MTIWtNGyogA5MwRIDXGUr+hbWNo
github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
github.com/spf13/cast v1.7.0 h1:ntdiHjuueXFgm5nzDRdOS4yfT43P5Fnud6DH50rz/7w= github.com/spf13/cast v1.7.0 h1:ntdiHjuueXFgm5nzDRdOS4yfT43P5Fnud6DH50rz/7w=
github.com/spf13/cast v1.7.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo= github.com/spf13/cast v1.7.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo=
github.com/spf13/cobra v1.9.1 h1:CXSaggrXdbHK9CF+8ywj8Amf7PBRmPCOJugH954Nnlo=
github.com/spf13/cobra v1.9.1/go.mod h1:nDyEzZ8ogv936Cinf6g1RU9MRY64Ir93oCnqb9wxYW0=
github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o= github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o=
github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/spf13/viper v1.19.0 h1:RWq5SEjt8o25SROyN3z2OrDB9l7RPd3lwTWU8EcEdcI= github.com/spf13/viper v1.19.0 h1:RWq5SEjt8o25SROyN3z2OrDB9l7RPd3lwTWU8EcEdcI=
@@ -283,6 +289,7 @@ golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ= golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ=
golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=

14
internal/cli/cli.go Normal file
View File

@@ -0,0 +1,14 @@
package cli
import (
"github.com/spf13/cobra"
)
var rootCmd = &cobra.Command{
Use: "aqi",
Short: "AQI Project Generator",
}
func Execute() {
cobra.CheckErr(rootCmd.Execute())
}

114
internal/cli/cli_new.go Normal file
View File

@@ -0,0 +1,114 @@
package cli
import (
"fmt"
"html/template"
"os"
"path/filepath"
"github.com/spf13/cobra"
)
var packageNameFlag string
var newCmd = &cobra.Command{
Use: "new [project-name]",
Short: "Create new project skeleton",
Args: cobra.MinimumNArgs(1),
Run: func(cmd *cobra.Command, args []string) {
projectName := args[0]
packageName := projectName
if packageNameFlag != "" {
packageName = packageNameFlag
}
createDir(projectName)
createProject(projectName, packageName)
},
}
func init() {
newCmd.Flags().StringVarP(&packageNameFlag, "package", "p", "", "Specify package name (optional, defaults to project name)")
rootCmd.AddCommand(newCmd)
}
func createDir(projectName string) {
// 检查目录是否存在
dirs := []struct {
dirName string
}{
{"cmd"},
{"internal/app"},
{"internal/dbc"},
{"internal/entity"},
{"internal/middlewares"},
{"internal/router"},
}
for _, d := range dirs {
dirPath := filepath.Join(projectName, d.dirName)
if err := os.MkdirAll(dirPath, 0755); err != nil {
fmt.Printf("Error creating directory: %v\n", err)
os.Exit(1)
}
}
}
func createProject(name, packageName string) {
// 复制模板文件
templates := []struct {
templatePath string
outputPath string
}{
{"templates/default/main.go.tmpl", "main.go"},
{"templates/default/go.mod.tmpl", "go.mod"},
{"templates/default/makefile.tmpl", "Makefile"},
{"templates/default/cmd/api.go.tmpl", "cmd/api.go"},
{"templates/default/cmd/dal.go.tmpl", "cmd/dal.go"},
{"templates/default/cmd/boot.go.tmpl", "cmd/boot.go"},
{"templates/default/dbc/dbc.go.tmpl", "internal/dbc/dbc.go"},
{"templates/default/middlewares/app.go.tmpl", "internal/middlewares/app.go"},
{"templates/default/middlewares/recovery.go.tmpl", "internal/middlewares/recovery.go"},
{"templates/default/middlewares/cors.go.tmpl", "internal/middlewares/cors.go"},
{"templates/default/router/action.go.tmpl", "internal/router/action.go"},
{"templates/default/router/api.go.tmpl", "internal/router/api.go"},
}
for _, t := range templates {
// 从嵌入的文件系统读取模板
tmplContent, err := templateFS.ReadFile(t.templatePath)
if err != nil {
fmt.Printf("Error reading template: %v\n", err)
os.Exit(1)
}
// 解析模板
tmpl, err := template.New(t.outputPath).Parse(string(tmplContent))
if err != nil {
fmt.Printf("Error parsing template: %v\n", err)
os.Exit(1)
}
outputFile, err := os.Create(filepath.Join(name, t.outputPath))
if err != nil {
fmt.Printf("Error creating file: %v\n", err)
os.Exit(1)
}
data := struct {
PackageName string
}{
PackageName: packageName,
}
if err := tmpl.Execute(outputFile, data); err != nil {
fmt.Printf("Error executing template: %v\n", err)
os.Exit(1)
}
_ = outputFile.Close()
}
fmt.Printf("Successfully created project: %s\n", name)
}

View File

@@ -0,0 +1,18 @@
package cli
import (
"fmt"
"github.com/spf13/cobra"
)
var verCmd = &cobra.Command{
Use: "version",
Short: "Version of this CLI",
Run: func(cmd *cobra.Command, args []string) {
fmt.Println("Version: 1.0")
},
}
func init() {
rootCmd.AddCommand(verCmd)
}

View File

@@ -0,0 +1,8 @@
package cli
import (
"embed"
)
//go:embed templates/default/*.tmpl templates/default/**/*.tmpl
var templateFS embed.FS

View File

@@ -0,0 +1,35 @@
package cmd
import (
"github.com/gin-gonic/gin"
"github.com/spf13/cobra"
"github.com/wonli/aqi"
"{{.PackageName}}/internal/dbc"
"{{.PackageName}}/internal/router"
)
func init() {
rootCmd.AddCommand(api)
}
var api = &cobra.Command{
Use: "api",
Short: "启动API",
Run: func(cmd *cobra.Command, args []string) {
app := aqi.Init(
aqi.ConfigFile(configFile),
aqi.HttpServer("Api", "apiPort"),
)
dbc.InitDBC()
g := gin.Default()
go router.Api(g)
go router.Actions(app)
app.WithHttpServer(g)
app.Start()
},
}

View File

@@ -0,0 +1,37 @@
package cmd
import (
"fmt"
"os"
"path/filepath"
"strings"
_ "time/tzdata"
"github.com/spf13/cobra"
)
var timezone string
var configFile string
func init() {
rootCmd.PersistentFlags().StringVarP(&timezone, "tz", "t", "default", "指定时区")
rootCmd.PersistentFlags().StringVarP(&configFile, "config", "c", "config.yaml", "指定配置文件路径默认当前路径下config.yaml")
cobra.OnInitialize(func() {
})
}
var runApp = filepath.Base(strings.TrimLeft(os.Args[0], "./"))
var rootCmd = &cobra.Command{
Use: runApp,
Version: "{{.PackageName}}",
Run: func(cmd *cobra.Command, args []string) {
_ = cmd.Help()
},
}
func Execute() {
if err := rootCmd.Execute(); err != nil {
fmt.Println(err)
os.Exit(1)
}
}

View File

@@ -0,0 +1,84 @@
package cmd
import (
"github.com/spf13/cobra"
"github.com/spf13/viper"
"github.com/wonli/aqi"
"golang.org/x/text/cases"
"golang.org/x/text/language"
"gorm.io/gen"
"gorm.io/gorm"
"strings"
"{{.PackageName}}/internal/dbc"
)
func init() {
rootCmd.AddCommand(dalCmd)
}
var dalCmd = &cobra.Command{
Use: "dal",
Short: "生成数据库表对应的model和dal",
Run: func(cmd *cobra.Command, args []string) {
aqi.Init(
aqi.ConfigFile(configFile),
)
dbc.InitDBC()
g := gen.NewGenerator(gen.Config{
OutPath: "./internal/entity/dal",
Mode: gen.WithoutContext | gen.WithDefaultQuery | gen.WithQueryInterface,
FieldSignable: true, // 无符号整数类型字段
FieldNullable: true, // 数据库中的字段可为空则生成struct字段为指针类型
FieldCoverable: true, // 如果数据库中字段有默认值则生成指针类型的字段以避免零值zero-value问题
FieldWithIndexTag: true, // 为结构体生成gorm index tag
FieldWithTypeTag: true, // 为结构体生成gorm type tag
})
g.WithDataTypeMap(map[string]func(columnType gorm.ColumnType) string{
"json": func(columnType gorm.ColumnType) string {
return "datatypes.JSON"
},
})
prefixToRemove := viper.GetString("mysql.logic.prefix")
g.WithTableNameStrategy(func(tableName string) string {
// 去掉指定的前缀
if strings.HasPrefix(tableName, prefixToRemove) {
return strings.TrimPrefix(tableName, prefixToRemove)
}
return tableName
})
g.WithJSONTagNameStrategy(func(columnName string) string {
parts := strings.Split(columnName, "_")
titleTransformer := cases.Title(language.English)
for i := range parts {
parts[i] = titleTransformer.String(parts[i])
}
// 将首字母转换为小写
if len(parts) > 0 {
parts[0] = strings.ToLower(parts[0][:1]) + parts[0][1:]
}
return strings.Join(parts, "")
})
logic := dbc.LogicDB.Use()
g.UseDB(logic)
g.ApplyInterface(func(Filter) {}, g.GenerateAllTable()...)
g.Execute()
},
}
type Filter interface {
// FilterWithColumn
// SELECT * FROM @@table WHERE @@column=@value
FilterWithColumn(column string, value string) ([]*gen.T, error)
}

View File

@@ -0,0 +1,13 @@
package dbc
import (
"github.com/wonli/aqi/store"
)
var Redis *store.RedisStore
var LogicDB *store.MySQLStore
func InitDBC() {
LogicDB = store.DB("mysql.logic")
Redis = store.Redis("redis.store")
}

View File

@@ -0,0 +1,14 @@
module {{.PackageName}}
go 1.24
require (
github.com/gin-gonic/gin v1.10.1
github.com/spf13/cobra v1.9.1
github.com/spf13/viper v1.20.1
github.com/wonli/aqi v1.3.1
golang.org/x/text v0.25.0
gorm.io/gen v0.3.27
gorm.io/gorm v1.30.0
gorm.io/plugin/dbresolver v1.6.0
)

View File

@@ -0,0 +1,7 @@
package main
import "{{.PackageName}}/cmd"
func main() {
cmd.Execute()
}

View File

@@ -0,0 +1,51 @@
APP_NAME = {{.PackageName}}
APP_PATH = .
# 编译路径
BUILD_PATH := ./dist
# 编译时间
BUILD_DATE = $(shell date +'%F %T')
ifeq ($(shell test -d .git && echo yes),yes)
# git已初始化,可以安全执行git命令
GIT_BRANCH = $(shell git rev-parse --abbrev-ref HEAD)
GIT_COMMIT = $(shell git rev-list --count HEAD)
GIT_REVISION = $(shell git rev-parse --short HEAD)
GIT_COMMITAT = $(shell git --no-pager log -1 --format="%at")
else
# git未初始化,相关变量设为默认值
GIT_BRANCH = -
GIT_COMMIT = -
GIT_REVISION = -
GIT_COMMITAT = -
endif
# support包名称
FLAGS_PKG = github.com/wonli/aqi
LDFLAGS = "-X '$(FLAGS_PKG).BuildDate=$(BUILD_DATE)' \
-X '$(FLAGS_PKG).Branch=$(GIT_BRANCH)' \
-X '$(FLAGS_PKG).CommitVersion=$(GIT_COMMIT)' \
-X '$(FLAGS_PKG).Revision=$(GIT_REVISION)' \
-extldflags '-static -s -w'"
# 编译参数
GO_FLAGS = -ldflags $(LDFLAGS) -trimpath -tags netgo
# Go编译命令 1-GOOS 2-GOARCH 3-FILE EXT
define go/build
go mod tidy
GOOS=$(1) GOARCH=$(2) CGO_ENABLED=0 go build $(GO_FLAGS) -o $(BUILD_PATH)/$(APP_NAME)-$(1)-$(2)-latest$(3) ${APP_PATH}
endef
# Generate binaries
.PHONY: build darwin linux windows
darwin:
$(call go/build,darwin,arm64)
linux:
$(call go/build,linux,amd64)
windows:
$(call go/build,windows,amd64,.exe)

View File

@@ -0,0 +1,42 @@
package middlewares
import (
"github.com/wonli/aqi/ws"
)
func App() ws.HandlerFunc {
return func(a *ws.Context) {
if a.Client.AppId == "" || a.Client.Platform == "" {
appId := a.Client.HttpRequest.URL.Query().Get("appId")
platform := a.Client.HttpRequest.URL.Query().Get("platform")
//获取storeId
if platform == "" {
a.SendCode(10003, "不支持的平台")
a.Abort()
return
}
a.Client.AppId = appId
a.Client.Platform = platform
}
// app登录
if a.Client.AppId == "app" && a.Client.ClientId == "" {
clientId := a.Client.HttpRequest.URL.Query().Get("clientId")
if clientId == "" {
a.SendCode(10013, "client不能为空")
a.Abort()
return
}
a.Client.ClientId = clientId
err := a.Client.Hub.UserLogin(clientId, a.Client.AppId, a.Client)
if err != nil {
a.SendCode(10013, "登录失败")
a.Abort()
return
}
}
}
}

View File

@@ -0,0 +1,21 @@
package middlewares
import "github.com/gin-gonic/gin"
func GinCORS() gin.HandlerFunc {
return func(c *gin.Context) {
// 设置响应头中的Access-Control-Allow-Origin为"*",允许所有域名的跨域请求。
c.Writer.Header().Set("Access-Control-Allow-Origin", "*")
c.Writer.Header().Set("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE, UPDATE")
c.Writer.Header().Set("Access-Control-Allow-Headers", "Origin, Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization")
c.Writer.Header().Set("Access-Control-Expose-Headers", "Content-Length")
c.Writer.Header().Set("Access-Control-Allow-Credentials", "false")
// 如果请求方法是OPTIONS直接返回200不继续后续的处理逻辑。
if c.Request.Method == "OPTIONS" {
c.AbortWithStatus(200)
} else {
c.Next()
}
}
}

View File

@@ -0,0 +1,24 @@
package middlewares
import (
"github.com/wonli/aqi/logger"
"github.com/wonli/aqi/ws"
"runtime/debug"
)
func Recovery() ws.HandlerFunc {
return func(a *ws.Context) {
defer func() {
if err := recover(); err != nil {
// 获取 panic 发生的堆栈跟踪
stack := debug.Stack()
logger.SugarLog.Errorf("Panic happened: %s \n %s\n", err, stack)
a.SendCode(30, "服务维护中")
a.Abort()
}
}()
a.Next()
}
}

View File

@@ -0,0 +1,15 @@
package router
import (
"github.com/wonli/aqi"
"github.com/wonli/aqi/ws"
"{{.PackageName}}/internal/middlewares"
)
func Actions(e *aqi.AppConfig) {
app := ws.NewRouter().Use(middlewares.Recovery(), middlewares.App())
app.Add("hi", func(a *ws.Context) {
a.Send(a.Params)
})
}

View File

@@ -0,0 +1,22 @@
package router
import (
"github.com/gin-gonic/gin"
"github.com/wonli/aqi/ws"
"time"
"{{.PackageName}}/internal/middlewares"
)
func Api(g *gin.Engine) {
g.Use(middlewares.GinCORS())
g.GET("/ok", func(c *gin.Context) {
c.JSON(200, gin.H{
"t": time.Now().Unix(),
})
})
g.GET("/ws", func(c *gin.Context) {
ws.HttpHandler(c.Writer, c.Request)
})
}