初步框架代码

This commit is contained in:
2024-04-07 18:12:24 +08:00
commit e79bc34225
10 changed files with 546 additions and 0 deletions

View File

@@ -0,0 +1,18 @@
package handlers
import (
"github.com/gin-gonic/gin"
"github.com/iapologizewhenimwrong/Vestmore_GO/server/app/internal/handlers/actions"
)
var HandlersFuncRoutes map[string]gin.HandlerFunc = make(map[string]gin.HandlerFunc)
func init() {
HandlersFuncRoutes["account/forgetSmsCode"] = actions.AccountForgetSmsCode
HandlersFuncRoutes["account/loginWithEmailPassword"] = actions.AccountLoginWithEmailPassword
HandlersFuncRoutes["account/loginWithTelephonePassword"] = actions.AccountLoginWithTelephonePassword
HandlersFuncRoutes["account/registerEmailCode"] = actions.AccountRegisterEmailCode
HandlersFuncRoutes["account/registerSmsCode"] = actions.AccountRegisterSmsCode
HandlersFuncRoutes["base/getToken"] = actions.BaseGetToken
HandlersFuncRoutes["member/alterPassword"] = actions.MemberAlterPassword
}

View File

@@ -0,0 +1,92 @@
package actions
import (
"log"
"github.com/gin-gonic/gin"
)
// @Action base/getToken
// Base_GetToken
// action: string;
// app_market: string;
// lang: string;
// token: string;
func BaseGetToken(ctx *gin.Context) {
param := &BaseGetTokenParam{}
ctx.ShouldBind(param)
log.Println()
}
// @Action account/loginWithTelephonePassword
// AccountLoginWithTelephonePassword
// action: string;
// country_code: string;
// device?: string;
// lang: string;
// password: string;
// telephone: string;
// token?: string;
// version?: string;
func AccountLoginWithTelephonePassword(ctx *gin.Context) {
// ctx.ShouldBind()
log.Println()
}
// @Action account/registerSmsCode
// AccountRegisterSmsCode
// action: string;
// country_code?: string;
// telephone?: string;
// token: string;
func AccountRegisterSmsCode(ctx *gin.Context) {
// ctx.ShouldBind()
log.Println()
}
// @Action account/forgetSmsCode
// AccountForgetSmsCode
// action: string;
// country_code?: string;
// telephone?: string;
// token: string;
func AccountForgetSmsCode(ctx *gin.Context) {
// ctx.ShouldBind()
log.Println()
}
// @Action account/registerEmailCode
// AccountRegisterEmailCode
// action: string;
// email?: string;
// token: string;
func AccountRegisterEmailCode(ctx *gin.Context) {
// ctx.ShouldBind()
log.Println()
}
// @Action member/alterPassword
// MemberAlterPassword
// action: string;
// confirm_password: string;
// new_password: string;
// old_password: string;
// token?: string;
func MemberAlterPassword(ctx *gin.Context) {
// ctx.ShouldBind()
log.Println()
}
// @Action account/loginWithEmailPassword
// AccountLoginWithEmailPassword
// action: string;
// device?: string;
// email: string;
// lang: string;
// password: string;
// token?: string;
// version?: string;
func AccountLoginWithEmailPassword(ctx *gin.Context) {
// ctx.ShouldBind()
log.Println()
}

View File

