genroutes.go 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181
  1. package gogen
  2. import (
  3. "bytes"
  4. "fmt"
  5. "path"
  6. "sort"
  7. "strings"
  8. "text/template"
  9. "zero/core/collection"
  10. "zero/tools/goctl/api/spec"
  11. apiutil "zero/tools/goctl/api/util"
  12. "zero/tools/goctl/util"
  13. )
  14. const (
  15. routesFilename = "routes.go"
  16. routesTemplate = `// DO NOT EDIT, generated by goctl
  17. package handler
  18. import (
  19. "net/http"
  20. {{.importPackages}}
  21. )
  22. func RegisterHandlers(engine *rest.Server, serverCtx *svc.ServiceContext) {
  23. {{.routesAdditions}}
  24. }
  25. `
  26. routesAdditionTemplate = `
  27. engine.AddRoutes([]rest.Route{
  28. {{.routes}}
  29. }{{.jwt}}{{.signature}})
  30. `
  31. )
  32. var mapping = map[string]string{
  33. "delete": "http.MethodDelete",
  34. "get": "http.MethodGet",
  35. "head": "http.MethodHead",
  36. "post": "http.MethodPost",
  37. "put": "http.MethodPut",
  38. }
  39. type (
  40. group struct {
  41. routes []route
  42. jwtEnabled bool
  43. signatureEnabled bool
  44. authName string
  45. }
  46. route struct {
  47. method string
  48. path string
  49. handler string
  50. }
  51. )
  52. func genRoutes(dir string, api *spec.ApiSpec) error {
  53. var builder strings.Builder
  54. groups, err := getRoutes(api)
  55. if err != nil {
  56. return err
  57. }
  58. gt := template.Must(template.New("groupTemplate").Parse(routesAdditionTemplate))
  59. for _, g := range groups {
  60. var gbuilder strings.Builder
  61. for _, r := range g.routes {
  62. fmt.Fprintf(&gbuilder, `
  63. {
  64. Method: %s,
  65. Path: "%s",
  66. Handler: %s,
  67. },`,
  68. r.method, r.path, r.handler)
  69. }
  70. jwt := ""
  71. if g.jwtEnabled {
  72. jwt = fmt.Sprintf(", ngin.WithJwt(serverCtx.Config.%s.AccessSecret)", g.authName)
  73. }
  74. signature := ""
  75. if g.signatureEnabled {
  76. signature = fmt.Sprintf(", ngin.WithSignature(serverCtx.Config.%s.Signature)", g.authName)
  77. }
  78. if err := gt.Execute(&builder, map[string]string{
  79. "routes": strings.TrimSpace(gbuilder.String()),
  80. "jwt": jwt,
  81. "signature": signature,
  82. }); err != nil {
  83. return err
  84. }
  85. }
  86. parentPkg, err := getParentPackage(dir)
  87. if err != nil {
  88. return err
  89. }
  90. filename := path.Join(dir, handlerDir, routesFilename)
  91. if err := util.RemoveOrQuit(filename); err != nil {
  92. return err
  93. }
  94. fp, created, err := apiutil.MaybeCreateFile(dir, handlerDir, routesFilename)
  95. if err != nil {
  96. return err
  97. }
  98. if !created {
  99. return nil
  100. }
  101. defer fp.Close()
  102. t := template.Must(template.New("routesTemplate").Parse(routesTemplate))
  103. buffer := new(bytes.Buffer)
  104. err = t.Execute(buffer, map[string]string{
  105. "importPackages": genRouteImports(parentPkg, api),
  106. "routesAdditions": strings.TrimSpace(builder.String()),
  107. })
  108. if err != nil {
  109. return nil
  110. }
  111. formatCode := formatCode(buffer.String())
  112. _, err = fp.WriteString(formatCode)
  113. return err
  114. }
  115. func genRouteImports(parentPkg string, api *spec.ApiSpec) string {
  116. var importSet = collection.NewSet()
  117. importSet.AddStr(`"zero/rest"`)
  118. importSet.AddStr(fmt.Sprintf("\"%s\"", path.Join(parentPkg, contextDir)))
  119. for _, group := range api.Service.Groups {
  120. for _, route := range group.Routes {
  121. folder, ok := apiutil.GetAnnotationValue(route.Annotations, "server", folderProperty)
  122. if !ok {
  123. folder, ok = apiutil.GetAnnotationValue(group.Annotations, "server", folderProperty)
  124. if !ok {
  125. continue
  126. }
  127. }
  128. importSet.AddStr(fmt.Sprintf("%s \"%s\"", folder, path.Join(parentPkg, handlerDir, folder)))
  129. }
  130. }
  131. imports := importSet.KeysStr()
  132. sort.Strings(imports)
  133. return strings.Join(imports, "\n\t")
  134. }
  135. func getRoutes(api *spec.ApiSpec) ([]group, error) {
  136. var routes []group
  137. for _, g := range api.Service.Groups {
  138. var groupedRoutes group
  139. for _, r := range g.Routes {
  140. handler, ok := apiutil.GetAnnotationValue(r.Annotations, "server", "handler")
  141. if !ok {
  142. return nil, fmt.Errorf("missing handler annotation for route %q", r.Path)
  143. }
  144. handler = getHandlerBaseName(handler) + "Handler(serverCtx)"
  145. folder, ok := apiutil.GetAnnotationValue(r.Annotations, "server", folderProperty)
  146. if ok {
  147. handler = folder + "." + strings.ToUpper(handler[:1]) + handler[1:]
  148. } else {
  149. folder, ok = apiutil.GetAnnotationValue(g.Annotations, "server", folderProperty)
  150. if ok {
  151. handler = folder + "." + strings.ToUpper(handler[:1]) + handler[1:]
  152. }
  153. }
  154. groupedRoutes.routes = append(groupedRoutes.routes, route{
  155. method: mapping[r.Method],
  156. path: r.Path,
  157. handler: handler,
  158. })
  159. }
  160. routes = append(routes, groupedRoutes)
  161. }
  162. return routes, nil
  163. }