Skip to content

Commit 4bdb07f

Browse files
kesonankevwanCopilot
authored
(goctl)feature: supported sse generation (#5082)
Co-authored-by: Kevin Wan <[email protected]> Co-authored-by: Copilot <[email protected]>
1 parent 3e6ec9b commit 4bdb07f

File tree

7 files changed

+141
-9
lines changed

7 files changed

+141
-9
lines changed

tools/goctl/api/gogen/genhandlers.go

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,12 @@ import (
1515

1616
const defaultLogicPackage = "logic"
1717

18-
//go:embed handler.tpl
19-
var handlerTemplate string
18+
var (
19+
//go:embed handler.tpl
20+
handlerTemplate string
21+
//go:embed sse_handler.tpl
22+
sseHandlerTemplate string
23+
)
2024

2125
func genHandler(dir, rootPkg string, cfg *config.Config, group spec.Group, route spec.Route) error {
2226
handler := getHandlerName(route)
@@ -32,19 +36,26 @@ func genHandler(dir, rootPkg string, cfg *config.Config, group spec.Group, route
3236
return err
3337
}
3438

39+
var builtinTemplate = handlerTemplate
40+
sse := group.GetAnnotation("sse")
41+
if sse == "true" {
42+
builtinTemplate = sseHandlerTemplate
43+
}
44+
3545
return genFile(fileGenConfig{
3646
dir: dir,
3747
subdir: getHandlerFolderPath(group, route),
3848
filename: filename + ".go",
3949
templateName: "handlerTemplate",
4050
category: category,
4151
templateFile: handlerTemplateFile,
42-
builtinTemplate: handlerTemplate,
52+
builtinTemplate: builtinTemplate,
4353
data: map[string]any{
4454
"PkgName": pkgName,
4555
"ImportPackages": genHandlerImports(group, route, rootPkg),
4656
"HandlerName": handler,
4757
"RequestType": util.Title(route.RequestTypeName()),
58+
"ResponseType": responseGoTypeName(route, typesPacket),
4859
"LogicName": logicName,
4960
"LogicType": strings.Title(getLogicName(route)),
5061
"Call": strings.Title(strings.TrimSuffix(handler, "Handler")),
@@ -73,7 +84,8 @@ func genHandlerImports(group spec.Group, route spec.Route, parentPkg string) str
7384
fmt.Sprintf("\"%s\"", pathx.JoinPackages(parentPkg, getLogicFolderPath(group, route))),
7485
fmt.Sprintf("\"%s\"", pathx.JoinPackages(parentPkg, contextDir)),
7586
}
76-
if len(route.RequestTypeName()) > 0 {
87+
sse := group.GetAnnotation("sse")
88+
if len(route.RequestTypeName()) > 0 || sse == "true" {
7789
imports = append(imports, fmt.Sprintf("\"%s\"\n", pathx.JoinPackages(parentPkg, typesDir)))
7890
}
7991

tools/goctl/api/gogen/genlogic.go

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,13 @@ import (
1515
"github.com/zeromicro/go-zero/tools/goctl/vars"
1616
)
1717

18-
//go:embed logic.tpl
19-
var logicTemplate string
18+
var (
19+
//go:embed logic.tpl
20+
logicTemplate string
21+
22+
//go:embed sse_logic.tpl
23+
sseLogicTemplate string
24+
)
2025

2126
func genLogic(dir, rootPkg string, cfg *config.Config, api *spec.ApiSpec) error {
2227
for _, g := range api.Service.Groups {
@@ -54,14 +59,28 @@ func genLogicByRoute(dir, rootPkg string, cfg *config.Config, group spec.Group,
5459
}
5560

5661
subDir := getLogicFolderPath(group, route)
62+
builtinTemplate := logicTemplate
63+
sse := group.GetAnnotation("sse")
64+
if sse == "true" {
65+
builtinTemplate = sseLogicTemplate
66+
responseString = "error"
67+
returnString = "return nil"
68+
resp := responseGoTypeName(route, typesPacket)
69+
if len(requestString) == 0 {
70+
requestString = "client chan<- " + resp
71+
} else {
72+
requestString += ", client chan<- " + resp
73+
}
74+
}
75+
5776
return genFile(fileGenConfig{
5877
dir: dir,
5978
subdir: subDir,
6079
filename: goFile + ".go",
6180
templateName: "logicTemplate",
6281
category: category,
6382
templateFile: logicTemplateFile,
64-
builtinTemplate: logicTemplate,
83+
builtinTemplate: builtinTemplate,
6584
data: map[string]any{
6685
"pkgName": subDir[strings.LastIndex(subDir, "/")+1:],
6786
"imports": imports,
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
package {{.PkgName}}
2+
3+
import (
4+
"encoding/json"
5+
"fmt"
6+
"net/http"
7+
8+
"github.com/zeromicro/go-zero/core/logc"
9+
"github.com/zeromicro/go-zero/core/threading"
10+
{{if .HasRequest}}"github.com/zeromicro/go-zero/rest/httpx"{{end}}
11+
{{.ImportPackages}}
12+
)
13+
14+
{{if .HasDoc}}{{.Doc}}{{end}}
15+
func {{.HandlerName}}(svcCtx *svc.ServiceContext) http.HandlerFunc {
16+
return func(w http.ResponseWriter, r *http.Request) {
17+
{{if .HasRequest}}var req types.{{.RequestType}}
18+
if err := httpx.Parse(r, &req); err != nil {
19+
httpx.ErrorCtx(r.Context(), w, err)
20+
return
21+
}
22+
23+
{{end}}// Buffer size of 16 is chosen as a reasonable default to balance throughput and memory usage.
24+
// You can change this based on your application's needs.
25+
// if your go-zero version less than 1.8.1, you need to add 3 lines below.
26+
// w.Header().Set("Content-Type", "text/event-stream")
27+
// w.Header().Set("Cache-Control", "no-cache")
28+
// w.Header().Set("Connection", "keep-alive")
29+
client := make(chan {{.ResponseType}}, 16)
30+
defer func() {
31+
close(client)
32+
}()
33+
l := {{.LogicName}}.New{{.LogicType}}(r.Context(), svcCtx)
34+
threading.GoSafeCtx(r.Context(), func() {
35+
err := l.{{.Call}}({{if .HasRequest}}&req, {{end}}client)
36+
if err != nil {
37+
logc.Errorw(r.Context(), "{{.HandlerName}}", logc.Field("error", err))
38+
return
39+
}
40+
})
41+
42+
for {
43+
select {
44+
case data := <-client:
45+
output, err := json.Marshal(data)
46+
if err != nil {
47+
logc.Errorw(r.Context(), "{{.HandlerName}}", logc.Field("error", err))
48+
continue
49+
}
50+
51+
if _, err := fmt.Fprintf(w, "data: %s\n\n", string(output)); err != nil {
52+
logc.Errorw(r.Context(), "{{.HandlerName}}", logc.Field("error", err))
53+
return
54+
}
55+
if flusher, ok := w.(http.Flusher); ok {
56+
flusher.Flush()
57+
}
58+
case <-r.Context().Done():
59+
return
60+
}
61+
}
62+
}
63+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
package {{.pkgName}}
2+
3+
import (
4+
{{.imports}}
5+
)
6+
7+
type {{.logic}} struct {
8+
logx.Logger
9+
ctx context.Context
10+
svcCtx *svc.ServiceContext
11+
}
12+
13+
{{if .hasDoc}}{{.doc}}{{end}}
14+
func New{{.logic}}(ctx context.Context, svcCtx *svc.ServiceContext) *{{.logic}} {
15+
return &{{.logic}}{
16+
Logger: logx.WithContext(ctx),
17+
ctx: ctx,
18+
svcCtx: svcCtx,
19+
}
20+
}
21+
22+
func (l *{{.logic}}) {{.function}}({{.request}}) {{.responseType}} {
23+
// todo: add your logic here and delete this line
24+
25+
{{.returnString}}
26+
}

tools/goctl/api/gogen/template.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,10 @@ const (
1212
contextTemplateFile = "context.tpl"
1313
etcTemplateFile = "etc.tpl"
1414
handlerTemplateFile = "handler.tpl"
15+
sseHandlerTemplateFile = "sse_handler.tpl"
1516
handlerTestTemplateFile = "handler_test.tpl"
1617
logicTemplateFile = "logic.tpl"
18+
sseLogicTemplateFile = "sse_logic.tpl"
1719
logicTestTemplateFile = "logic_test.tpl"
1820
mainTemplateFile = "main.tpl"
1921
middlewareImplementCodeFile = "middleware.tpl"
@@ -27,8 +29,10 @@ var templates = map[string]string{
2729
contextTemplateFile: contextTemplate,
2830
etcTemplateFile: etcTemplate,
2931
handlerTemplateFile: handlerTemplate,
32+
sseHandlerTemplateFile: sseHandlerTemplate,
3033
handlerTestTemplateFile: handlerTestTemplate,
3134
logicTemplateFile: logicTemplate,
35+
sseLogicTemplateFile: sseLogicTemplate,
3236
logicTestTemplateFile: logicTestTemplate,
3337
mainTemplateFile: mainTemplate,
3438
middlewareImplementCodeFile: middlewareImplementCode,

tools/goctl/internal/version/version.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,9 @@ import (
66
)
77

88
// BuildVersion is the version of goctl.
9-
const BuildVersion = "1.8.5"
9+
const BuildVersion = "1.8.6-alpha"
1010

11-
var tag = map[string]int{"pre-alpha": 0, "alpha": 1, "pre-bata": 2, "beta": 3, "released": 4, "": 5}
11+
var tag = map[string]int{"pre-alpha": 0, "alpha": 1, "pre-beta": 2, "beta": 3, "released": 4, "": 5}
1212

1313
// GetGoctlVersion returns BuildVersion
1414
func GetGoctlVersion() string {

tools/goctl/pkg/parser/api/parser/analyzer.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -244,6 +244,7 @@ func (a *Analyzer) fillService() error {
244244
group.Annotation.Properties = a.convertKV(item.AtServerStmt.Values)
245245
}
246246

247+
sse := group.GetAnnotation("sse") == "true"
247248
for _, astRoute := range item.Routes {
248249
head, leading := astRoute.CommentGroup()
249250
route := spec.Route{
@@ -277,6 +278,13 @@ func (a *Analyzer) fillService() error {
277278
}
278279
route.ResponseType = responseType
279280
}
281+
if route.ResponseType == nil && sse {
282+
if route.RequestType != nil {
283+
return ast.SyntaxError(astRoute.Route.Request.Pos(), "missing response type")
284+
} else {
285+
return ast.SyntaxError(astRoute.Route.Path.Pos(), "missing response type")
286+
}
287+
}
280288

281289
if err := a.fillRouteType(&route); err != nil {
282290
return err

0 commit comments

Comments
 (0)