Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Streaming Interceptors #3641

Merged
merged 28 commits into from
Feb 9, 2025
Merged
Changes from 1 commit
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
9f853b8
Add read/write streaming payload/result methods to interceptor DSL
douglaswth Jan 24, 2025
e547e64
Weave streaming interceptor stuff through codegen
douglaswth Jan 24, 2025
d6d779d
Do not try to use a field from an interface for the raw payload when …
douglaswth Jan 25, 2025
fa0bdde
Fix golden files
douglaswth Jan 25, 2025
946b677
Collect attributes from a method that actually has the interceptor ap…
douglaswth Jan 28, 2025
28789b0
Fix StreamingResult accessor signature and return
douglaswth Jan 28, 2025
905c5d8
Add SendWithContext and RecvWithContext methods to the stream interfa…
douglaswth Jan 29, 2025
5905958
Progress on wrapping streams with interceptors
douglaswth Jan 30, 2025
6e8e746
Finish generating the stream wrapping for interceptors; remove the En…
douglaswth Jan 31, 2025
3826f70
Progress on adding comments and fixing tests; fix a bug where refs we…
douglaswth Jan 31, 2025
0261a0c
Finish fixing tests
douglaswth Feb 1, 2025
9c35929
Add more tests for streaming interceptor service codegen
douglaswth Feb 1, 2025
cc0e16a
Fix bug where the CLI ParseEndpoint method would try to wrap every me…
douglaswth Feb 1, 2025
79eafc5
Merge branch 'v3' into streaming-interceptors
douglaswth Feb 3, 2025
81835c3
Update InterceptorInfo comment and replace Send and Recv boolean fiel…
douglaswth Feb 3, 2025
ebd3114
Merge branch 'v3' into streaming-interceptors
douglaswth Feb 3, 2025
1e1c7ab
Update Golden files to make the Interceptor tests happy
douglaswth Feb 3, 2025
712ab19
Add a ReturnContext field to goa.InterceptorInfo to allow interceptor…
douglaswth Feb 4, 2025
3161e0b
Scrap ReturnContext field in favor of changing the interceptor interf…
douglaswth Feb 4, 2025
c236fce
Merge branch 'v3' into streaming-interceptors
douglaswth Feb 4, 2025
6a734fe
Update Golden files to make the Interceptor tests happy again
douglaswth Feb 4, 2025
c36dfb6
Change goa.InterceptorInfo to an interface that generated interceptor…
douglaswth Feb 5, 2025
8035d69
Separate StreamingPayload and StreamingResult methods to Client and S…
douglaswth Feb 5, 2025
2ba73ae
Use goa.Endpoint for next again and do not return contexts from SendW…
douglaswth Feb 6, 2025
a1f2a91
Merge branch 'v3' into streaming-interceptors
douglaswth Feb 6, 2025
edbbca8
Address lint issues
raphael Feb 8, 2025
e4eb8a1
Merge branch 'v3' into streaming-interceptors
raphael Feb 8, 2025
77667dc
Fix lint issue
raphael Feb 8, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Add SendWithContext and RecvWithContext methods to the stream interfa…
…ce generation
douglaswth committed Jan 30, 2025
commit 905c5d8c6faf038f92c1bdf05ff63d0f1d0d34e7
52 changes: 36 additions & 16 deletions codegen/service/service_data.go
Original file line number Diff line number Diff line change
@@ -203,6 +203,10 @@ type (
SendName string
// SendDesc is the description for the send function.
SendDesc string
// SendWithContextName is the name of the send function with context.
SendWithContextName string
// SendWithContextDesc is the description for the send function with context.
SendWithContextDesc string
// SendTypeName is the type name sent through the stream.
SendTypeName string
// SendTypeRef is the reference to the type sent through the stream.
@@ -211,6 +215,10 @@ type (
RecvName string
// RecvDesc is the description for the recv function.
RecvDesc string
// RecvWithContextName is the name of the receive function with context.
RecvWithContextName string
// RecvWithContextDesc is the description for the recv function with context.
RecvWithContextDesc string
// RecvTypeName is the type name received from the stream.
RecvTypeName string
// RecvTypeRef is the reference to the type received from the stream.
@@ -1164,34 +1172,42 @@ func initStreamData(data *MethodData, m *expr.MethodExpr, vname, rname, resultRe
spayloadEx = m.StreamingPayload.Example(expr.Root.API.ExampleGenerator)
}
svrStream := &StreamData{
Interface: vname + "ServerStream",
VarName: scope.Unique(codegen.Goify(m.Name, true), "ServerStream"),
EndpointStruct: vname + "EndpointInput",
Kind: m.Stream,
SendName: "Send",
SendDesc: fmt.Sprintf("Send streams instances of %q.", rname),
SendTypeName: rname,
SendTypeRef: resultRef,
MustClose: true,
Interface: vname + "ServerStream",
VarName: scope.Unique(codegen.Goify(m.Name, true), "ServerStream"),
EndpointStruct: vname + "EndpointInput",
Kind: m.Stream,
SendName: "Send",
SendDesc: fmt.Sprintf("Send streams instances of %q.", rname),
SendWithContextName: "SendWithContext",
SendWithContextDesc: fmt.Sprintf("SendWithContext streams instances of %q with context.", rname),
SendTypeName: rname,
SendTypeRef: resultRef,
MustClose: true,
}
cliStream := &StreamData{
Interface: vname + "ClientStream",
VarName: scope.Unique(codegen.Goify(m.Name, true), "ClientStream"),
Kind: m.Stream,
RecvName: "Recv",
RecvDesc: fmt.Sprintf("Recv reads instances of %q from the stream.", rname),
RecvTypeName: rname,
RecvTypeRef: resultRef,
Interface: vname + "ClientStream",
VarName: scope.Unique(codegen.Goify(m.Name, true), "ClientStream"),
Kind: m.Stream,
RecvName: "Recv",
RecvDesc: fmt.Sprintf("Recv reads instances of %q from the stream.", rname),
RecvWithContextName: "RecvWithContext",
RecvWithContextDesc: fmt.Sprintf("RecvWithContext reads instances of %q from the stream with context.", rname),
RecvTypeName: rname,
RecvTypeRef: resultRef,
}
if m.Stream == expr.ClientStreamKind || m.Stream == expr.BidirectionalStreamKind {
switch m.Stream {
case expr.ClientStreamKind:
if resultRef != "" {
svrStream.SendName = "SendAndClose"
svrStream.SendDesc = fmt.Sprintf("SendAndClose streams instances of %q and closes the stream.", rname)
svrStream.SendWithContextName = "SendAndCloseWithContext"
svrStream.SendWithContextDesc = fmt.Sprintf("SendAndCloseWithContext streams instances of %q and closes the stream with context.", rname)
svrStream.MustClose = false
cliStream.RecvName = "CloseAndRecv"
cliStream.RecvDesc = fmt.Sprintf("CloseAndRecv stops sending messages to the stream and reads instances of %q from the stream.", rname)
cliStream.RecvWithContextName = "CloseAndRecvWithContext"
cliStream.RecvWithContextDesc = fmt.Sprintf("CloseAndRecvWithContext stops sending messages to the stream and reads instances of %q from the stream with context.", rname)
} else {
cliStream.MustClose = true
}
@@ -1200,10 +1216,14 @@ func initStreamData(data *MethodData, m *expr.MethodExpr, vname, rname, resultRe
}
svrStream.RecvName = "Recv"
svrStream.RecvDesc = fmt.Sprintf("Recv reads instances of %q from the stream.", spayloadName)
svrStream.RecvWithContextName = "RecvWithContext"
svrStream.RecvWithContextDesc = fmt.Sprintf("RecvWithContext reads instances of %q from the stream with context.", spayloadName)
svrStream.RecvTypeName = spayloadName
svrStream.RecvTypeRef = spayloadRef
cliStream.SendName = "Send"
cliStream.SendDesc = fmt.Sprintf("Send streams instances of %q.", spayloadName)
cliStream.SendWithContextName = "SendWithContext"
cliStream.SendWithContextDesc = fmt.Sprintf("SendWithContext streams instances of %q with context.", spayloadName)
cliStream.SendTypeName = spayloadName
cliStream.SendTypeRef = spayloadRef
}
4 changes: 4 additions & 0 deletions codegen/service/templates/service.go.tpl
Original file line number Diff line number Diff line change
@@ -64,10 +64,14 @@ type {{ .Stream.Interface }} interface {
{{- if .Stream.SendTypeRef }}
{{ comment .Stream.SendDesc }}
{{ .Stream.SendName }}({{ .Stream.SendTypeRef }}) error
{{ comment .Stream.SendWithContextDesc }}
{{ .Stream.SendWithContextName }}(context.Context, {{ .Stream.SendTypeRef }}) error
{{- end }}
{{- if .Stream.RecvTypeRef }}
{{ comment .Stream.RecvDesc }}
{{ .Stream.RecvName }}() ({{ .Stream.RecvTypeRef }}, error)
{{ comment .Stream.RecvWithContextDesc }}
{{ .Stream.RecvWithContextName }}(context.Context) ({{ .Stream.RecvTypeRef }}, error)
{{- end }}
{{- if .Stream.MustClose }}
{{ comment "Close closes the stream." }}
80 changes: 51 additions & 29 deletions grpc/codegen/service_data.go
Original file line number Diff line number Diff line change
@@ -332,6 +332,10 @@ type (
SendName string
// SendDesc is the description for the send function.
SendDesc string
// SendWithContextName is the name of the send function with context.
SendWithContextName string
// SendWithContextDesc is the description for the send function with context.
SendWithContextDesc string
// SendRef is the fully qualified reference to the type sent across the
// stream.
SendRef string
@@ -347,6 +351,10 @@ type (
RecvName string
// RecvDesc is the description for the recv function.
RecvDesc string
// RecvWithContextName is the name of the receive function with context.
RecvWithContextName string
// RecvWithContextDesc is the description for the recv function with context.
RecvWithContextDesc string
// RecvRef is the fully qualified reference to the type received from the
// stream.
RecvRef string
@@ -393,7 +401,7 @@ func (d ServicesData) Get(name string) *ServiceData {
return d[name]
}

// Endpoint returns the endoint data for the endpoint with the given name, nil
// Endpoint returns the endpoint data for the endpoint with the given name, nil
// if there isn't one.
func (sd *ServiceData) Endpoint(name string) *EndpointData {
for _, ed := range sd.Endpoints {
@@ -779,7 +787,7 @@ func collectValidations(att *expr.AttributeExpr, attName string, ctx *codegen.At
switch dt := att.Type.(type) {
case expr.UserType:
if expr.IsPrimitive(dt) {
// Alias type - validation is generatd inline in parent type validation code.
// Alias type - validation is generate inline in parent type validation code.
return
}
vtx := protoBufTypeContext(sd.PkgName, sd.Scope, false)
@@ -1151,19 +1159,23 @@ func buildErrorConvertData(ge *expr.GRPCErrorExpr, e *expr.GRPCEndpointExpr, sd
// svr param indicates that the stream data is built for the server.
func buildStreamData(e *expr.GRPCEndpointExpr, sd *ServiceData, svr bool) *StreamData {
var (
varn string
intName string
svcInt string
sendName string
sendDesc string
sendRef string
sendConvert *ConvertData
recvName string
recvDesc string
recvRef string
recvConvert *ConvertData
mustClose bool
typ string
varn string
intName string
svcInt string
sendName string
sendDesc string
sendWithContextName string
sendWithContextDesc string
sendRef string
sendConvert *ConvertData
recvName string
recvDesc string
recvWithContextName string
recvWithContextDesc string
recvRef string
recvConvert *ConvertData
mustClose bool
typ string

svc = sd.Service
ed = sd.Endpoint(e.Name())
@@ -1184,6 +1196,7 @@ func buildStreamData(e *expr.GRPCEndpointExpr, sd *ServiceData, svr bool) *Strea
if e.MethodExpr.Result.Type != expr.Empty {
sendName = md.ServerStream.SendName
sendRef = ed.ResultRef
sendWithContextName = md.ServerStream.SendWithContextName
sendConvert = &ConvertData{
SrcName: resCtx.Scope.Name(result, resCtx.Pkg(result), resCtx.Pointer, resCtx.UseDefault),
SrcRef: resCtx.Scope.Ref(result, resCtx.Pkg(result)),
@@ -1194,6 +1207,7 @@ func buildStreamData(e *expr.GRPCEndpointExpr, sd *ServiceData, svr bool) *Strea
}
if e.MethodExpr.StreamingPayload.Type != expr.Empty {
recvName = md.ServerStream.RecvName
recvWithContextName = md.ServerStream.RecvWithContextName
recvRef = svcCtx.Scope.Ref(e.MethodExpr.StreamingPayload, svcCtx.Pkg(e.MethodExpr.StreamingPayload))
recvConvert = &ConvertData{
SrcName: protoBufGoFullTypeName(e.StreamingRequest, sd.PkgName, sd.Scope),
@@ -1212,6 +1226,7 @@ func buildStreamData(e *expr.GRPCEndpointExpr, sd *ServiceData, svr bool) *Strea
svcInt = fmt.Sprintf("%s.%s", svc.PkgName, md.ClientStream.Interface)
if e.MethodExpr.StreamingPayload.Type != expr.Empty {
sendName = md.ClientStream.SendName
sendWithContextName = md.ClientStream.SendWithContextName
sendRef = svcCtx.Scope.Ref(e.MethodExpr.StreamingPayload, svcCtx.Pkg(e.MethodExpr.StreamingPayload))
sendConvert = &ConvertData{
SrcName: svcCtx.Scope.Name(e.MethodExpr.StreamingPayload, svcCtx.Pkg(e.MethodExpr.StreamingPayload), svcCtx.Pointer, svcCtx.UseDefault),
@@ -1223,6 +1238,7 @@ func buildStreamData(e *expr.GRPCEndpointExpr, sd *ServiceData, svr bool) *Strea
}
if e.MethodExpr.Result.Type != expr.Empty {
recvName = md.ClientStream.RecvName
recvWithContextName = md.ClientStream.RecvWithContextName
recvRef = ed.ResultRef
recvConvert = &ConvertData{
SrcName: protoBufGoFullTypeName(e.Response.Message, sd.PkgName, sd.Scope),
@@ -1237,26 +1253,32 @@ func buildStreamData(e *expr.GRPCEndpointExpr, sd *ServiceData, svr bool) *Strea
}
if sendConvert != nil {
sendDesc = fmt.Sprintf("%s streams instances of %q to the %q endpoint gRPC stream.", sendName, sendConvert.TgtName, md.Name)
sendWithContextDesc = fmt.Sprintf("%s streams instances of %q to the %q endpoint gRPC stream with context.", sendWithContextName, sendConvert.TgtName, md.Name)
}
if recvConvert != nil {
recvDesc = fmt.Sprintf("%s reads instances of %q from the %q endpoint gRPC stream.", recvName, recvConvert.SrcName, md.Name)
recvWithContextDesc = fmt.Sprintf("%s reads instances of %q from the %q endpoint gRPC stream with context.", recvWithContextName, recvConvert.SrcName, md.Name)
}
}
return &StreamData{
VarName: varn,
Type: typ,
Interface: intName,
ServiceInterface: svcInt,
Endpoint: ed,
SendName: sendName,
SendDesc: sendDesc,
SendRef: sendRef,
SendConvert: sendConvert,
RecvName: recvName,
RecvDesc: recvDesc,
RecvRef: recvRef,
RecvConvert: recvConvert,
MustClose: mustClose,
VarName: varn,
Type: typ,
Interface: intName,
ServiceInterface: svcInt,
Endpoint: ed,
SendName: sendName,
SendDesc: sendDesc,
SendWithContextName: sendWithContextName,
SendWithContextDesc: sendWithContextDesc,
SendRef: sendRef,
SendConvert: sendConvert,
RecvName: recvName,
RecvDesc: recvDesc,
RecvWithContextName: recvWithContextName,
RecvWithContextDesc: recvWithContextDesc,
RecvRef: recvRef,
RecvConvert: recvConvert,
MustClose: mustClose,
}
}

5 changes: 5 additions & 0 deletions grpc/codegen/templates/stream_recv.go.tpl
Original file line number Diff line number Diff line change
@@ -21,3 +21,8 @@ func (s *{{ .VarName }}) {{ .RecvName }}() ({{ .RecvRef }}, error) {
return {{ .RecvConvert.Init.Name }}({{ range .RecvConvert.Init.Args }}{{ .Name }}, {{ end }}), nil
{{- end }}
}

{{ comment .RecvWithContextDesc }}
func (s *{{ .VarName }}) {{ .RecvWithContextName }}(_ context.Context) ({{ .RecvRef }}, error) {
return s.{{ .RecvName }}()
}
5 changes: 5 additions & 0 deletions grpc/codegen/templates/stream_send.go.tpl
Original file line number Diff line number Diff line change
@@ -10,3 +10,8 @@ func (s *{{ .VarName }}) {{ .SendName }}(res {{ .SendRef }}) error {
v := {{ .SendConvert.Init.Name }}({{ if and .Endpoint.Method.ViewedResult (eq .Type "server") }}vres.Projected{{ else }}res{{ end }})
return s.stream.{{ .SendName }}(v)
}

{{ comment .SendWithContextDesc }}
func (s *{{ .VarName }}) {{ .SendWithContextName }}(_ context.Context, res {{ .SendRef }}) error {
return s.{{ .SendName }}(res)
}
5 changes: 5 additions & 0 deletions http/codegen/templates/websocket_recv.go.tpl
Original file line number Diff line number Diff line change
@@ -83,3 +83,8 @@ func (s *{{ .VarName }}) {{ .RecvName }}() ({{ .RecvTypeRef }}, error) {
{{- end }}
{{- end }}
}

{{ comment .RecvWithContextDesc }}
func (s *{{ .VarName }}) {{ .RecvWithContextName }}(_ context.Context) ({{ .RecvTypeRef }}, error) {
return s.{{ .RecvName }}()
}
5 changes: 5 additions & 0 deletions http/codegen/templates/websocket_send.go.tpl
Original file line number Diff line number Diff line change
@@ -52,3 +52,8 @@ func (s *{{ .VarName }}) {{ .SendName }}(v {{ .SendTypeRef }}) error {
{{- end }}
{{- end }}
}

{{ comment .SendWithContextDesc }}
func (s *{{ .VarName }}) {{ .SendWithContextName }}(_ context.Context, v {{ .SendTypeRef }}) error {
return s.{{ .SendName }}(v)
}
116 changes: 71 additions & 45 deletions http/codegen/websocket.go
Original file line number Diff line number Diff line change
@@ -32,6 +32,10 @@ type (
SendName string
// SendDesc is the description for the send function.
SendDesc string
// SendWithContextName is the name of the send function with context.
SendWithContextName string
// SendWithContextDesc is the description for the send function with context.
SendWithContextDesc string
// SendTypeName is the fully qualified type name sent through
// the stream.
SendTypeName string
@@ -42,6 +46,10 @@ type (
RecvName string
// RecvDesc is the description for the recv function.
RecvDesc string
// RecvWithContextName is the name of the receive function with context.
RecvWithContextName string
// RecvWithContextDesc is the description for the recv function with context.
RecvWithContextDesc string
// RecvTypeName is the fully qualified type name received from
// the stream.
RecvTypeName string
@@ -67,16 +75,20 @@ type (
// initWebSocketData initializes the WebSocket related data in ed.
func initWebSocketData(ed *EndpointData, e *expr.HTTPEndpointExpr, sd *ServiceData) {
var (
svrSendTypeName string
svrSendTypeRef string
svrRecvTypeName string
svrRecvTypeRef string
svrSendDesc string
svrRecvDesc string
svrPayload *TypeData
cliSendDesc string
cliRecvDesc string
cliPayload *TypeData
svrSendTypeName string
svrSendTypeRef string
svrRecvTypeName string
svrRecvTypeRef string
svrSendDesc string
svrSendWithContextDesc string
svrRecvDesc string
svrRecvWithContextDesc string
svrPayload *TypeData
cliSendDesc string
cliSendWithContextDesc string
cliRecvDesc string
cliRecvWithContextDesc string
cliPayload *TypeData

md = ed.Method
svc = sd.Service
@@ -86,7 +98,9 @@ func initWebSocketData(ed *EndpointData, e *expr.HTTPEndpointExpr, sd *ServiceDa
svrSendTypeName = ed.Result.Name
svrSendTypeRef = ed.Result.Ref
svrSendDesc = fmt.Sprintf("%s streams instances of %q to the %q endpoint websocket connection.", md.ServerStream.SendName, svrSendTypeName, md.Name)
svrSendWithContextDesc = fmt.Sprintf("%s streams instances of %q to the %q endpoint websocket connection with context.", md.ServerStream.SendWithContextName, svrSendTypeName, md.Name)
cliRecvDesc = fmt.Sprintf("%s reads instances of %q from the %q endpoint websocket connection.", md.ClientStream.RecvName, svrSendTypeName, md.Name)
cliRecvWithContextDesc = fmt.Sprintf("%s reads instances of %q from the %q endpoint websocket connection with context.", md.ClientStream.RecvWithContextName, svrSendTypeName, md.Name)
if e.MethodExpr.Stream == expr.ClientStreamKind || e.MethodExpr.Stream == expr.BidirectionalStreamKind {
svrRecvTypeName = sd.Scope.GoFullTypeName(e.MethodExpr.StreamingPayload, svc.PkgName)
svrRecvTypeRef = sd.Scope.GoFullTypeRef(e.MethodExpr.StreamingPayload, svc.PkgName)
@@ -175,50 +189,62 @@ func initWebSocketData(ed *EndpointData, e *expr.HTTPEndpointExpr, sd *ServiceDa
}
if e.MethodExpr.Stream == expr.ClientStreamKind {
svrSendDesc = fmt.Sprintf("%s streams instances of %q to the %q endpoint websocket connection and closes the connection.", md.ServerStream.SendName, svrSendTypeName, md.Name)
svrSendWithContextDesc = fmt.Sprintf("%s streams instances of %q to the %q endpoint websocket connection with context and closes the connection.", md.ServerStream.SendWithContextName, svrSendTypeName, md.Name)
cliRecvDesc = fmt.Sprintf("%s stops sending messages to the %q endpoint websocket connection and reads instances of %q from the connection.", md.ClientStream.RecvName, md.Name, svrSendTypeName)
cliRecvWithContextDesc = fmt.Sprintf("%s stops sending messages to the %q endpoint websocket connection with context and reads instances of %q from the connection.", md.ClientStream.RecvWithContextName, md.Name, svrSendTypeName)
}
svrRecvDesc = fmt.Sprintf("%s reads instances of %q from the %q endpoint websocket connection.", md.ServerStream.RecvName, svrRecvTypeName, md.Name)
svrRecvWithContextDesc = fmt.Sprintf("%s reads instances of %q from the %q endpoint websocket connection with context.", md.ServerStream.RecvWithContextName, svrRecvTypeName, md.Name)
cliSendDesc = fmt.Sprintf("%s streams instances of %q to the %q endpoint websocket connection.", md.ClientStream.SendName, svrRecvTypeName, md.Name)
cliSendWithContextDesc = fmt.Sprintf("%s streams instances of %q to the %q endpoint websocket connection with context.", md.ClientStream.SendWithContextName, svrRecvTypeName, md.Name)
}
}
ed.ServerWebSocket = &WebSocketData{
VarName: md.ServerStream.VarName,
Interface: fmt.Sprintf("%s.%s", svc.PkgName, md.ServerStream.Interface),
Endpoint: ed,
Payload: svrPayload,
Response: ed.Result.Responses[0],
PkgName: svc.PkgName,
Type: "server",
Kind: md.ServerStream.Kind,
SendName: md.ServerStream.SendName,
SendDesc: svrSendDesc,
SendTypeName: svrSendTypeName,
SendTypeRef: svrSendTypeRef,
RecvName: md.ServerStream.RecvName,
RecvDesc: svrRecvDesc,
RecvTypeName: svrRecvTypeName,
RecvTypeRef: svrRecvTypeRef,
RecvTypeIsPointer: expr.IsArray(e.MethodExpr.StreamingPayload.Type) || expr.IsMap(e.MethodExpr.StreamingPayload.Type),
MustClose: md.ServerStream.MustClose,
VarName: md.ServerStream.VarName,
Interface: fmt.Sprintf("%s.%s", svc.PkgName, md.ServerStream.Interface),
Endpoint: ed,
Payload: svrPayload,
Response: ed.Result.Responses[0],
PkgName: svc.PkgName,
Type: "server",
Kind: md.ServerStream.Kind,
SendName: md.ServerStream.SendName,
SendDesc: svrSendDesc,
SendWithContextName: md.ServerStream.SendWithContextName,
SendWithContextDesc: svrSendWithContextDesc,
SendTypeName: svrSendTypeName,
SendTypeRef: svrSendTypeRef,
RecvName: md.ServerStream.RecvName,
RecvDesc: svrRecvDesc,
RecvWithContextName: md.ServerStream.RecvWithContextName,
RecvWithContextDesc: svrRecvWithContextDesc,
RecvTypeName: svrRecvTypeName,
RecvTypeRef: svrRecvTypeRef,
RecvTypeIsPointer: expr.IsArray(e.MethodExpr.StreamingPayload.Type) || expr.IsMap(e.MethodExpr.StreamingPayload.Type),
MustClose: md.ServerStream.MustClose,
}
ed.ClientWebSocket = &WebSocketData{
VarName: md.ClientStream.VarName,
Interface: fmt.Sprintf("%s.%s", svc.PkgName, md.ClientStream.Interface),
Endpoint: ed,
Payload: cliPayload,
Response: ed.Result.Responses[0],
PkgName: svc.PkgName,
Type: "client",
Kind: md.ClientStream.Kind,
SendName: md.ClientStream.SendName,
SendDesc: cliSendDesc,
SendTypeName: svrRecvTypeName,
SendTypeRef: svrRecvTypeRef,
RecvName: md.ClientStream.RecvName,
RecvDesc: cliRecvDesc,
RecvTypeName: svrSendTypeName,
RecvTypeRef: svrSendTypeRef,
MustClose: md.ClientStream.MustClose,
VarName: md.ClientStream.VarName,
Interface: fmt.Sprintf("%s.%s", svc.PkgName, md.ClientStream.Interface),
Endpoint: ed,
Payload: cliPayload,
Response: ed.Result.Responses[0],
PkgName: svc.PkgName,
Type: "client",
Kind: md.ClientStream.Kind,
SendName: md.ClientStream.SendName,
SendDesc: cliSendDesc,
SendWithContextName: md.ClientStream.SendWithContextName,
SendWithContextDesc: cliSendWithContextDesc,
SendTypeName: svrRecvTypeName,
SendTypeRef: svrRecvTypeRef,
RecvName: md.ClientStream.RecvName,
RecvDesc: cliRecvDesc,
RecvWithContextName: md.ClientStream.RecvWithContextName,
RecvWithContextDesc: cliRecvWithContextDesc,
RecvTypeName: svrSendTypeName,
RecvTypeRef: svrSendTypeRef,
MustClose: md.ClientStream.MustClose,
}
}