506 lines
12 KiB
Go
506 lines
12 KiB
Go
package main
|
|
|
|
import (
|
|
"bytes"
|
|
"errors"
|
|
"fmt"
|
|
"os"
|
|
"strings"
|
|
"text/template"
|
|
|
|
"gitter.top/common/goast"
|
|
"google.golang.org/protobuf/compiler/protogen"
|
|
)
|
|
|
|
type generateRouterMethod struct {
|
|
MethodName string
|
|
InputName string
|
|
OutputName string
|
|
API string
|
|
Author string
|
|
Describe string
|
|
Method string
|
|
}
|
|
|
|
type generateRouters struct {
|
|
StructName string
|
|
BaseURL string
|
|
GenTo string
|
|
Methods []generateRouterMethod
|
|
}
|
|
|
|
const routerGenerateTpl = `type AutoGen{{.StructName}}Impl interface { ` + `{{range .Methods}}
|
|
{{.MethodName}}(ctx *coco.Context, req *{{.InputName}}) (resp *{{.OutputName}}, err error){{end}}
|
|
}
|
|
|
|
type {{.StructName}}_RouterMap struct {}
|
|
|
|
func (receiver *{{.StructName}}_RouterMap) GetRouterMap() *coco.Routers {
|
|
return &coco.Routers {
|
|
BaseURL: "{{.BaseURL}}",
|
|
Apis: coco.RouterMap{ {{range .Methods}}
|
|
"{{.MethodName}}": {
|
|
API: "{{.API}}",
|
|
Method: "{{.Method}}",
|
|
Author: "{{.Author}}",
|
|
Describe: "{{.Describe}}",
|
|
},{{end}}
|
|
},
|
|
}
|
|
}
|
|
`
|
|
|
|
func GenerateRouterMap(srv *protogen.Service) (string, error) {
|
|
var generate = new(generateRouters)
|
|
generate.StructName = srv.GoName
|
|
generate.BaseURL = GetCommentBaseURL(srv.Comments)
|
|
generate.GenTo = GetCommentGenerateTo(srv.Comments)
|
|
|
|
for _, method := range srv.Methods {
|
|
generate.Methods = append(generate.Methods, generateRouterMethod{
|
|
MethodName: method.GoName,
|
|
InputName: method.Input.GoIdent.GoName,
|
|
OutputName: method.Output.GoIdent.GoName,
|
|
API: GetCommentApiURL(method),
|
|
Author: GetCommentAuthor(method.Comments),
|
|
Describe: GetCommentDescribe(method.Comments),
|
|
Method: GetCommentHttpMethod(method.Comments),
|
|
})
|
|
}
|
|
|
|
tpl, err := template.New("group_router").Parse(routerGenerateTpl)
|
|
if err != nil {
|
|
return "", fmt.Errorf("parse %s group router template failed: %v", srv.GoName, err)
|
|
}
|
|
|
|
tpl.DefinedTemplates()
|
|
var buf bytes.Buffer
|
|
if err = tpl.Execute(&buf, generate); err != nil {
|
|
return "", fmt.Errorf("execute %s group router template failed: %v", srv.GoName, err)
|
|
}
|
|
|
|
return buf.String(), nil
|
|
}
|
|
|
|
type rpcInfo struct {
|
|
FuncName string // 函数名
|
|
RouterPath string // 路由路径
|
|
Method string // 请求类型 POST/GET...
|
|
Author string // 接口作者
|
|
Describe string // 描述
|
|
ReqName string // request name
|
|
RespName string // response name
|
|
}
|
|
|
|
type routerImpl struct {
|
|
Filename string
|
|
PkgName string
|
|
SrvName string
|
|
GoPkgName string
|
|
ProjectName string
|
|
Version string
|
|
Routers []*rpcInfo
|
|
}
|
|
|
|
// newRouterImpl 生成路由信息
|
|
// filename 文件生成地址
|
|
// pkgName 文件包名
|
|
// srvName 被控制的service名称
|
|
// service service信息
|
|
func newRouterImpl(filename, pkgName, goPkgName, srvName string, service *protogen.Service) *routerImpl {
|
|
if filename == "" {
|
|
filename = "./"
|
|
}
|
|
return &routerImpl{
|
|
Filename: filename,
|
|
SrvName: srvName,
|
|
PkgName: pkgName,
|
|
GoPkgName: goPkgName,
|
|
Routers: GetRPCInfoList(service),
|
|
}
|
|
}
|
|
|
|
func newRouterImplWire(filename, pkgName, goPkgName, srvName string) *routerImpl {
|
|
return &routerImpl{
|
|
Filename: filename,
|
|
SrvName: srvName,
|
|
PkgName: pkgName,
|
|
GoPkgName: goPkgName,
|
|
}
|
|
}
|
|
|
|
// fixPkgName 修正不规范的包名
|
|
func fixPkgName(name string) string {
|
|
name = strings.ReplaceAll(name, "-", "_")
|
|
name = strings.ReplaceAll(name, ".", "_")
|
|
return name
|
|
}
|
|
|
|
func (ri *routerImpl) IsFileExist() bool {
|
|
_, err := os.Stat(ri.Filename)
|
|
if err != nil {
|
|
if errors.Is(err, os.ErrNotExist) {
|
|
return false
|
|
} else {
|
|
_, _ = fmt.Fprintf(os.Stderr, "get file stat failed: %v", err)
|
|
}
|
|
return false
|
|
}
|
|
return true
|
|
}
|
|
|
|
func (ri *routerImpl) GetFileInfo(filename string) (os.FileInfo, error) {
|
|
return os.Stat(filename)
|
|
}
|
|
|
|
const CompleteRouteGenerateAndPackageTpl = `package {{.PkgName}}
|
|
|
|
import (
|
|
"gitter.top/coco/coco"
|
|
|
|
{{$.GoPkgName}} "{{.ProjectName}}/gen/v1"
|
|
)
|
|
|
|
type {{.SrvName}} struct {}
|
|
|
|
// IDE: {{.SrvName}} implemented {{.GoPkgName}}.AutoGen{{.SrvName}}Impl interface
|
|
var _ {{.GoPkgName}}.AutoGen{{.SrvName}}Impl = (*{{.SrvName}})(nil)
|
|
|
|
{{range $route := .Routers}}
|
|
// {{$route.FuncName}} {{$route.Describe}}
|
|
func (receiver *{{$.SrvName}}) {{$route.FuncName}}(ctx *coco.Context, req *{{$.GoPkgName}}.{{$route.ReqName}}) (resp *{{$.GoPkgName}}.{{$route.RespName}}, err error) {
|
|
resp = new({{$.GoPkgName}}.{{$route.RespName}})
|
|
|
|
// TODO impl...
|
|
|
|
return resp, nil
|
|
}
|
|
{{end}}
|
|
`
|
|
|
|
func (ri *routerImpl) generateNewFile() error {
|
|
t, err := template.New("generate_new_file").Parse(CompleteRouteGenerateAndPackageTpl)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
t.DefinedTemplates()
|
|
var buf bytes.Buffer
|
|
if err = t.Execute(&buf, ri); err != nil {
|
|
return err
|
|
}
|
|
f, err := os.OpenFile(ri.Filename, os.O_APPEND|os.O_RDWR|os.O_CREATE, os.ModePerm)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer f.Close()
|
|
if _, err = f.Write(buf.Bytes()); err != nil {
|
|
return err
|
|
}
|
|
return nil
|
|
}
|
|
|
|
const CompleteGrpcGenerateAndPackageTpl = `package {{.PkgName}}
|
|
|
|
import (
|
|
"context"
|
|
|
|
{{.GoPkgName}} "{{.ProjectName}}/gen/v1"
|
|
)
|
|
|
|
type {{.SrvName}} struct {}
|
|
|
|
// IDE: {{.SrvName}} implemented {{.GoPkgName}}.{{.SrvName}}Server interface
|
|
var _ {{.GoPkgName}}.{{.SrvName}}Server = (*{{.SrvName}})(nil)
|
|
|
|
{{range $route := .Routers}}
|
|
// {{$route.FuncName}} {{$route.Describe}}
|
|
func (receiver *{{$.SrvName}}) {{$route.FuncName}}(ctx context.Context, req *{{$.GoPkgName}}.{{$route.ReqName}}) (resp *{{$.GoPkgName}}.{{$route.RespName}}, err error) {
|
|
resp = new({{$.GoPkgName}}.{{$route.RespName}})
|
|
|
|
// TODO impl...
|
|
|
|
return resp, nil
|
|
}
|
|
{{end}}
|
|
`
|
|
|
|
func (ri *routerImpl) generateNewGrpcFile() error {
|
|
t, err := template.New("generate_new_grpc_file").Parse(CompleteGrpcGenerateAndPackageTpl)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
t.DefinedTemplates()
|
|
var buf bytes.Buffer
|
|
if err = t.Execute(&buf, ri); err != nil {
|
|
return err
|
|
}
|
|
f, err := os.OpenFile(ri.Filename, os.O_APPEND|os.O_RDWR|os.O_CREATE, os.ModePerm)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer f.Close()
|
|
if _, err = f.Write(buf.Bytes()); err != nil {
|
|
return err
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (ri *routerImpl) generateNewRouters() error {
|
|
info, err := ri.GetFileInfo(ri.Filename)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if info.IsDir() {
|
|
return nil
|
|
}
|
|
parser, err := goast.NewParser(ri.Filename)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
definer, err := parser.Parse()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if !definer.ExistType(ri.SrvName) {
|
|
tpl := `
|
|
type {{.SrvName}} struct {}
|
|
|
|
// IDE: {{.SrvName}} implemented {{.GoPkgName}}.AutoGen{{.SrvName}}Impl interface
|
|
var _ {{.GoPkgName}}.AutoGen{{.SrvName}}Impl = (*{{.SrvName}})(nil)
|
|
`
|
|
t, err := template.New("generate_type").Parse(tpl)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
t.DefinedTemplates()
|
|
var buf bytes.Buffer
|
|
if err = t.Execute(&buf, ri); err != nil {
|
|
return err
|
|
}
|
|
f, err := os.OpenFile(ri.Filename, os.O_APPEND|os.O_RDWR|os.O_CREATE, os.ModePerm)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer f.Close()
|
|
if _, err = f.Write(buf.Bytes()); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
var needImpls []*rpcInfo
|
|
for _, router := range ri.Routers {
|
|
if !definer.ExistMethod(fmt.Sprintf("%s.%s", ri.SrvName, router.FuncName)) {
|
|
needImpls = append(needImpls, router)
|
|
}
|
|
}
|
|
if len(needImpls) != 0 {
|
|
tpl := `{{range $route := .Routers}}
|
|
// {{$route.FuncName}} {{$route.Describe}}
|
|
func (receiver *{{$.SrvName}}) {{$route.FuncName}}(ctx *coco.Context, req *{{$.GoPkgName}}.{{$route.ReqName}}) (resp *{{$.GoPkgName}}.{{$route.RespName}}, err error) {
|
|
resp = new({{$.GoPkgName}}.{{$route.RespName}})
|
|
|
|
// TODO impl...
|
|
|
|
return resp, nil
|
|
}
|
|
{{end}}`
|
|
ri.Routers = needImpls
|
|
t, err := template.New("generate_impls").Parse(tpl)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
t.DefinedTemplates()
|
|
var buf bytes.Buffer
|
|
if err = t.Execute(&buf, ri); err != nil {
|
|
return err
|
|
}
|
|
f, err := os.OpenFile(ri.Filename, os.O_APPEND|os.O_RDWR|os.O_CREATE, os.ModePerm)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer f.Close()
|
|
if _, err = f.Write(buf.Bytes()); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (ri *routerImpl) generateNewGrpcServers() error {
|
|
info, err := ri.GetFileInfo(ri.Filename)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if info.IsDir() {
|
|
return nil
|
|
}
|
|
parser, err := goast.NewParser(ri.Filename)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
definer, err := parser.Parse()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if !definer.ExistType(ri.SrvName) {
|
|
tpl := `
|
|
type {{.SrvName}} struct {}
|
|
|
|
// IDE: {{.SrvName}} implemented {{.GoPkgName}}.{{.SrvName}}Server interface
|
|
var _ {{.GoPkgName}}.{{.SrvName}}Server = (*{{.SrvName}})(nil)
|
|
`
|
|
t, err := template.New("generate_type").Parse(tpl)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
t.DefinedTemplates()
|
|
var buf bytes.Buffer
|
|
if err = t.Execute(&buf, ri); err != nil {
|
|
return err
|
|
}
|
|
f, err := os.OpenFile(ri.Filename, os.O_APPEND|os.O_RDWR|os.O_CREATE, os.ModePerm)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer f.Close()
|
|
if _, err = f.Write(buf.Bytes()); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
var needImpls []*rpcInfo
|
|
for _, router := range ri.Routers {
|
|
if !definer.ExistMethod(fmt.Sprintf("%s.%s", ri.SrvName, router.FuncName)) {
|
|
needImpls = append(needImpls, router)
|
|
}
|
|
}
|
|
if len(needImpls) != 0 {
|
|
tpl := `{{range $route := .Routers}}
|
|
// {{$route.FuncName}} {{$route.Describe}}
|
|
func (receiver *{{$.SrvName}}) {{$route.FuncName}}(ctx context.Context, req *{{$.GoPkgName}}.{{$route.ReqName}}) (resp *{{$.GoPkgName}}.{{$route.RespName}}, err error) {
|
|
resp = new({{$.GoPkgName}}.{{$route.RespName}})
|
|
|
|
// TODO impl...
|
|
|
|
return resp, nil
|
|
}
|
|
{{end}}`
|
|
ri.Routers = needImpls
|
|
t, err := template.New("generate_impls").Parse(tpl)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
t.DefinedTemplates()
|
|
var buf bytes.Buffer
|
|
if err = t.Execute(&buf, ri); err != nil {
|
|
return err
|
|
}
|
|
f, err := os.OpenFile(ri.Filename, os.O_APPEND|os.O_RDWR|os.O_CREATE, os.ModePerm)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer f.Close()
|
|
if _, err = f.Write(buf.Bytes()); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
const routeWireCompleteTpl = `//go:build wireinject
|
|
// +build wireinject
|
|
|
|
package wire
|
|
|
|
import (
|
|
"github.com/google/wire"
|
|
|
|
"{{.ProjectName}}/gen/{{.Version}}"
|
|
"{{.ProjectName}}/services/controller/{{.Version}}"
|
|
)
|
|
|
|
`
|
|
|
|
func (ri *routerImpl) generateNewWireFile() error {
|
|
t, err := template.New("generate_new_wire").Parse(routeWireCompleteTpl)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
t.DefinedTemplates()
|
|
var buf bytes.Buffer
|
|
if err = t.Execute(&buf, ri); err != nil {
|
|
return err
|
|
}
|
|
f, err := os.OpenFile(ri.Filename, os.O_APPEND|os.O_RDWR|os.O_CREATE, os.ModePerm)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer f.Close()
|
|
if _, err = f.Write(buf.Bytes()); err != nil {
|
|
return err
|
|
}
|
|
return nil
|
|
}
|
|
|
|
const routeWireTpl = `type {{.SrvName}} struct {
|
|
*controller{{.Version}}.{{.SrvName}}
|
|
*gen{{.Version}}.{{.SrvName}}_RouterMap
|
|
}
|
|
|
|
func New{{.SrvName}}(c *controller{{.Version}}.{{.SrvName}}, r *gen{{.Version}}.{{.SrvName}}_RouterMap) *{{.SrvName}} {
|
|
return &{{.SrvName}}{c, r}
|
|
}
|
|
|
|
func Init{{.SrvName}}() *{{.SrvName}} {
|
|
wire.Build(wire.Struct(new(controller{{.Version}}.{{.SrvName}})), wire.Struct(new(gen{{.Version}}.{{.SrvName}}_RouterMap)), New{{.SrvName}})
|
|
return &{{.SrvName}}{}
|
|
}
|
|
`
|
|
|
|
func (ri *routerImpl) generateServicesWire() error {
|
|
info, err := ri.GetFileInfo(ri.Filename)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if info.IsDir() {
|
|
return nil
|
|
}
|
|
parser, err := goast.NewParser(ri.Filename)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
definer, err := parser.Parse()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if definer.ExistType(ri.SrvName) {
|
|
return nil
|
|
}
|
|
|
|
t, err := template.New("generate_router_wire").Parse(routeWireTpl)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
t.DefinedTemplates()
|
|
var buf bytes.Buffer
|
|
if err = t.Execute(&buf, ri); err != nil {
|
|
return err
|
|
}
|
|
f, err := os.OpenFile(ri.Filename, os.O_APPEND|os.O_RDWR|os.O_CREATE, os.ModePerm)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer f.Close()
|
|
if _, err = f.Write(buf.Bytes()); err != nil {
|
|
return err
|
|
}
|
|
return nil
|
|
}
|