genservice.go 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275
  1. package generator
  2. import (
  3. "bufio"
  4. "fmt"
  5. "io"
  6. "log"
  7. "os"
  8. "strings"
  9. "text/template"
  10. assets "go-common/app/tool/warden/generator/templates"
  11. "go-common/app/tool/warden/types"
  12. )
  13. const (
  14. protoTemplateName = "service.tmpl"
  15. contextType = "context.Context"
  16. )
  17. // ProtoMessage ProtoMessage
  18. type ProtoMessage struct {
  19. Name string
  20. Fields []ProtoField
  21. }
  22. // ProtoField ProtoField
  23. type ProtoField struct {
  24. FieldID int
  25. FieldType string
  26. FieldName string
  27. }
  28. // ProtoMethod method info
  29. type ProtoMethod struct {
  30. Comments []string
  31. Name string
  32. Req string
  33. Reply string
  34. }
  35. // ProtoValue proto template render value
  36. type ProtoValue struct {
  37. Package string
  38. Name string
  39. GoPackage string
  40. Imports map[string]bool
  41. Messages map[string]ProtoMessage
  42. Methods []ProtoMethod
  43. options *ServiceProtoOptions
  44. }
  45. // ServiceProtoOptions ...
  46. type ServiceProtoOptions struct {
  47. GoPackage string
  48. ProtoPackage string
  49. IgnoreType bool
  50. ImportPaths []string
  51. }
  52. func readProtoPackage(protoFile string) (string, error) {
  53. fp, err := os.Open(protoFile)
  54. if err != nil {
  55. return "", err
  56. }
  57. defer fp.Close()
  58. buf := bufio.NewReader(fp)
  59. for {
  60. line, err := buf.ReadString('\n')
  61. if err != nil {
  62. if err == io.EOF {
  63. break
  64. }
  65. return "", err
  66. }
  67. line = strings.TrimSpace(line)
  68. if !strings.HasPrefix(line, "package") {
  69. continue
  70. }
  71. return strings.TrimSpace(strings.TrimRight(line[len("package"):], ";")), nil
  72. }
  73. return "", fmt.Errorf("proto %s miss package define", protoFile)
  74. }
  75. func underscore(s string) string {
  76. cc := []byte(s)
  77. us := make([]byte, 0, len(cc)+3)
  78. pervUp := true
  79. for _, b := range cc {
  80. if 65 <= b && b <= 90 {
  81. if pervUp {
  82. us = append(us, b+32)
  83. } else {
  84. us = append(us, '_', b+32)
  85. }
  86. pervUp = true
  87. } else {
  88. pervUp = false
  89. us = append(us, b)
  90. }
  91. }
  92. return string(us)
  93. }
  94. func (p *ProtoValue) convertType(t types.Typer) (string, error) {
  95. switch v := t.(type) {
  96. case *types.BasicType:
  97. return convertBasicType(v.String())
  98. case *types.ArrayType:
  99. if v.EltType.String() == "byte" {
  100. return "bytes", nil
  101. }
  102. elt, err := p.convertType(v.EltType)
  103. if err != nil {
  104. return "", err
  105. }
  106. return fmt.Sprintf("repeated %s", elt), nil
  107. case *types.MapType:
  108. kt, err := p.convertType(v.KeyType)
  109. if err != nil {
  110. return "", err
  111. }
  112. vt, err := p.convertType(v.ValueType)
  113. if err != nil {
  114. return "", err
  115. }
  116. return fmt.Sprintf("map<%s, %s>", kt, vt), nil
  117. case *types.StructType:
  118. if v.ProtoFile == "" {
  119. messageName := fmt.Sprintf("%s%s", strings.Title(v.Package), v.IdentName)
  120. err := p.renderMessage(messageName, v.Fields)
  121. if err != nil {
  122. return "", err
  123. }
  124. return messageName, nil
  125. }
  126. protoPackage, err := readProtoPackage(v.ProtoFile)
  127. if err != nil {
  128. return "", err
  129. }
  130. p.importPackage(v.ProtoFile)
  131. if p.Package == protoPackage {
  132. return v.IdentName, nil
  133. }
  134. return fmt.Sprintf(".%s.%s", protoPackage, v.IdentName), nil
  135. }
  136. return "", fmt.Errorf("unsupport type %s", t)
  137. }
  138. func convertBasicType(gt string) (string, error) {
  139. switch gt {
  140. case "float64":
  141. return "double", nil
  142. case "float32":
  143. return "float", nil
  144. case "int", "int8", "uint8", "int16", "uint16":
  145. return "int32", nil
  146. case "int64", "int32", "uint32", "uint64", "string", "bool":
  147. return gt, nil
  148. }
  149. return "", fmt.Errorf("unsupport basic type %s", gt)
  150. }
  151. func (p *ProtoValue) render(spec *types.ServiceSpec, options *ServiceProtoOptions) (*ProtoValue, error) {
  152. p.options = options
  153. p.Name = spec.Name
  154. p.GoPackage = options.GoPackage
  155. p.Package = options.ProtoPackage
  156. p.Imports = make(map[string]bool)
  157. p.Messages = make(map[string]ProtoMessage)
  158. return p, p.renderMethods(spec.Methods)
  159. }
  160. func (p *ProtoValue) renderMethods(methods []*types.Method) error {
  161. for _, method := range methods {
  162. protoMethod := ProtoMethod{
  163. Comments: method.Comments,
  164. Name: method.Name,
  165. }
  166. //if len(method.Parameters) == 0 || (len(method.Parameters) == 1 && method.Parameters[0].Type.String() == contextType) {
  167. // p.importPackage(emptyProtoFile)
  168. // protoMethod.Req = emptyProtoMsg
  169. //} else {
  170. // protoMethod.Req = fmt.Sprintf("%sReq", method.Name)
  171. // if err := p.renderMessage(protoMethod.Req, method.Parameters); err != nil {
  172. // return err
  173. // }
  174. //}
  175. //if len(method.Results) == 0 || (len(method.Results) == 1 && method.Results[0].Type.String() == "error") {
  176. // p.importPackage(emptyProtoFile)
  177. // protoMethod.Reply = emptyProtoMsg
  178. //} else {
  179. // protoMethod.Reply = fmt.Sprintf("%sReply", method.Name)
  180. // if err := p.renderMessage(protoMethod.Reply, method.Results); err != nil {
  181. // return err
  182. // }
  183. //}
  184. protoMethod.Req = fmt.Sprintf("%sReq", method.Name)
  185. if err := p.renderMessage(protoMethod.Req, method.Parameters); err != nil {
  186. return err
  187. }
  188. protoMethod.Reply = fmt.Sprintf("%sReply", method.Name)
  189. if err := p.renderMessage(protoMethod.Reply, method.Results); err != nil {
  190. return err
  191. }
  192. p.Methods = append(p.Methods, protoMethod)
  193. }
  194. return nil
  195. }
  196. func (p *ProtoValue) importPackage(imp string) {
  197. for _, importPath := range p.options.ImportPaths {
  198. if strings.HasPrefix(imp, importPath) {
  199. p.Imports[strings.TrimLeft(imp[len(importPath):], "/")] = true
  200. return
  201. }
  202. }
  203. p.Imports[imp] = true
  204. }
  205. func (p *ProtoValue) renderMessage(name string, fields []*types.Field) error {
  206. if _, ok := p.Messages[name]; ok {
  207. return nil
  208. }
  209. message := ProtoMessage{
  210. Name: name,
  211. }
  212. for i, field := range fields {
  213. if field.Type.String() == "error" || field.Type.String() == contextType {
  214. continue
  215. }
  216. fieldName := underscore(field.Name)
  217. if fieldName == "" {
  218. fieldName = fmt.Sprintf("data_%d", i)
  219. }
  220. pField := ProtoField{
  221. FieldID: i + 1,
  222. FieldName: fieldName,
  223. }
  224. ptype, err := p.convertType(field.Type)
  225. if err != nil {
  226. if p.options.IgnoreType {
  227. log.Printf("warning convert type fail %s", err)
  228. ptype = fmt.Sprintf("//FIXME type %s", field.Type)
  229. } else {
  230. return err
  231. }
  232. }
  233. pField.FieldType = ptype
  234. message.Fields = append(message.Fields, pField)
  235. }
  236. p.Messages[name] = message
  237. return nil
  238. }
  239. func renderProtoValue(spec *types.ServiceSpec, options *ServiceProtoOptions) (*ProtoValue, error) {
  240. v := &ProtoValue{}
  241. return v.render(spec, options)
  242. }
  243. // GenServiceProto generator proto service by service spec
  244. func GenServiceProto(out io.Writer, spec *types.ServiceSpec, options *ServiceProtoOptions) error {
  245. value, err := renderProtoValue(spec, options)
  246. if err != nil {
  247. return err
  248. }
  249. assets.MustAsset(protoTemplateName)
  250. t, err := template.New(protoTemplateName).Parse(string(assets.MustAsset(protoTemplateName)))
  251. if err != nil {
  252. return err
  253. }
  254. return t.Execute(out, value)
  255. }