genshared.go 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216
  1. package gogen
  2. import (
  3. "fmt"
  4. "os"
  5. "os/exec"
  6. "path/filepath"
  7. "strings"
  8. "github.com/tal-tech/go-zero/tools/goctl/rpc/execx"
  9. "github.com/tal-tech/go-zero/tools/goctl/rpc/parser"
  10. "github.com/tal-tech/go-zero/tools/goctl/util"
  11. )
  12. var (
  13. sharedTemplateText = `{{.head}}
  14. //go:generate mockgen -destination ./mock{{.name}}model.go -package {{.filePackage}} -source $GOFILE
  15. package {{.filePackage}}
  16. import (
  17. "context"
  18. {{.package}}
  19. "github.com/tal-tech/go-zero/core/jsonx"
  20. "github.com/tal-tech/go-zero/rpcx"
  21. )
  22. type (
  23. {{.serviceName}}Model interface {
  24. {{.interface}}
  25. }
  26. default{{.serviceName}}Model struct {
  27. cli rpcx.Client
  28. }
  29. )
  30. func NewDefault{{.serviceName}}Model(cli rpcx.Client) {{.serviceName}}Model {
  31. return &default{{.serviceName}}Model{
  32. cli: cli,
  33. }
  34. }
  35. {{.functions}}
  36. `
  37. sharedTemplateTypes = `{{.head}}
  38. package {{.filePackage}}
  39. import (
  40. "errors"
  41. )
  42. var (
  43. errJsonConvert = errors.New("json convert error")
  44. )
  45. {{.types}}
  46. `
  47. sharedInterfaceFunctionTemplate = `{{if .hasComment}}{{.comment}}
  48. {{end}}{{.method}}(ctx context.Context,in *{{.pbRequest}}) {{if .hasResponse}}(*{{.pbResponse}},{{end}} error{{if .hasResponse}}){{end}}`
  49. sharedFunctionTemplate = `
  50. {{if .hasComment}}{{.comment}}{{end}}
  51. func (m *default{{.rpcServiceName}}Model) {{.method}}(ctx context.Context,in *{{.pbRequest}}) {{if .hasResponse}}(*{{.pbResponse}},{{end}} error{{if .hasResponse}}){{end}} {
  52. conn:= m.cli.Conn()
  53. client := {{.package}}.New{{.rpcServiceName}}Client(conn)
  54. var request {{.package}}.{{.pbRequest}}
  55. bts, err := jsonx.Marshal(in)
  56. if err != nil {
  57. return {{if .hasResponse}}nil,{{end}}errJsonConvert
  58. }
  59. err = jsonx.Unmarshal(bts, &request)
  60. if err != nil {
  61. return {{if .hasResponse}}nil,{{end}}errJsonConvert
  62. }
  63. {{if .hasResponse}}resp,err:={{else}}_,err={{end}}client.{{.method}}(ctx, &request)
  64. {{if .hasResponse}}if err!=nil{
  65. return nil,err
  66. }
  67. var ret {{.pbResponse}}
  68. bts,err=jsonx.Marshal(resp)
  69. if err!=nil{
  70. return nil,errJsonConvert
  71. }
  72. err=jsonx.Unmarshal(bts,&ret)
  73. if err!=nil{
  74. return nil,errJsonConvert
  75. }
  76. return &ret, nil{{else}}if err!=nil {
  77. return err
  78. }
  79. return nil{{end}}
  80. }`
  81. )
  82. func (g *defaultRpcGenerator) genShared() error {
  83. sharePackage := filepath.Base(g.Ctx.SharedDir)
  84. file := g.ast
  85. typeCode, err := file.GenTypesCode()
  86. if err != nil {
  87. return err
  88. }
  89. pbPkg := file.Package
  90. remotePackage := fmt.Sprintf(`%v "%v"`, pbPkg, g.mustGetPackage(dirPb))
  91. filename := filepath.Join(g.Ctx.SharedDir, "types.go")
  92. head := util.GetHead(g.Ctx.ProtoSource)
  93. err = util.With("types").GoFmt(true).Parse(sharedTemplateTypes).SaveTo(map[string]interface{}{
  94. "head": head,
  95. "filePackage": sharePackage,
  96. "pbPkg": pbPkg,
  97. "serviceName": g.Ctx.ServiceName.Title(),
  98. "lowerStartServiceName": g.Ctx.ServiceName.UnTitle(),
  99. "types": typeCode,
  100. }, filename, true)
  101. for _, service := range file.Service {
  102. filename := filepath.Join(g.Ctx.SharedDir, fmt.Sprintf("%smodel.go", service.Name.Lower()))
  103. functions, err := g.getFuncs(service)
  104. if err != nil {
  105. return err
  106. }
  107. iFunctions, err := g.getInterfaceFuncs(service)
  108. if err != nil {
  109. return err
  110. }
  111. mockFile := filepath.Join(g.Ctx.SharedDir, fmt.Sprintf("mock%smodel.go", service.Name.Lower()))
  112. os.Remove(mockFile)
  113. err = util.With("shared").GoFmt(true).Parse(sharedTemplateText).SaveTo(map[string]interface{}{
  114. "name": service.Name.Lower(),
  115. "head": head,
  116. "filePackage": sharePackage,
  117. "pbPkg": pbPkg,
  118. "package": remotePackage,
  119. "serviceName": service.Name.Title(),
  120. "functions": strings.Join(functions, "\n"),
  121. "interface": strings.Join(iFunctions, "\n"),
  122. }, filename, true)
  123. if err != nil {
  124. return err
  125. }
  126. }
  127. // if mockgen is already installed, it will generate code of gomock for shared files
  128. _, err = exec.LookPath("mockgen")
  129. if err != nil {
  130. g.Ctx.Warning("warning:mockgen is not found")
  131. } else {
  132. execx.Run(fmt.Sprintf("cd %s \ngo generate", g.Ctx.SharedDir))
  133. }
  134. return nil
  135. }
  136. func (g *defaultRpcGenerator) getFuncs(service *parser.RpcService) ([]string, error) {
  137. file := g.ast
  138. pkgName := file.Package
  139. functions := make([]string, 0)
  140. for _, method := range service.Funcs {
  141. data, found := file.Strcuts[strings.ToLower(method.OutType)]
  142. if found {
  143. found = len(data.Field) > 0
  144. }
  145. var comment string
  146. if len(method.Document) > 0 {
  147. comment = method.Document[0]
  148. }
  149. buffer, err := util.With("sharedFn").Parse(sharedFunctionTemplate).Execute(map[string]interface{}{
  150. "rpcServiceName": service.Name.Title(),
  151. "method": method.Name.Title(),
  152. "package": pkgName,
  153. "pbRequest": method.InType,
  154. "pbResponse": method.OutType,
  155. "hasResponse": found,
  156. "hasComment": len(method.Document) > 0,
  157. "comment": comment,
  158. })
  159. if err != nil {
  160. return nil, err
  161. }
  162. functions = append(functions, buffer.String())
  163. }
  164. return functions, nil
  165. }
  166. func (g *defaultRpcGenerator) getInterfaceFuncs(service *parser.RpcService) ([]string, error) {
  167. file := g.ast
  168. functions := make([]string, 0)
  169. for _, method := range service.Funcs {
  170. data, found := file.Strcuts[strings.ToLower(method.OutType)]
  171. if found {
  172. found = len(data.Field) > 0
  173. }
  174. var comment string
  175. if len(method.Document) > 0 {
  176. comment = method.Document[0]
  177. }
  178. buffer, err := util.With("interfaceFn").Parse(sharedInterfaceFunctionTemplate).Execute(map[string]interface{}{
  179. "hasComment": len(method.Document) > 0,
  180. "comment": comment,
  181. "method": method.Name.Title(),
  182. "pbRequest": method.InType,
  183. "pbResponse": method.OutType,
  184. "hasResponse": found,
  185. })
  186. if err != nil {
  187. return nil, err
  188. }
  189. functions = append(functions, buffer.String())
  190. }
  191. return functions, nil
  192. }