@@ -0,0 +1,57 @@
package actions
type AccountForgetSmsCodeParam struct {
Action string `json:"action" form:"action" binding:"-"`
CountryCode string `json:"country_code" form:"country_code" binding:"required"`
Telephone string `json:"telephone" form:"telephone" binding:"required"`
Token string `json:"token" form:"token" binding:"-"`
}
type AccountLoginWithEmailPasswordParam struct {
Action string `json:"action" form:"action" binding:"-"`
Device string `json:"device" form:"device" binding:"required"`
Email string `json:"email" form:"email" binding:"-"`
Lang string `json:"lang" form:"lang" binding:"-"`
Password string `json:"password" form:"password" binding:"-"`
Token string `json:"token" form:"token" binding:"required"`
Version string `json:"version" form:"version" binding:"required"`
}
type AccountLoginWithTelephonePasswordParam struct {
Action string `json:"action" form:"action" binding:"-"`
CountryCode string `json:"country_code" form:"country_code" binding:"-"`
Device string `json:"device" form:"device" binding:"required"`
Lang string `json:"lang" form:"lang" binding:"-"`
Password string `json:"password" form:"password" binding:"-"`
Telephone string `json:"telephone" form:"telephone" binding:"-"`
Token string `json:"token" form:"token" binding:"required"`
Version string `json:"version" form:"version" binding:"required"`
}
type AccountRegisterEmailCodeParam struct {
Action string `json:"action" form:"action" binding:"-"`
Email string `json:"email" form:"email" binding:"required"`
Token string `json:"token" form:"token" binding:"-"`
}
type AccountRegisterSmsCodeParam struct {
Action string `json:"action" form:"action" binding:"-"`
CountryCode string `json:"country_code" form:"country_code" binding:"required"`
Telephone string `json:"telephone" form:"telephone" binding:"required"`
Token string `json:"token" form:"token" binding:"-"`
}
type BaseGetTokenParam struct {
Action string `json:"action" form:"action" binding:"-"`
AppMarket string `json:"app_market" form:"app_market" binding:"-"`
Lang string `json:"lang" form:"lang" binding:"-"`
Token string `json:"token" form:"token" binding:"-"`
}
type MemberAlterPasswordParam struct {
Action string `json:"action" form:"action" binding:"-"`
ConfirmPassword string `json:"confirm_password" form:"confirm_password" binding:"-"`
NewPassword string `json:"new_password" form:"new_password" binding:"-"`
OldPassword string `json:"old_password" form:"old_password" binding:"-"`
Token string `json:"token" form:"token" binding:"required"`
}

View File

@@ -0,0 +1,14 @@
package handlers
import (
"github.com/gin-gonic/gin"
"github.com/iapologizewhenimwrong/Vestmore_GO/server/app/internal/handlers/actions"
)
var HandlersFuncRoutes map[string]gin.HandlerFunc = make(map[string]gin.HandlerFunc)
func init() {
{{- range .}}
HandlersFuncRoutes["{{.ActionName}}"] = actions.{{.FuncName}}
{{- end}}
}

View File

