main.go 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192
  1. // A commandline tool for generating rpc code by service methods.
  2. //
  3. // This tool can generate rpc client code ,rpc arg model for specific Go project dir.
  4. // Usage :
  5. // $gorpc [options]
  6. // Available options:
  7. //
  8. // -client generate rpc client code.
  9. //
  10. // -d specific go project service dir (default ./service/)
  11. //
  12. // -model generate rpc arg model code.
  13. //
  14. // -o specific rpc client code output file. (default ./rpc/client/client.go)
  15. //
  16. // -m specific rpc arg model output file. (default ./model/rpc.go)
  17. //
  18. // -s print code to stdout.
  19. // Example:
  20. // $ cd $GOPATH/relation
  21. // $ gorpc
  22. // such command will generate rpc client code by functions of ./service/* and write code to $GOPATH/relation/rpc/client/client.go
  23. package main
  24. import (
  25. "bytes"
  26. "flag"
  27. "fmt"
  28. "go/importer"
  29. "io"
  30. "io/ioutil"
  31. "log"
  32. "path"
  33. "go-common/app/tool/gorpc/goparser"
  34. "go-common/app/tool/gorpc/input"
  35. "go-common/app/tool/gorpc/model"
  36. "golang.org/x/tools/imports"
  37. )
  38. const (
  39. tpl = `var (
  40. _noRes = &struct{}{}
  41. )
  42. type Service struct {
  43. client *rpc.Client2
  44. }
  45. func New(c *rpc.ClientConfig) (s *Service) {
  46. s = &Service{}
  47. s.client = rpc.NewDiscoveryCli(c)
  48. return
  49. }`
  50. )
  51. type output struct {
  52. rpcClient *bytes.Buffer
  53. methodStr *bytes.Buffer
  54. methods *bytes.Buffer
  55. model *bytes.Buffer
  56. }
  57. var out = &output{
  58. rpcClient: new(bytes.Buffer),
  59. methodStr: new(bytes.Buffer),
  60. methods: new(bytes.Buffer),
  61. model: new(bytes.Buffer),
  62. }
  63. var (
  64. dir = flag.String("d", "./service/", "source code dir")
  65. argModel = flag.Bool("model", false, "use -model to generate rpc arg model")
  66. client = flag.Bool("client", true, "use -client to generate rpc client code")
  67. clientfile = flag.String("o", "./rpc/client/client.go", "out file name")
  68. modelfile = flag.String("m", "./model/rpc.go", "generate rpc arg model")
  69. std = flag.Bool("s", false, "use -s to print code to stdout")
  70. )
  71. func main() {
  72. flag.Parse()
  73. p := &goparser.Parser{Importer: importer.Default()}
  74. files, err := input.Files(path.Dir(*dir))
  75. if err != nil {
  76. panic(err)
  77. }
  78. if *argModel {
  79. out.model.WriteString("package model\n")
  80. }
  81. for _, f := range files {
  82. rs, err := p.Parse(string(f), files)
  83. if err != nil {
  84. panic(err)
  85. }
  86. for _, f := range rs.Funcs {
  87. if f.IsExported && len(f.Results) <= 1 && f.Receiver != nil && f.ReturnsError {
  88. if *client {
  89. out.generateMeStr(f)
  90. out.generateMethod(f)
  91. }
  92. if *argModel {
  93. out.generateModel(f)
  94. }
  95. }
  96. }
  97. }
  98. if *argModel {
  99. m, err := imports.Process("model.go", out.model.Bytes(), &imports.Options{TabWidth: 4})
  100. if err != nil {
  101. log.Printf("gopimorts err %v", err)
  102. return
  103. }
  104. if *std {
  105. fmt.Printf("%s", m)
  106. } else {
  107. ioutil.WriteFile(*modelfile, m, 0666)
  108. }
  109. }
  110. if *client {
  111. out.rpcClient.WriteString("package client \n")
  112. out.rpcClient.WriteString(tpl)
  113. out.rpcClient.WriteString("\nconst ( \n")
  114. io.Copy(out.rpcClient, out.methodStr)
  115. out.rpcClient.WriteString("\n)\n")
  116. io.Copy(out.rpcClient, out.methods)
  117. c, err := imports.Process("client.go", out.rpcClient.Bytes(), &imports.Options{TabWidth: 4})
  118. if err != nil {
  119. log.Printf("gopimorts err %v", err)
  120. return
  121. }
  122. if *std {
  123. fmt.Printf("%s", c)
  124. } else {
  125. ioutil.WriteFile(*clientfile, c, 0666)
  126. }
  127. }
  128. }
  129. func (o *output) generateMeStr(f *model.Function) {
  130. b := o.methodStr
  131. fmt.Fprintf(b, "_%s = \"RPC.%s\"\n", f.Name, f.Name)
  132. }
  133. func (o *output) generateModel(f *model.Function) {
  134. b := o.model
  135. for _, p := range f.Parameters {
  136. if !p.IsBasicType() {
  137. if p.Type.String() == "context.Context" {
  138. continue
  139. }
  140. return
  141. }
  142. }
  143. fmt.Fprintf(b, fmt.Sprintf("type Arg%s struct{\n", f.Name))
  144. for _, p := range f.Parameters {
  145. fmt.Fprintln(b, string(bytes.ToUpper([]byte(p.Name))), p.Type)
  146. }
  147. fmt.Fprintln(b, "}")
  148. }
  149. func (o *output) generateMethod(f *model.Function) {
  150. b := o.methods
  151. name := f.Name
  152. for _, p := range f.Parameters {
  153. if !p.IsBasicType() {
  154. if p.Type.String() == "context.Context" {
  155. continue
  156. }
  157. return
  158. }
  159. }
  160. fmt.Fprintf(b, "func(s %s)%s(", f.Receiver.Type, f.Name)
  161. fmt.Fprintf(b, "c context.Context, arg *model.Arg%s)(", f.Name)
  162. if f.ReturnsError {
  163. if len(f.Results) > 0 {
  164. fmt.Fprintf(b, "res %s", f.Results[0].Type)
  165. fmt.Fprint(b, ",")
  166. }
  167. fmt.Fprintf(b, "err error)")
  168. } else {
  169. fmt.Fprint(b, ")")
  170. }
  171. fmt.Fprint(b, " {\n")
  172. if len(f.Results) == 0 {
  173. fmt.Fprintf(b, "err = s.client.Call(c, _%s, arg, &_noRes)", name)
  174. } else if f.Results[0].Type.IsStar {
  175. fmt.Fprintf(b, "res = new(%s)\n", f.Results[0].Type.String()[1:])
  176. fmt.Fprintf(b, "err = s.client.Call(c, _%s, arg, res)", name)
  177. } else {
  178. fmt.Fprintf(b, "err = s.client.Call(c, _%s, arg, &res)", name)
  179. }
  180. fmt.Fprintf(b, "\nreturn\n}\n")
  181. }