Skip to content

Commit

Permalink
feat: support injected verb clients in Go (#2828)
Browse files Browse the repository at this point in the history
https://hackmd.io/OULeRFQQQvaMURysN27eEw

only the TestLifecycle integration test is updated with the new approach
in this PR, to demonstrate that both old and new verb call strategies
are still functional. will remove other usages of `ftl.Call(...)` to
follow

- generates `<Verb>Client` signatures in external stubs and (local)
signatures in `types.ftl.go`
- generates resource registrations in `main.go` and `types.ftl.go`, e.g.
"providers" for verb clients
-`go-runtime/build.go` changes accompanying the above^ bunch of stuff to
get imports working now that we're generating full verb request/response
types rather than just function references
- updates `go-runtime/server.go` to inject the registered providers when
processing an inbound call

#2641

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
  • Loading branch information
worstell and github-actions[bot] committed Sep 26, 2024
1 parent 80ad0a3 commit ef6056f
Show file tree
Hide file tree
Showing 27 changed files with 934 additions and 199 deletions.
14 changes: 10 additions & 4 deletions backend/schema/schema.go
Original file line number Diff line number Diff line change
Expand Up @@ -93,18 +93,24 @@ func (s *Schema) resolveToDataMonomorphised(n Node, parent Node) (*Data, error)
}
}

