Files
toolset/console/commands/route.go
T
2022-03-29 15:20:24 +08:00

280 lines
7.2 KiB
Go

package commands
import (
"bytes"
"github.com/ctfang/command"
"github.com/go-home-admin/toolset/parser"
"log"
"os"
"os/exec"
"strings"
)
// RouteCommand @Bean
type RouteCommand struct{}
func (RouteCommand) Configure() command.Configure {
return command.Configure{
Name: "make:route",
Description: "根据protoc文件定义, 生成路由信息和控制器文件",
Input: command.Argument{
Option: []command.ArgParam{
{
Name: "path",
Description: "只解析指定目录",
Default: "@root/protobuf",
},
{
Name: "out_route",
Description: "生成文件到指定目录",
Default: "@root/routes",
},
{
Name: "out_actions",
Description: "生成文件到指定目录",
Default: "@root/app/http",
},
},
},
}
}
func (RouteCommand) Execute(input command.Input) {
root := getRootPath()
module := getModModule()
out := input.GetOption("out_route")
out = strings.Replace(out, "@root", root, 1)
outHttp := input.GetOption("out_actions")
outHttp = strings.Replace(outHttp, "@root", root, 1)
path := input.GetOption("path")
path = strings.Replace(path, "@root", root, 1)
agl := map[string]*ApiGroups{}
for _, parsers := range parser.NewProtocParserForDir(path) {
for _, fileParser := range parsers {
for _, service := range fileParser.Services {
group := ""
for _, option := range service.Opt {
if option.Key == "http.RouteGroup" {
group = option.Val
if _, ok := agl[group]; !ok {
agl[group] = &ApiGroups{
name: group,
imports: map[string]string{
"home_api_1": "github.com/go-home-admin/home/bootstrap/http/api",
"home_gin_1": "github.com/gin-gonic/gin",
},
controllers: make([]Controller, 0),
servers: make([]parser.Service, 0),
}
}
genController(service, outHttp)
break
}
}
if group != "" {
g := agl[group]
imports := module + "/app/http/" + fileParser.PackageName + "/" + parser.StringToSnake(service.Name)
g.imports[imports] = imports
g.controllers = append(g.controllers, Controller{
name: service.Name,
alias: imports,
})
g.servers = append(g.servers, service)
}
}
}
}
for _, g := range agl {
genRoute(g, out)
}
cmd := exec.Command("go", []string{"fmt", out}...)
var outBuffer bytes.Buffer
cmd.Stdout = &outBuffer
cmd.Stderr = os.Stderr
cmd.Dir = out
_ = cmd.Run()
}
func genController(server parser.Service, out string) {
page := server.Protoc.PackageName
out += "/" + page + "/" + parser.StringToSnake(server.Name)
if !parser.DirIsExist(out) {
_ = os.MkdirAll(out, 0760)
}
conStr := `package {package}
// Controller @Bean
type Controller struct {
}`
conStr = strings.ReplaceAll(conStr, "{package}", parser.StringToSnake(server.Name))
err := os.WriteFile(out+"/controller.go", []byte(conStr), 0760)
if err != nil {
panic(err)
}
methodStr := `package {package}
import ({import})
// {action} {doc}
func (receiver *Controller) {action}(req *{controllerAlias}.{param}, ctx *gin.Context) (*{controllerAlias}.{return}, error) {
// TODO 这里写业务
return &{controllerAlias}.{return}{}, nil
}
// GinHandle{action} gin原始路由处理
// http.{method}({url})
func (receiver *Controller) GinHandle{action}(ctx *gin.Context) {
req := &{controllerAlias}.{param}{}
err := ctx.ShouldBind(req)
if err != nil {
{providers}.ErrorRequest(ctx, err)
return
}
resp, err := receiver.{action}(req, ctx)
if err != nil {
{providers}.ErrorResponse(ctx, err)
return
}
{providers}.SuccessResponse(ctx, resp)
}
`
gin := "github.com/gin-gonic/gin"
providers := "github.com/go-home-admin/home/app/providers"
imports := map[string]string{gin: gin, providers: providers}
goMod := getModModule()
for rName, rpc := range server.Rpc {
for _, option := range rpc.Opt {
if strings.Index(option.Key, "http.") == 0 {
serPage := goMod + "/generate/proto/" + server.Protoc.PackageName
imports[serPage] = serPage
importsStr := ""
m := genImportAlias(imports)
sk := sortMap(m)
for _, s := range sk {
importsStr += "\n\t" + m[s] + " \"" + s + "\""
}
controllerAlias := m[serPage]
str := methodStr
actionName := parser.StringToHump(rName)
i := strings.Index(option.Key, ".")
method := option.Key[i+1:]
url := option.Val
for s, O := range map[string]string{
"{package}": parser.StringToSnake(server.Name),
"{import}": importsStr + "\n",
"{doc}": rpc.Doc,
"{method}": method,
"{url}": url,
"{action}": actionName,
"{controllerAlias}": controllerAlias,
"{providers}": m[providers],
"{param}": rpc.Param,
"{return}": rpc.Return,
} {
str = strings.ReplaceAll(str, s, O)
}
err = os.WriteFile(out+"/"+parser.StringToSnake(actionName)+"_action.go", []byte(str), 0766)
if err != nil {
log.Fatal(err)
}
}
}
}
}
func genRoute(g *ApiGroups, out string) {
context := make([]string, 0)
context = append(context, "package routes")
// import
importAlias := genImportAlias(g.imports)
if len(importAlias) != 0 {
context = append(context, "\nimport ("+parser.GetImportStrForMap(importAlias)+"\n)")
}
// Routes struct
context = append(context, genRoutesStruct(g, importAlias))
// Routes struct func GetRoutes
context = append(context, genRoutesFunc(g, importAlias))
str := "// gen for home toolset"
for _, s2 := range context {
str = str + "\n" + s2
}
err := os.WriteFile(out+"/"+parser.StringToSnake(g.name)+"_gen.go", []byte(str), 0766)
if err != nil {
log.Fatal(err)
}
}
func genRoutesFunc(g *ApiGroups, m map[string]string) string {
homeGin := m["github.com/gin-gonic/gin"]
homeApi := m["github.com/go-home-admin/home/bootstrap/http/api"]
str := "func (c *" + parser.StringToHump(g.name) + "Routes) GetGroup() string {" +
"\n\treturn \"" + g.name + "\"" +
"\n}"
str += "\nfunc (c *" + parser.StringToHump(g.name) + "Routes) GetRoutes() map[*" + homeApi + ".Config]func(c *" + homeGin + ".Context) {" +
"\n\treturn map[*" + homeApi + ".Config]func(c *" + homeGin + ".Context){"
for _, server := range g.servers {
for rName, rpc := range server.Rpc {
for _, option := range rpc.Opt {
if strings.Index(option.Key, "http.") == 0 {
i := strings.Index(option.Key, ".")
method := option.Key[i+1:]
str += "\n\t\t" + homeApi + "." + method + "(\"" + option.Val + "\"):" +
"c." + parser.StringToSnake(server.Name) + ".GinHandle" + parser.StringToHump(rName) + ","
}
}
}
}
return str + "\n\t}\n}"
}
func genRoutesStruct(g *ApiGroups, m map[string]string) string {
str := "\n// @Bean" +
"\ntype " + parser.StringToHump(g.name) + "Routes struct {\n"
for _, controller := range g.controllers {
alias := m[controller.alias]
str += "\t" + parser.StringToSnake(controller.name) + " *" + alias + ".Controller" + " `inject:\"\"`\n"
}
return str + "}\n"
}
type ApiGroups struct {
name string
imports map[string]string
controllers []Controller
servers []parser.Service
}
type Controller struct {
name string
alias string
ty string // *alias.Controller
}