@@ -0,0 +1,193 @@
package handlers
import (
"bytes"
"fmt"
"go/ast"
"go/format"
"go/parser"
"go/token"
"log"
"os"
"path/filepath"
"regexp"
"strings"
"testing"
"text/template"
"unicode"
)
func TestGenActionsHandlerFunc(t *testing.T) {
createActionRoutesGen()
}
// 生成路由代码
func createActionRoutesGen() {
var err error
af := getActionsInfo()
tpl, err := template.ParseGlob("./*.tpl")
if err != nil {
panic(err)
}
genFile(tpl, "gen_action_routes.tpl", "./action_routes_gen.go", af)
genFile(tpl, "types_gen.tpl", "./actions/types_gen.go", af)
}
func genFile(tpl *template.Template, executeTemplate string, genFilePath string, tplParam any) {
var buf bytes.Buffer
err := tpl.ExecuteTemplate(&buf, executeTemplate, tplParam)
if err != nil {
panic(err)
}
data, err := format.Source(buf.Bytes())
if err != nil {
panic(err)
}
log.Println(string(data))
f, err := os.OpenFile(genFilePath, os.O_TRUNC|os.O_WRONLY|os.O_CREATE, 0644)
if err != nil {
panic(err)
}
f.Write(data)
f.Close()
}
type actionsFunc struct {
ActionName string
FuncName string
ParamStruct *paramStruct
}
type paramStructField struct {
ParamName string
ParamNameCamel string
ParamType string
ParamBinding string
}
type paramStruct struct {
ParamStructName string
ParamFields []paramStructField
}
func getActionsInfo() map[string]*actionsFunc {
regActionRe := regexp.MustCompile(`(?i)action +([^ ]+)`)
paramStructRe := regexp.MustCompile(` +([a-zA-Z_\-/]+)(\?{0,1}): +(\w+) ?;`)
dir := "actions"
actionsMap := make(map[string]*actionsFunc)
err := filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {
if err != nil {
return err
}
if !info.IsDir() && strings.HasSuffix(info.Name(), ".go") {
fset := token.NewFileSet()
file, err := parser.ParseFile(fset, path, nil, parser.ParseComments)
if err != nil {
return err
}
for _, decl := range file.Decls {
fn, ok := decl.(*ast.FuncDecl)
if !ok {
continue
}
if fn.Doc != nil {
var pstru *paramStruct
var af *actionsFunc
for _, comment := range fn.Doc.List {
// 匹配 @Action 提取
if strings.Contains(comment.Text, "@Action") || strings.Contains(comment.Text, "@action") {
matches := regActionRe.FindStringSubmatch(comment.Text)
if len(matches) != 0 {
af = &actionsFunc{
ActionName: matches[1],
FuncName: fn.Name.Name,
}
actionsMap[af.ActionName] = af
} else {
log.Panicf("action 无法匹配: %s", comment.Text)
}
continue
}
psvalue := paramStructRe.FindAllStringSubmatch(comment.Text, -1)
if len(psvalue) != 0 {
if pstru == nil {
pstru = &paramStruct{
ParamStructName: fn.Name.Name + "Param",
}
af.ParamStruct = pstru
}
pf := paramStructField{}
paramInfo := psvalue[0]
pf.ParamName = paramInfo[1]
pf.ParamNameCamel = toCamelCase(pf.ParamName)
paramRequired := paramInfo[2]
if paramRequired != "" {
pf.ParamBinding = "required"
} else {
pf.ParamBinding = "-"
}
pf.ParamType = paramInfo[3]
pstru.ParamFields = append(pstru.ParamFields, pf)
}
}
}
}
}
return nil
})
if err != nil {
panic(fmt.Sprint("Error:", err))
// return actionsMap
}
for action, funcNames := range actionsMap {
fmt.Printf("Action: %s %v\n", action, funcNames)
}
return actionsMap
}
func TestCase2(t *testing.T) {
eg := `// device: string;`
re := regexp.MustCompile(` +([a-zA-Z_\-/]+)(\?{0,1}): +(\w+) ?;`)
vs := re.FindAllStringSubmatch(eg, -1)
log.Println(vs)
}
func toCamelCase(s string) string {
var sb strings.Builder
capitalizeNext := true
for _, r := range s {
if r == '_' || r == '/' || r == '-' {
capitalizeNext = true
} else if capitalizeNext {
sb.WriteRune(unicode.ToUpper(r))
capitalizeNext = false
} else {
sb.WriteRune(unicode.ToLower(r))
}
}
return sb.String()
}

View File

@@ -0,0 +1,9 @@
package actions
{{- range .}}
type {{.ParamStruct.ParamStructName}} struct {
{{- range .ParamStruct.ParamFields}}
{{.ParamNameCamel}} {{.ParamType}} `json:"{{.ParamName}}" form:"{{.ParamName}}" binding:"{{.ParamBinding}}"`
{{- end}}
}
{{end}}

27
server/app/main.go Normal file
View File

@@ -0,0 +1,27 @@
package main
import (
"log"
"github.com/gin-gonic/gin"
"github.com/iapologizewhenimwrong/Vestmore_GO/server/app/internal/handlers"
)
func AppV10(ctx *gin.Context) {
if actionKey, ok := ctx.GetPostForm("action"); ok {
handlers.HandlersFuncRoutes[actionKey](ctx)
}
}
func main() {
r := gin.Default()
v10 := r.Group("app")
v10.POST("/1_0", AppV10)
for k := range handlers.HandlersFuncRoutes {
log.Printf("api %s", k)
}
r.Run(":8080")
}

7
server/app/main_test.go Normal file
View File

@@ -0,0 +1,7 @@
package main
import "testing"
func TestMain(t *testing.T) {
main()
}