// Resolve a reference to a declaration.
func (s *Schema) Resolve(ref *Ref) optional.Option[Decl] {
// ResolveWithModule a reference to a declaration and its module.
func (s *Schema) ResolveWithModule(ref *Ref) (optional.Option[Decl], optional.Option[*Module]) {
for _, module := range s.Modules {
if module.Name == ref.Module {
for _, decl := range module.Decls {
if decl.GetName() == ref.Name {
return optional.Some(decl)
return optional.Some(decl), optional.Some(module)
}
}
}
}
return optional.None[Decl]()
return optional.None[Decl](), optional.None[*Module]()
}

// Resolve a reference to a declaration.
func (s *Schema) Resolve(ref *Ref) optional.Option[Decl] {
decl, _ := s.ResolveWithModule(ref)
return decl
}

// ResolveToType resolves a reference to a declaration of the given type.
Expand Down
2 changes: 1 addition & 1 deletion backend/schema/validate.go
Original file line number Diff line number Diff line change
Expand Up @@ -295,7 +295,7 @@ func ValidateModule(module *Module) error {
switch n := n.(type) {
case *Ref:
mdecl := scopes.Resolve(*n)
if mdecl == nil && n.Module == "" {
if mdecl == nil && (n.Module == "" || n.Module == module.Name) {
merr = append(merr, errorf(n, "unknown reference %q, is the type annotated and exported?", n))
}
if mdecl != nil {
Expand Down
30 changes: 20 additions & 10 deletions go-runtime/compile/build-template/.ftl.tmpl/go/main/main.go.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -10,19 +10,29 @@ import (
{{.}}
{{- end}}
)
{{- if or .SumTypes .ExternalTypes }}
{{- if or .SumTypes .ExternalTypes $verbs }}

func init() {
reflection.Register(
{{- range .SumTypes}}
reflection.SumType[{{.TypeName}}](
{{- range .Variants}}
*new({{.Name}}),
*new({{.TypeName}}),
{{- end}}
),
{{- end}}
{{- range .ExternalTypes}}
reflection.ExternalType(*new({{.TypeName}})),
{{- end}}
{{- range $verbs}}
reflection.ProvideResourcesForVerb(
{{.TypeName}},
{{- range .Resources}}
{{- with getVerbClient . }}
server.VerbClient[{{.TypeName}}, {{.Request.TypeName}}, {{.Response.TypeName}}](),
{{- end }}
{{- end}}
),
{{- end}}
)
}
Expand All @@ -31,15 +41,15 @@ func init() {
func main() {
verbConstructor := server.NewUserVerbServer("{{.ProjectName}}", "{{$name}}",
{{- range $verbs }}
{{- if and .HasRequest .HasResponse}}
server.HandleCall({{.TypeName}}),
{{- else if .HasRequest}}
server.HandleSink({{.TypeName}}),
{{- else if .HasResponse}}
server.HandleSource({{.TypeName}}),
{{- else}}
{{- if and (eq .Request.TypeName "ftl.Unit") (eq .Response.TypeName "ftl.Unit") }}
server.HandleEmpty({{.TypeName}}),
{{- end}}
{{- else if eq .Request.TypeName "ftl.Unit" }}
server.HandleSource[{{.Response.TypeName}}]({{.TypeName}}),
{{- else if eq .Response.TypeName "ftl.Unit" }}
server.HandleSink[{{.Request.TypeName}}]({{.TypeName}}),
{{- else }}
server.HandleCall[{{.Request.TypeName}}, {{.Response.TypeName}}]({{.TypeName}}),
{{- end -}}
{{- end}}
)
plugin.Start(context.Background(), "{{$name}}", verbConstructor, ftlv1connect.VerbServiceName, ftlv1connect.NewVerbServiceHandler)
Expand Down
41 changes: 38 additions & 3 deletions go-runtime/compile/build-template/types.ftl.go.tmpl
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
{{- $moduleName := .Name -}}
{{- $verbs := .Verbs -}}
{{- $name := .Name -}}
{{- with .TypesCtx -}}
{{- $moduleName := .MainModulePkg -}}

// Code generated by FTL. DO NOT EDIT.
package {{$name}}

{{- if or .SumTypes .ExternalTypes }}
{{ if .Imports -}}
import (
{{- range .Imports }}
Expand All @@ -15,17 +14,53 @@ import (
)
{{- end }}

{{ range $verbs -}}
{{ $req := .Request.LocalTypeName -}}
{{ $resp := .Response.LocalTypeName -}}

{{ if and (eq .Request.TypeName "ftl.Unit") (eq .Response.TypeName "ftl.Unit")}}
type {{.Name|title}}Client func(context.Context) error
{{- else if eq .Request.TypeName "ftl.Unit" }}
type {{.Name|title}}Client func(context.Context) ({{$resp}}, error)
{{- else if eq .Response.TypeName "ftl.Unit" }}
type {{.Name|title}}Client func(context.Context, {{$req}}) error
{{- else }}
type {{.Name|title}}Client func(context.Context, {{$req}}) ({{$resp}}, error)
{{- end }}
{{ end -}}

{{- if or .SumTypes .ExternalTypes $verbs }}
func init() {
reflection.Register(
{{- range .SumTypes}}
reflection.SumType[{{ trimModuleQualifier $moduleName .TypeName }}](
{{- range .Variants}}
*new({{ trimModuleQualifier $moduleName .Name }}),
*new({{ trimModuleQualifier $moduleName .TypeName }}),
{{- end}}
),
{{- end}}
{{- range .ExternalTypes}}
reflection.ExternalType(*new({{.TypeName}})),
{{- end}}
{{- range $verbs}}
reflection.ProvideResourcesForVerb(
{{ trimModuleQualifier $moduleName .TypeName }},
{{- range .Resources}}
{{- with getVerbClient . }}
{{ $verb := trimModuleQualifier $moduleName .TypeName -}}

{{ if and (eq .Request.TypeName "ftl.Unit") (eq .Response.TypeName "ftl.Unit")}}
server.EmptyClient[{{$verb}}](),
{{- else if eq .Request.TypeName "ftl.Unit" }}
server.SourceClient[{{$verb}}, {{.Response.LocalTypeName}}](),
{{- else if eq .Response.TypeName "ftl.Unit" }}
server.SinkClient[{{$verb}}, {{.Request.LocalTypeName}}](),
{{- else }}
server.VerbClient[{{$verb}}, {{.Request.LocalTypeName}}, {{.Response.LocalTypeName}}](),
{{- end }}
{{- end }}
{{- end}}
),
{{- end}}
)
}
Expand Down
Loading

0 comments on commit ef6056f

Please sign in to comment.