diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 00000000..a1818c9a --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,13 @@ +{ + "protoc": { + "options": [ + "--proto_path=proto", + ] + }, + "grpc-federation": { + "path": "bin/grpc-federation-language-server", + "import-paths": [ + "proto", + ] + } +} diff --git a/_examples/01_minimum/.gitignore b/_examples/01_minimum/.gitignore index fec7fd36..81d0826b 100644 --- a/_examples/01_minimum/.gitignore +++ b/_examples/01_minimum/.gitignore @@ -1 +1,2 @@ grpc/federation/federation.pb.go +grpc/federation/plugin.pb.go diff --git a/_examples/01_minimum/federation/federation_grpc_federation.pb.go b/_examples/01_minimum/federation/federation_grpc_federation.pb.go index fc5347e5..8527b290 100644 --- a/_examples/01_minimum/federation/federation_grpc_federation.pb.go +++ b/_examples/01_minimum/federation/federation_grpc_federation.pb.go @@ -61,6 +61,11 @@ type FederationServiceResolver interface { Resolve_Federation_GetPostResponse(context.Context, *Federation_GetPostResponseArgument[*FederationServiceDependentClientSet]) (*GetPostResponse, error) } +type FederationServiceCELPluginWasmConfig = grpcfedcel.WasmConfig + +type FederationServiceCELPluginConfig struct { +} + // FederationServiceUnimplementedResolver a structure implemented to satisfy the Resolver interface. // An Unimplemented error is always returned. // This is intended for use when there are many Resolver interfaces that do not need to be implemented, @@ -104,13 +109,14 @@ func NewFederationService(cfg FederationServiceConfig) (*FederationService, erro "id": grpcfed.NewCELFieldType(celtypes.StringType, "Id"), }, }) - env, err := cel.NewCustomEnv( + envOpts := []cel.EnvOption{ cel.StdLib(), cel.Lib(grpcfedcel.NewLibrary()), cel.CrossTypeNumericComparisons(true), cel.CustomTypeAdapter(celHelper.TypeAdapter()), cel.CustomTypeProvider(celHelper.TypeProvider()), - ) + } + env, err := cel.NewCustomEnv(envOpts...) if err != nil { return nil, err } diff --git a/_examples/01_minimum/go.mod b/_examples/01_minimum/go.mod index 4ecb5f3e..b550aae6 100644 --- a/_examples/01_minimum/go.mod +++ b/_examples/01_minimum/go.mod @@ -26,6 +26,7 @@ require ( github.com/google/uuid v1.5.0 // indirect github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0 // indirect github.com/stoewer/go-strcase v1.2.0 // indirect + github.com/tetratelabs/wazero v1.6.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.21.0 // indirect go.opentelemetry.io/otel/metric v1.21.0 // indirect go.opentelemetry.io/proto/otlp v1.0.0 // indirect diff --git a/_examples/01_minimum/go.sum b/_examples/01_minimum/go.sum index f4e6e138..58a10076 100644 --- a/_examples/01_minimum/go.sum +++ b/_examples/01_minimum/go.sum @@ -32,6 +32,8 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+ github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/tetratelabs/wazero v1.6.0 h1:z0H1iikCdP8t+q341xqepY4EWvHEw8Es7tlqiVzlP3g= +github.com/tetratelabs/wazero v1.6.0/go.mod h1:0U0G41+ochRKoPKCJlh0jMg1CHkyfK8kDqiirMmKY8A= go.opentelemetry.io/otel v1.21.0 h1:hzLeKBZEL7Okw2mGzZ0cc4k/A7Fta0uoPgaJCr8fsFc= go.opentelemetry.io/otel v1.21.0/go.mod h1:QZzNPQPm1zLX4gZK4cMi+71eaorMSGT3A4znnUvNNEo= go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.21.0 h1:cl5P5/GIfFh4t6xyruOgJP5QiA1pw4fYYdv6nc6CBWw= diff --git a/_examples/02_simple/.gitignore b/_examples/02_simple/.gitignore index fec7fd36..81d0826b 100644 --- a/_examples/02_simple/.gitignore +++ b/_examples/02_simple/.gitignore @@ -1 +1,2 @@ grpc/federation/federation.pb.go +grpc/federation/plugin.pb.go diff --git a/_examples/02_simple/federation/federation_grpc_federation.pb.go b/_examples/02_simple/federation/federation_grpc_federation.pb.go index f2912d8a..d653b338 100644 --- a/_examples/02_simple/federation/federation_grpc_federation.pb.go +++ b/_examples/02_simple/federation/federation_grpc_federation.pb.go @@ -101,6 +101,11 @@ type FederationServiceDependentClientSet struct { type FederationServiceResolver interface { } +type FederationServiceCELPluginWasmConfig = grpcfedcel.WasmConfig + +type FederationServiceCELPluginConfig struct { +} + // FederationServiceUnimplementedResolver a structure implemented to satisfy the Resolver interface. // An Unimplemented error is always returned. // This is intended for use when there are many Resolver interfaces that do not need to be implemented, @@ -164,13 +169,14 @@ func NewFederationService(cfg FederationServiceConfig) (*FederationService, erro "user_id": grpcfed.NewCELFieldType(celtypes.StringType, "UserId"), }, }) - env, err := cel.NewCustomEnv( + envOpts := []cel.EnvOption{ cel.StdLib(), cel.Lib(grpcfedcel.NewLibrary()), cel.CrossTypeNumericComparisons(true), cel.CustomTypeAdapter(celHelper.TypeAdapter()), cel.CustomTypeProvider(celHelper.TypeProvider()), - ) + } + env, err := cel.NewCustomEnv(envOpts...) if err != nil { return nil, err } diff --git a/_examples/02_simple/go.mod b/_examples/02_simple/go.mod index e882a7d0..a9cdeca7 100644 --- a/_examples/02_simple/go.mod +++ b/_examples/02_simple/go.mod @@ -27,6 +27,7 @@ require ( github.com/google/uuid v1.5.0 // indirect github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0 // indirect github.com/stoewer/go-strcase v1.2.0 // indirect + github.com/tetratelabs/wazero v1.6.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.21.0 // indirect go.opentelemetry.io/otel/metric v1.21.0 // indirect go.opentelemetry.io/proto/otlp v1.0.0 // indirect diff --git a/_examples/02_simple/go.sum b/_examples/02_simple/go.sum index f4e6e138..58a10076 100644 --- a/_examples/02_simple/go.sum +++ b/_examples/02_simple/go.sum @@ -32,6 +32,8 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+ github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/tetratelabs/wazero v1.6.0 h1:z0H1iikCdP8t+q341xqepY4EWvHEw8Es7tlqiVzlP3g= +github.com/tetratelabs/wazero v1.6.0/go.mod h1:0U0G41+ochRKoPKCJlh0jMg1CHkyfK8kDqiirMmKY8A= go.opentelemetry.io/otel v1.21.0 h1:hzLeKBZEL7Okw2mGzZ0cc4k/A7Fta0uoPgaJCr8fsFc= go.opentelemetry.io/otel v1.21.0/go.mod h1:QZzNPQPm1zLX4gZK4cMi+71eaorMSGT3A4znnUvNNEo= go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.21.0 h1:cl5P5/GIfFh4t6xyruOgJP5QiA1pw4fYYdv6nc6CBWw= diff --git a/_examples/03_custom_resolver/.gitignore b/_examples/03_custom_resolver/.gitignore index fec7fd36..81d0826b 100644 --- a/_examples/03_custom_resolver/.gitignore +++ b/_examples/03_custom_resolver/.gitignore @@ -1 +1,2 @@ grpc/federation/federation.pb.go +grpc/federation/plugin.pb.go diff --git a/_examples/03_custom_resolver/federation/federation_grpc_federation.pb.go b/_examples/03_custom_resolver/federation/federation_grpc_federation.pb.go index 9bc3dde4..fedfa454 100644 --- a/_examples/03_custom_resolver/federation/federation_grpc_federation.pb.go +++ b/_examples/03_custom_resolver/federation/federation_grpc_federation.pb.go @@ -130,6 +130,11 @@ type FederationServiceResolver interface { Resolve_Federation_User_Name(context.Context, *Federation_User_NameArgument[*FederationServiceDependentClientSet]) (string, error) } +type FederationServiceCELPluginWasmConfig = grpcfedcel.WasmConfig + +type FederationServiceCELPluginConfig struct { +} + // FederationServiceUnimplementedResolver a structure implemented to satisfy the Resolver interface. // An Unimplemented error is always returned. // This is intended for use when there are many Resolver interfaces that do not need to be implemented, @@ -238,13 +243,14 @@ func NewFederationService(cfg FederationServiceConfig) (*FederationService, erro "user_id": grpcfed.NewCELFieldType(celtypes.StringType, "UserId"), }, }) - env, err := cel.NewCustomEnv( + envOpts := []cel.EnvOption{ cel.StdLib(), cel.Lib(grpcfedcel.NewLibrary()), cel.CrossTypeNumericComparisons(true), cel.CustomTypeAdapter(celHelper.TypeAdapter()), cel.CustomTypeProvider(celHelper.TypeProvider()), - ) + } + env, err := cel.NewCustomEnv(envOpts...) if err != nil { return nil, err } diff --git a/_examples/03_custom_resolver/go.mod b/_examples/03_custom_resolver/go.mod index 90f5d2a5..30030315 100644 --- a/_examples/03_custom_resolver/go.mod +++ b/_examples/03_custom_resolver/go.mod @@ -27,6 +27,7 @@ require ( github.com/google/uuid v1.5.0 // indirect github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0 // indirect github.com/stoewer/go-strcase v1.2.0 // indirect + github.com/tetratelabs/wazero v1.6.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.21.0 // indirect go.opentelemetry.io/otel/metric v1.21.0 // indirect go.opentelemetry.io/proto/otlp v1.0.0 // indirect diff --git a/_examples/03_custom_resolver/go.sum b/_examples/03_custom_resolver/go.sum index f4e6e138..58a10076 100644 --- a/_examples/03_custom_resolver/go.sum +++ b/_examples/03_custom_resolver/go.sum @@ -32,6 +32,8 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+ github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/tetratelabs/wazero v1.6.0 h1:z0H1iikCdP8t+q341xqepY4EWvHEw8Es7tlqiVzlP3g= +github.com/tetratelabs/wazero v1.6.0/go.mod h1:0U0G41+ochRKoPKCJlh0jMg1CHkyfK8kDqiirMmKY8A= go.opentelemetry.io/otel v1.21.0 h1:hzLeKBZEL7Okw2mGzZ0cc4k/A7Fta0uoPgaJCr8fsFc= go.opentelemetry.io/otel v1.21.0/go.mod h1:QZzNPQPm1zLX4gZK4cMi+71eaorMSGT3A4znnUvNNEo= go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.21.0 h1:cl5P5/GIfFh4t6xyruOgJP5QiA1pw4fYYdv6nc6CBWw= diff --git a/_examples/04_timeout/.gitignore b/_examples/04_timeout/.gitignore new file mode 100644 index 00000000..81d0826b --- /dev/null +++ b/_examples/04_timeout/.gitignore @@ -0,0 +1,2 @@ +grpc/federation/federation.pb.go +grpc/federation/plugin.pb.go diff --git a/_examples/04_timeout/federation/federation_grpc_federation.pb.go b/_examples/04_timeout/federation/federation_grpc_federation.pb.go index 133bc55e..87479da7 100644 --- a/_examples/04_timeout/federation/federation_grpc_federation.pb.go +++ b/_examples/04_timeout/federation/federation_grpc_federation.pb.go @@ -71,6 +71,11 @@ type FederationServiceDependentClientSet struct { type FederationServiceResolver interface { } +type FederationServiceCELPluginWasmConfig = grpcfedcel.WasmConfig + +type FederationServiceCELPluginConfig struct { +} + // FederationServiceUnimplementedResolver a structure implemented to satisfy the Resolver interface. // An Unimplemented error is always returned. // This is intended for use when there are many Resolver interfaces that do not need to be implemented, @@ -120,13 +125,14 @@ func NewFederationService(cfg FederationServiceConfig) (*FederationService, erro "id": grpcfed.NewCELFieldType(celtypes.StringType, "Id"), }, }) - env, err := cel.NewCustomEnv( + envOpts := []cel.EnvOption{ cel.StdLib(), cel.Lib(grpcfedcel.NewLibrary()), cel.CrossTypeNumericComparisons(true), cel.CustomTypeAdapter(celHelper.TypeAdapter()), cel.CustomTypeProvider(celHelper.TypeProvider()), - ) + } + env, err := cel.NewCustomEnv(envOpts...) if err != nil { return nil, err } diff --git a/_examples/04_timeout/go.mod b/_examples/04_timeout/go.mod index e2562d96..54568988 100644 --- a/_examples/04_timeout/go.mod +++ b/_examples/04_timeout/go.mod @@ -25,6 +25,7 @@ require ( github.com/google/uuid v1.5.0 // indirect github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0 // indirect github.com/stoewer/go-strcase v1.2.0 // indirect + github.com/tetratelabs/wazero v1.6.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.21.0 // indirect go.opentelemetry.io/otel/metric v1.21.0 // indirect go.opentelemetry.io/proto/otlp v1.0.0 // indirect diff --git a/_examples/04_timeout/go.sum b/_examples/04_timeout/go.sum index f4e6e138..58a10076 100644 --- a/_examples/04_timeout/go.sum +++ b/_examples/04_timeout/go.sum @@ -32,6 +32,8 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+ github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/tetratelabs/wazero v1.6.0 h1:z0H1iikCdP8t+q341xqepY4EWvHEw8Es7tlqiVzlP3g= +github.com/tetratelabs/wazero v1.6.0/go.mod h1:0U0G41+ochRKoPKCJlh0jMg1CHkyfK8kDqiirMmKY8A= go.opentelemetry.io/otel v1.21.0 h1:hzLeKBZEL7Okw2mGzZ0cc4k/A7Fta0uoPgaJCr8fsFc= go.opentelemetry.io/otel v1.21.0/go.mod h1:QZzNPQPm1zLX4gZK4cMi+71eaorMSGT3A4znnUvNNEo= go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.21.0 h1:cl5P5/GIfFh4t6xyruOgJP5QiA1pw4fYYdv6nc6CBWw= diff --git a/_examples/05_async/.gitignore b/_examples/05_async/.gitignore new file mode 100644 index 00000000..81d0826b --- /dev/null +++ b/_examples/05_async/.gitignore @@ -0,0 +1,2 @@ +grpc/federation/federation.pb.go +grpc/federation/plugin.pb.go diff --git a/_examples/05_async/federation/federation_grpc_federation.pb.go b/_examples/05_async/federation/federation_grpc_federation.pb.go index b1559f0e..848cc2d4 100644 --- a/_examples/05_async/federation/federation_grpc_federation.pb.go +++ b/_examples/05_async/federation/federation_grpc_federation.pb.go @@ -133,6 +133,11 @@ type FederationServiceDependentClientSet struct { type FederationServiceResolver interface { } +type FederationServiceCELPluginWasmConfig = grpcfedcel.WasmConfig + +type FederationServiceCELPluginConfig struct { +} + // FederationServiceUnimplementedResolver a structure implemented to satisfy the Resolver interface. // An Unimplemented error is always returned. // This is intended for use when there are many Resolver interfaces that do not need to be implemented, @@ -191,13 +196,14 @@ func NewFederationService(cfg FederationServiceConfig) (*FederationService, erro "i": grpcfed.NewCELFieldType(celtypes.StringType, "I"), }, }) - env, err := cel.NewCustomEnv( + envOpts := []cel.EnvOption{ cel.StdLib(), cel.Lib(grpcfedcel.NewLibrary()), cel.CrossTypeNumericComparisons(true), cel.CustomTypeAdapter(celHelper.TypeAdapter()), cel.CustomTypeProvider(celHelper.TypeProvider()), - ) + } + env, err := cel.NewCustomEnv(envOpts...) if err != nil { return nil, err } diff --git a/_examples/05_async/go.mod b/_examples/05_async/go.mod index 90f5d2a5..30030315 100644 --- a/_examples/05_async/go.mod +++ b/_examples/05_async/go.mod @@ -27,6 +27,7 @@ require ( github.com/google/uuid v1.5.0 // indirect github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0 // indirect github.com/stoewer/go-strcase v1.2.0 // indirect + github.com/tetratelabs/wazero v1.6.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.21.0 // indirect go.opentelemetry.io/otel/metric v1.21.0 // indirect go.opentelemetry.io/proto/otlp v1.0.0 // indirect diff --git a/_examples/05_async/go.sum b/_examples/05_async/go.sum index f4e6e138..58a10076 100644 --- a/_examples/05_async/go.sum +++ b/_examples/05_async/go.sum @@ -32,6 +32,8 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+ github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/tetratelabs/wazero v1.6.0 h1:z0H1iikCdP8t+q341xqepY4EWvHEw8Es7tlqiVzlP3g= +github.com/tetratelabs/wazero v1.6.0/go.mod h1:0U0G41+ochRKoPKCJlh0jMg1CHkyfK8kDqiirMmKY8A= go.opentelemetry.io/otel v1.21.0 h1:hzLeKBZEL7Okw2mGzZ0cc4k/A7Fta0uoPgaJCr8fsFc= go.opentelemetry.io/otel v1.21.0/go.mod h1:QZzNPQPm1zLX4gZK4cMi+71eaorMSGT3A4znnUvNNEo= go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.21.0 h1:cl5P5/GIfFh4t6xyruOgJP5QiA1pw4fYYdv6nc6CBWw= diff --git a/_examples/06_alias/.gitignore b/_examples/06_alias/.gitignore new file mode 100644 index 00000000..81d0826b --- /dev/null +++ b/_examples/06_alias/.gitignore @@ -0,0 +1,2 @@ +grpc/federation/federation.pb.go +grpc/federation/plugin.pb.go diff --git a/_examples/06_alias/federation/federation_grpc_federation.pb.go b/_examples/06_alias/federation/federation_grpc_federation.pb.go index 8e416860..33fd6179 100644 --- a/_examples/06_alias/federation/federation_grpc_federation.pb.go +++ b/_examples/06_alias/federation/federation_grpc_federation.pb.go @@ -81,6 +81,11 @@ type FederationServiceDependentClientSet struct { type FederationServiceResolver interface { } +type FederationServiceCELPluginWasmConfig = grpcfedcel.WasmConfig + +type FederationServiceCELPluginConfig struct { +} + // FederationServiceUnimplementedResolver a structure implemented to satisfy the Resolver interface. // An Unimplemented error is always returned. // This is intended for use when there are many Resolver interfaces that do not need to be implemented, @@ -130,13 +135,14 @@ func NewFederationService(cfg FederationServiceConfig) (*FederationService, erro "id": grpcfed.NewCELFieldType(celtypes.StringType, "Id"), }, }) - env, err := cel.NewCustomEnv( + envOpts := []cel.EnvOption{ cel.StdLib(), cel.Lib(grpcfedcel.NewLibrary()), cel.CrossTypeNumericComparisons(true), cel.CustomTypeAdapter(celHelper.TypeAdapter()), cel.CustomTypeProvider(celHelper.TypeProvider()), - ) + } + env, err := cel.NewCustomEnv(envOpts...) if err != nil { return nil, err } diff --git a/_examples/06_alias/go.mod b/_examples/06_alias/go.mod index 4ecb5f3e..b550aae6 100644 --- a/_examples/06_alias/go.mod +++ b/_examples/06_alias/go.mod @@ -26,6 +26,7 @@ require ( github.com/google/uuid v1.5.0 // indirect github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0 // indirect github.com/stoewer/go-strcase v1.2.0 // indirect + github.com/tetratelabs/wazero v1.6.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.21.0 // indirect go.opentelemetry.io/otel/metric v1.21.0 // indirect go.opentelemetry.io/proto/otlp v1.0.0 // indirect diff --git a/_examples/06_alias/go.sum b/_examples/06_alias/go.sum index f4e6e138..58a10076 100644 --- a/_examples/06_alias/go.sum +++ b/_examples/06_alias/go.sum @@ -32,6 +32,8 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+ github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/tetratelabs/wazero v1.6.0 h1:z0H1iikCdP8t+q341xqepY4EWvHEw8Es7tlqiVzlP3g= +github.com/tetratelabs/wazero v1.6.0/go.mod h1:0U0G41+ochRKoPKCJlh0jMg1CHkyfK8kDqiirMmKY8A= go.opentelemetry.io/otel v1.21.0 h1:hzLeKBZEL7Okw2mGzZ0cc4k/A7Fta0uoPgaJCr8fsFc= go.opentelemetry.io/otel v1.21.0/go.mod h1:QZzNPQPm1zLX4gZK4cMi+71eaorMSGT3A4znnUvNNEo= go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.21.0 h1:cl5P5/GIfFh4t6xyruOgJP5QiA1pw4fYYdv6nc6CBWw= diff --git a/_examples/07_autobind/.gitignore b/_examples/07_autobind/.gitignore index fec7fd36..34f115c8 100644 --- a/_examples/07_autobind/.gitignore +++ b/_examples/07_autobind/.gitignore @@ -1 +1,3 @@ grpc/federation/federation.pb.go +grpc/federation/plugin.pb.go + diff --git a/_examples/07_autobind/federation/federation_grpc_federation.pb.go b/_examples/07_autobind/federation/federation_grpc_federation.pb.go index 43b1d981..042b8a9a 100644 --- a/_examples/07_autobind/federation/federation_grpc_federation.pb.go +++ b/_examples/07_autobind/federation/federation_grpc_federation.pb.go @@ -79,6 +79,11 @@ type FederationServiceDependentClientSet struct { type FederationServiceResolver interface { } +type FederationServiceCELPluginWasmConfig = grpcfedcel.WasmConfig + +type FederationServiceCELPluginConfig struct { +} + // FederationServiceUnimplementedResolver a structure implemented to satisfy the Resolver interface. // An Unimplemented error is always returned. // This is intended for use when there are many Resolver interfaces that do not need to be implemented, @@ -131,13 +136,14 @@ func NewFederationService(cfg FederationServiceConfig) (*FederationService, erro "user_id": grpcfed.NewCELFieldType(celtypes.StringType, "UserId"), }, }) - env, err := cel.NewCustomEnv( + envOpts := []cel.EnvOption{ cel.StdLib(), cel.Lib(grpcfedcel.NewLibrary()), cel.CrossTypeNumericComparisons(true), cel.CustomTypeAdapter(celHelper.TypeAdapter()), cel.CustomTypeProvider(celHelper.TypeProvider()), - ) + } + env, err := cel.NewCustomEnv(envOpts...) if err != nil { return nil, err } diff --git a/_examples/07_autobind/go.mod b/_examples/07_autobind/go.mod index 90f5d2a5..30030315 100644 --- a/_examples/07_autobind/go.mod +++ b/_examples/07_autobind/go.mod @@ -27,6 +27,7 @@ require ( github.com/google/uuid v1.5.0 // indirect github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0 // indirect github.com/stoewer/go-strcase v1.2.0 // indirect + github.com/tetratelabs/wazero v1.6.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.21.0 // indirect go.opentelemetry.io/otel/metric v1.21.0 // indirect go.opentelemetry.io/proto/otlp v1.0.0 // indirect diff --git a/_examples/07_autobind/go.sum b/_examples/07_autobind/go.sum index f4e6e138..58a10076 100644 --- a/_examples/07_autobind/go.sum +++ b/_examples/07_autobind/go.sum @@ -32,6 +32,8 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+ github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/tetratelabs/wazero v1.6.0 h1:z0H1iikCdP8t+q341xqepY4EWvHEw8Es7tlqiVzlP3g= +github.com/tetratelabs/wazero v1.6.0/go.mod h1:0U0G41+ochRKoPKCJlh0jMg1CHkyfK8kDqiirMmKY8A= go.opentelemetry.io/otel v1.21.0 h1:hzLeKBZEL7Okw2mGzZ0cc4k/A7Fta0uoPgaJCr8fsFc= go.opentelemetry.io/otel v1.21.0/go.mod h1:QZzNPQPm1zLX4gZK4cMi+71eaorMSGT3A4znnUvNNEo= go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.21.0 h1:cl5P5/GIfFh4t6xyruOgJP5QiA1pw4fYYdv6nc6CBWw= diff --git a/_examples/08_literal/.gitignore b/_examples/08_literal/.gitignore index fec7fd36..81d0826b 100644 --- a/_examples/08_literal/.gitignore +++ b/_examples/08_literal/.gitignore @@ -1 +1,2 @@ grpc/federation/federation.pb.go +grpc/federation/plugin.pb.go diff --git a/_examples/08_literal/federation/federation_grpc_federation.pb.go b/_examples/08_literal/federation/federation_grpc_federation.pb.go index 6ab618fb..e9d91102 100644 --- a/_examples/08_literal/federation/federation_grpc_federation.pb.go +++ b/_examples/08_literal/federation/federation_grpc_federation.pb.go @@ -109,6 +109,11 @@ type FederationServiceDependentClientSet struct { type FederationServiceResolver interface { } +type FederationServiceCELPluginWasmConfig = grpcfedcel.WasmConfig + +type FederationServiceCELPluginConfig struct { +} + // FederationServiceUnimplementedResolver a structure implemented to satisfy the Resolver interface. // An Unimplemented error is always returned. // This is intended for use when there are many Resolver interfaces that do not need to be implemented, @@ -194,13 +199,14 @@ func NewFederationService(cfg FederationServiceConfig) (*FederationService, erro "id": grpcfed.NewCELFieldType(celtypes.StringType, "Id"), }, }) - env, err := cel.NewCustomEnv( + envOpts := []cel.EnvOption{ cel.StdLib(), cel.Lib(grpcfedcel.NewLibrary()), cel.CrossTypeNumericComparisons(true), cel.CustomTypeAdapter(celHelper.TypeAdapter()), cel.CustomTypeProvider(celHelper.TypeProvider()), - ) + } + env, err := cel.NewCustomEnv(envOpts...) if err != nil { return nil, err } diff --git a/_examples/08_literal/go.mod b/_examples/08_literal/go.mod index 90f5d2a5..30030315 100644 --- a/_examples/08_literal/go.mod +++ b/_examples/08_literal/go.mod @@ -27,6 +27,7 @@ require ( github.com/google/uuid v1.5.0 // indirect github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0 // indirect github.com/stoewer/go-strcase v1.2.0 // indirect + github.com/tetratelabs/wazero v1.6.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.21.0 // indirect go.opentelemetry.io/otel/metric v1.21.0 // indirect go.opentelemetry.io/proto/otlp v1.0.0 // indirect diff --git a/_examples/08_literal/go.sum b/_examples/08_literal/go.sum index f4e6e138..58a10076 100644 --- a/_examples/08_literal/go.sum +++ b/_examples/08_literal/go.sum @@ -32,6 +32,8 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+ github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/tetratelabs/wazero v1.6.0 h1:z0H1iikCdP8t+q341xqepY4EWvHEw8Es7tlqiVzlP3g= +github.com/tetratelabs/wazero v1.6.0/go.mod h1:0U0G41+ochRKoPKCJlh0jMg1CHkyfK8kDqiirMmKY8A= go.opentelemetry.io/otel v1.21.0 h1:hzLeKBZEL7Okw2mGzZ0cc4k/A7Fta0uoPgaJCr8fsFc= go.opentelemetry.io/otel v1.21.0/go.mod h1:QZzNPQPm1zLX4gZK4cMi+71eaorMSGT3A4znnUvNNEo= go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.21.0 h1:cl5P5/GIfFh4t6xyruOgJP5QiA1pw4fYYdv6nc6CBWw= diff --git a/_examples/09_multi_user/.gitignore b/_examples/09_multi_user/.gitignore new file mode 100644 index 00000000..81d0826b --- /dev/null +++ b/_examples/09_multi_user/.gitignore @@ -0,0 +1,2 @@ +grpc/federation/federation.pb.go +grpc/federation/plugin.pb.go diff --git a/_examples/09_multi_user/federation/federation_grpc_federation.pb.go b/_examples/09_multi_user/federation/federation_grpc_federation.pb.go index 23490cd6..157414d5 100644 --- a/_examples/09_multi_user/federation/federation_grpc_federation.pb.go +++ b/_examples/09_multi_user/federation/federation_grpc_federation.pb.go @@ -99,6 +99,11 @@ type FederationServiceResolver interface { Resolve_Org_Federation_User_Name(context.Context, *Org_Federation_User_NameArgument[*FederationServiceDependentClientSet]) (string, error) } +type FederationServiceCELPluginWasmConfig = grpcfedcel.WasmConfig + +type FederationServiceCELPluginConfig struct { +} + // FederationServiceUnimplementedResolver a structure implemented to satisfy the Resolver interface. // An Unimplemented error is always returned. // This is intended for use when there are many Resolver interfaces that do not need to be implemented, @@ -166,13 +171,14 @@ func NewFederationService(cfg FederationServiceConfig) (*FederationService, erro }, "grpc.federation.private.UserIDArgument": {}, }) - env, err := cel.NewCustomEnv( + envOpts := []cel.EnvOption{ cel.StdLib(), cel.Lib(grpcfedcel.NewLibrary()), cel.CrossTypeNumericComparisons(true), cel.CustomTypeAdapter(celHelper.TypeAdapter()), cel.CustomTypeProvider(celHelper.TypeProvider()), - ) + } + env, err := cel.NewCustomEnv(envOpts...) if err != nil { return nil, err } diff --git a/_examples/09_multi_user/go.mod b/_examples/09_multi_user/go.mod index 90f5d2a5..30030315 100644 --- a/_examples/09_multi_user/go.mod +++ b/_examples/09_multi_user/go.mod @@ -27,6 +27,7 @@ require ( github.com/google/uuid v1.5.0 // indirect github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0 // indirect github.com/stoewer/go-strcase v1.2.0 // indirect + github.com/tetratelabs/wazero v1.6.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.21.0 // indirect go.opentelemetry.io/otel/metric v1.21.0 // indirect go.opentelemetry.io/proto/otlp v1.0.0 // indirect diff --git a/_examples/09_multi_user/go.sum b/_examples/09_multi_user/go.sum index f4e6e138..58a10076 100644 --- a/_examples/09_multi_user/go.sum +++ b/_examples/09_multi_user/go.sum @@ -32,6 +32,8 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+ github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/tetratelabs/wazero v1.6.0 h1:z0H1iikCdP8t+q341xqepY4EWvHEw8Es7tlqiVzlP3g= +github.com/tetratelabs/wazero v1.6.0/go.mod h1:0U0G41+ochRKoPKCJlh0jMg1CHkyfK8kDqiirMmKY8A= go.opentelemetry.io/otel v1.21.0 h1:hzLeKBZEL7Okw2mGzZ0cc4k/A7Fta0uoPgaJCr8fsFc= go.opentelemetry.io/otel v1.21.0/go.mod h1:QZzNPQPm1zLX4gZK4cMi+71eaorMSGT3A4znnUvNNEo= go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.21.0 h1:cl5P5/GIfFh4t6xyruOgJP5QiA1pw4fYYdv6nc6CBWw= diff --git a/_examples/10_oneof/.gitignore b/_examples/10_oneof/.gitignore new file mode 100644 index 00000000..81d0826b --- /dev/null +++ b/_examples/10_oneof/.gitignore @@ -0,0 +1,2 @@ +grpc/federation/federation.pb.go +grpc/federation/plugin.pb.go diff --git a/_examples/10_oneof/federation/federation_grpc_federation.pb.go b/_examples/10_oneof/federation/federation_grpc_federation.pb.go index 5d72eb13..b9064e60 100644 --- a/_examples/10_oneof/federation/federation_grpc_federation.pb.go +++ b/_examples/10_oneof/federation/federation_grpc_federation.pb.go @@ -80,6 +80,11 @@ type FederationServiceDependentClientSet struct { type FederationServiceResolver interface { } +type FederationServiceCELPluginWasmConfig = grpcfedcel.WasmConfig + +type FederationServiceCELPluginConfig struct { +} + // FederationServiceUnimplementedResolver a structure implemented to satisfy the Resolver interface. // An Unimplemented error is always returned. // This is intended for use when there are many Resolver interfaces that do not need to be implemented, @@ -138,13 +143,14 @@ func NewFederationService(cfg FederationServiceConfig) (*FederationService, erro ), }, }) - env, err := cel.NewCustomEnv( + envOpts := []cel.EnvOption{ cel.StdLib(), cel.Lib(grpcfedcel.NewLibrary()), cel.CrossTypeNumericComparisons(true), cel.CustomTypeAdapter(celHelper.TypeAdapter()), cel.CustomTypeProvider(celHelper.TypeProvider()), - ) + } + env, err := cel.NewCustomEnv(envOpts...) if err != nil { return nil, err } diff --git a/_examples/10_oneof/go.mod b/_examples/10_oneof/go.mod index 4ecb5f3e..b550aae6 100644 --- a/_examples/10_oneof/go.mod +++ b/_examples/10_oneof/go.mod @@ -26,6 +26,7 @@ require ( github.com/google/uuid v1.5.0 // indirect github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0 // indirect github.com/stoewer/go-strcase v1.2.0 // indirect + github.com/tetratelabs/wazero v1.6.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.21.0 // indirect go.opentelemetry.io/otel/metric v1.21.0 // indirect go.opentelemetry.io/proto/otlp v1.0.0 // indirect diff --git a/_examples/10_oneof/go.sum b/_examples/10_oneof/go.sum index f4e6e138..58a10076 100644 --- a/_examples/10_oneof/go.sum +++ b/_examples/10_oneof/go.sum @@ -32,6 +32,8 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+ github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/tetratelabs/wazero v1.6.0 h1:z0H1iikCdP8t+q341xqepY4EWvHEw8Es7tlqiVzlP3g= +github.com/tetratelabs/wazero v1.6.0/go.mod h1:0U0G41+ochRKoPKCJlh0jMg1CHkyfK8kDqiirMmKY8A= go.opentelemetry.io/otel v1.21.0 h1:hzLeKBZEL7Okw2mGzZ0cc4k/A7Fta0uoPgaJCr8fsFc= go.opentelemetry.io/otel v1.21.0/go.mod h1:QZzNPQPm1zLX4gZK4cMi+71eaorMSGT3A4znnUvNNEo= go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.21.0 h1:cl5P5/GIfFh4t6xyruOgJP5QiA1pw4fYYdv6nc6CBWw= diff --git a/_examples/11_multi_service/.gitignore b/_examples/11_multi_service/.gitignore new file mode 100644 index 00000000..81d0826b --- /dev/null +++ b/_examples/11_multi_service/.gitignore @@ -0,0 +1,2 @@ +grpc/federation/federation.pb.go +grpc/federation/plugin.pb.go diff --git a/_examples/11_multi_service/federation/federation_grpc_federation.pb.go b/_examples/11_multi_service/federation/federation_grpc_federation.pb.go index 77289a83..f1ee1832 100644 --- a/_examples/11_multi_service/federation/federation_grpc_federation.pb.go +++ b/_examples/11_multi_service/federation/federation_grpc_federation.pb.go @@ -73,6 +73,11 @@ type FederationServiceDependentClientSet struct { type FederationServiceResolver interface { } +type FederationServiceCELPluginWasmConfig = grpcfedcel.WasmConfig + +type FederationServiceCELPluginConfig struct { +} + // FederationServiceUnimplementedResolver a structure implemented to satisfy the Resolver interface. // An Unimplemented error is always returned. // This is intended for use when there are many Resolver interfaces that do not need to be implemented, @@ -110,13 +115,14 @@ func NewFederationService(cfg FederationServiceConfig) (*FederationService, erro "name": grpcfed.NewCELFieldType(celtypes.StringType, "Name"), }, }) - env, err := cel.NewCustomEnv( + envOpts := []cel.EnvOption{ cel.StdLib(), cel.Lib(grpcfedcel.NewLibrary()), cel.CrossTypeNumericComparisons(true), cel.CustomTypeAdapter(celHelper.TypeAdapter()), cel.CustomTypeProvider(celHelper.TypeProvider()), - ) + } + env, err := cel.NewCustomEnv(envOpts...) if err != nil { return nil, err } @@ -394,6 +400,11 @@ type DebugServiceDependentClientSet struct { type DebugServiceResolver interface { } +type DebugServiceCELPluginWasmConfig = grpcfedcel.WasmConfig + +type DebugServiceCELPluginConfig struct { +} + // DebugServiceUnimplementedResolver a structure implemented to satisfy the Resolver interface. // An Unimplemented error is always returned. // This is intended for use when there are many Resolver interfaces that do not need to be implemented, @@ -428,13 +439,14 @@ func NewDebugService(cfg DebugServiceConfig) (*DebugService, error) { "name": grpcfed.NewCELFieldType(celtypes.StringType, "Name"), }, }) - env, err := cel.NewCustomEnv( + envOpts := []cel.EnvOption{ cel.StdLib(), cel.Lib(grpcfedcel.NewLibrary()), cel.CrossTypeNumericComparisons(true), cel.CustomTypeAdapter(celHelper.TypeAdapter()), cel.CustomTypeProvider(celHelper.TypeProvider()), - ) + } + env, err := cel.NewCustomEnv(envOpts...) if err != nil { return nil, err } diff --git a/_examples/11_multi_service/federation/other_grpc_federation.pb.go b/_examples/11_multi_service/federation/other_grpc_federation.pb.go index d97764eb..1df8afd6 100644 --- a/_examples/11_multi_service/federation/other_grpc_federation.pb.go +++ b/_examples/11_multi_service/federation/other_grpc_federation.pb.go @@ -68,6 +68,11 @@ type OtherServiceResolver interface { Resolve_Federation_GetResponse_Post(context.Context, *Federation_GetResponse_PostArgument[*OtherServiceDependentClientSet]) (*Post, error) } +type OtherServiceCELPluginWasmConfig = grpcfedcel.WasmConfig + +type OtherServiceCELPluginConfig struct { +} + // OtherServiceUnimplementedResolver a structure implemented to satisfy the Resolver interface. // An Unimplemented error is always returned. // This is intended for use when there are many Resolver interfaces that do not need to be implemented, @@ -116,13 +121,14 @@ func NewOtherService(cfg OtherServiceConfig) (*OtherService, error) { "name": grpcfed.NewCELFieldType(celtypes.StringType, "Name"), }, }) - env, err := cel.NewCustomEnv( + envOpts := []cel.EnvOption{ cel.StdLib(), cel.Lib(grpcfedcel.NewLibrary()), cel.CrossTypeNumericComparisons(true), cel.CustomTypeAdapter(celHelper.TypeAdapter()), cel.CustomTypeProvider(celHelper.TypeProvider()), - ) + } + env, err := cel.NewCustomEnv(envOpts...) if err != nil { return nil, err } diff --git a/_examples/11_multi_service/go.mod b/_examples/11_multi_service/go.mod index 4ecb5f3e..b550aae6 100644 --- a/_examples/11_multi_service/go.mod +++ b/_examples/11_multi_service/go.mod @@ -26,6 +26,7 @@ require ( github.com/google/uuid v1.5.0 // indirect github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0 // indirect github.com/stoewer/go-strcase v1.2.0 // indirect + github.com/tetratelabs/wazero v1.6.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.21.0 // indirect go.opentelemetry.io/otel/metric v1.21.0 // indirect go.opentelemetry.io/proto/otlp v1.0.0 // indirect diff --git a/_examples/11_multi_service/go.sum b/_examples/11_multi_service/go.sum index f4e6e138..58a10076 100644 --- a/_examples/11_multi_service/go.sum +++ b/_examples/11_multi_service/go.sum @@ -32,6 +32,8 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+ github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/tetratelabs/wazero v1.6.0 h1:z0H1iikCdP8t+q341xqepY4EWvHEw8Es7tlqiVzlP3g= +github.com/tetratelabs/wazero v1.6.0/go.mod h1:0U0G41+ochRKoPKCJlh0jMg1CHkyfK8kDqiirMmKY8A= go.opentelemetry.io/otel v1.21.0 h1:hzLeKBZEL7Okw2mGzZ0cc4k/A7Fta0uoPgaJCr8fsFc= go.opentelemetry.io/otel v1.21.0/go.mod h1:QZzNPQPm1zLX4gZK4cMi+71eaorMSGT3A4znnUvNNEo= go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.21.0 h1:cl5P5/GIfFh4t6xyruOgJP5QiA1pw4fYYdv6nc6CBWw= diff --git a/_examples/12_validation/.gitignore b/_examples/12_validation/.gitignore index fec7fd36..81d0826b 100644 --- a/_examples/12_validation/.gitignore +++ b/_examples/12_validation/.gitignore @@ -1 +1,2 @@ grpc/federation/federation.pb.go +grpc/federation/plugin.pb.go diff --git a/_examples/12_validation/federation/federation_grpc_federation.pb.go b/_examples/12_validation/federation/federation_grpc_federation.pb.go index faba9f6d..1866af1c 100644 --- a/_examples/12_validation/federation/federation_grpc_federation.pb.go +++ b/_examples/12_validation/federation/federation_grpc_federation.pb.go @@ -81,6 +81,11 @@ type FederationServiceResolver interface { Resolve_Org_Federation_CustomHandlerMessage(context.Context, *Org_Federation_CustomHandlerMessageArgument[*FederationServiceDependentClientSet]) (*CustomHandlerMessage, error) } +type FederationServiceCELPluginWasmConfig = grpcfedcel.WasmConfig + +type FederationServiceCELPluginConfig struct { +} + // FederationServiceUnimplementedResolver a structure implemented to satisfy the Resolver interface. // An Unimplemented error is always returned. // This is intended for use when there are many Resolver interfaces that do not need to be implemented, @@ -131,13 +136,14 @@ func NewFederationService(cfg FederationServiceConfig) (*FederationService, erro }, "grpc.federation.private.PostArgument": {}, }) - env, err := cel.NewCustomEnv( + envOpts := []cel.EnvOption{ cel.StdLib(), cel.Lib(grpcfedcel.NewLibrary()), cel.CrossTypeNumericComparisons(true), cel.CustomTypeAdapter(celHelper.TypeAdapter()), cel.CustomTypeProvider(celHelper.TypeProvider()), - ) + } + env, err := cel.NewCustomEnv(envOpts...) if err != nil { return nil, err } diff --git a/_examples/12_validation/go.mod b/_examples/12_validation/go.mod index 9d230383..b739bb46 100644 --- a/_examples/12_validation/go.mod +++ b/_examples/12_validation/go.mod @@ -24,6 +24,7 @@ require ( github.com/golang/protobuf v1.5.3 // indirect github.com/google/uuid v1.5.0 // indirect github.com/stoewer/go-strcase v1.2.0 // indirect + github.com/tetratelabs/wazero v1.6.0 // indirect go.opentelemetry.io/otel/metric v1.21.0 // indirect golang.org/x/exp v0.0.0-20230515195305-f3d0a9c9a5cc // indirect golang.org/x/net v0.19.0 // indirect diff --git a/_examples/12_validation/go.sum b/_examples/12_validation/go.sum index 7a279e87..0262d59b 100644 --- a/_examples/12_validation/go.sum +++ b/_examples/12_validation/go.sum @@ -28,6 +28,8 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+ github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/tetratelabs/wazero v1.6.0 h1:z0H1iikCdP8t+q341xqepY4EWvHEw8Es7tlqiVzlP3g= +github.com/tetratelabs/wazero v1.6.0/go.mod h1:0U0G41+ochRKoPKCJlh0jMg1CHkyfK8kDqiirMmKY8A= go.opentelemetry.io/otel v1.21.0 h1:hzLeKBZEL7Okw2mGzZ0cc4k/A7Fta0uoPgaJCr8fsFc= go.opentelemetry.io/otel v1.21.0/go.mod h1:QZzNPQPm1zLX4gZK4cMi+71eaorMSGT3A4znnUvNNEo= go.opentelemetry.io/otel/metric v1.21.0 h1:tlYWfeo+Bocx5kLEloTjbcDwBuELRrIFxwdQ36PlJu4= diff --git a/_examples/13_map/.gitignore b/_examples/13_map/.gitignore index fec7fd36..81d0826b 100644 --- a/_examples/13_map/.gitignore +++ b/_examples/13_map/.gitignore @@ -1 +1,2 @@ grpc/federation/federation.pb.go +grpc/federation/plugin.pb.go diff --git a/_examples/13_map/federation/federation_grpc_federation.pb.go b/_examples/13_map/federation/federation_grpc_federation.pb.go index 83714d93..2f01d1eb 100644 --- a/_examples/13_map/federation/federation_grpc_federation.pb.go +++ b/_examples/13_map/federation/federation_grpc_federation.pb.go @@ -87,6 +87,11 @@ type FederationServiceDependentClientSet struct { type FederationServiceResolver interface { } +type FederationServiceCELPluginWasmConfig = grpcfedcel.WasmConfig + +type FederationServiceCELPluginConfig struct { +} + // FederationServiceUnimplementedResolver a structure implemented to satisfy the Resolver interface. // An Unimplemented error is always returned. // This is intended for use when there are many Resolver interfaces that do not need to be implemented, @@ -147,13 +152,14 @@ func NewFederationService(cfg FederationServiceConfig) (*FederationService, erro "user_id": grpcfed.NewCELFieldType(celtypes.StringType, "UserId"), }, }) - env, err := cel.NewCustomEnv( + envOpts := []cel.EnvOption{ cel.StdLib(), cel.Lib(grpcfedcel.NewLibrary()), cel.CrossTypeNumericComparisons(true), cel.CustomTypeAdapter(celHelper.TypeAdapter()), cel.CustomTypeProvider(celHelper.TypeProvider()), - ) + } + env, err := cel.NewCustomEnv(envOpts...) if err != nil { return nil, err } diff --git a/_examples/13_map/go.mod b/_examples/13_map/go.mod index 90f5d2a5..30030315 100644 --- a/_examples/13_map/go.mod +++ b/_examples/13_map/go.mod @@ -27,6 +27,7 @@ require ( github.com/google/uuid v1.5.0 // indirect github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0 // indirect github.com/stoewer/go-strcase v1.2.0 // indirect + github.com/tetratelabs/wazero v1.6.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.21.0 // indirect go.opentelemetry.io/otel/metric v1.21.0 // indirect go.opentelemetry.io/proto/otlp v1.0.0 // indirect diff --git a/_examples/13_map/go.sum b/_examples/13_map/go.sum index f4e6e138..58a10076 100644 --- a/_examples/13_map/go.sum +++ b/_examples/13_map/go.sum @@ -32,6 +32,8 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+ github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/tetratelabs/wazero v1.6.0 h1:z0H1iikCdP8t+q341xqepY4EWvHEw8Es7tlqiVzlP3g= +github.com/tetratelabs/wazero v1.6.0/go.mod h1:0U0G41+ochRKoPKCJlh0jMg1CHkyfK8kDqiirMmKY8A= go.opentelemetry.io/otel v1.21.0 h1:hzLeKBZEL7Okw2mGzZ0cc4k/A7Fta0uoPgaJCr8fsFc= go.opentelemetry.io/otel v1.21.0/go.mod h1:QZzNPQPm1zLX4gZK4cMi+71eaorMSGT3A4znnUvNNEo= go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.21.0 h1:cl5P5/GIfFh4t6xyruOgJP5QiA1pw4fYYdv6nc6CBWw= diff --git a/_examples/14_condition/.gitignore b/_examples/14_condition/.gitignore new file mode 100644 index 00000000..81d0826b --- /dev/null +++ b/_examples/14_condition/.gitignore @@ -0,0 +1,2 @@ +grpc/federation/federation.pb.go +grpc/federation/plugin.pb.go diff --git a/_examples/14_condition/federation/federation_grpc_federation.pb.go b/_examples/14_condition/federation/federation_grpc_federation.pb.go index e1e77916..da26eb73 100644 --- a/_examples/14_condition/federation/federation_grpc_federation.pb.go +++ b/_examples/14_condition/federation/federation_grpc_federation.pb.go @@ -83,6 +83,11 @@ type FederationServiceDependentClientSet struct { type FederationServiceResolver interface { } +type FederationServiceCELPluginWasmConfig = grpcfedcel.WasmConfig + +type FederationServiceCELPluginConfig struct { +} + // FederationServiceUnimplementedResolver a structure implemented to satisfy the Resolver interface. // An Unimplemented error is always returned. // This is intended for use when there are many Resolver interfaces that do not need to be implemented, @@ -135,13 +140,14 @@ func NewFederationService(cfg FederationServiceConfig) (*FederationService, erro "user_id": grpcfed.NewCELFieldType(celtypes.StringType, "UserId"), }, }) - env, err := cel.NewCustomEnv( + envOpts := []cel.EnvOption{ cel.StdLib(), cel.Lib(grpcfedcel.NewLibrary()), cel.CrossTypeNumericComparisons(true), cel.CustomTypeAdapter(celHelper.TypeAdapter()), cel.CustomTypeProvider(celHelper.TypeProvider()), - ) + } + env, err := cel.NewCustomEnv(envOpts...) if err != nil { return nil, err } diff --git a/_examples/14_condition/go.mod b/_examples/14_condition/go.mod index 90f5d2a5..30030315 100644 --- a/_examples/14_condition/go.mod +++ b/_examples/14_condition/go.mod @@ -27,6 +27,7 @@ require ( github.com/google/uuid v1.5.0 // indirect github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0 // indirect github.com/stoewer/go-strcase v1.2.0 // indirect + github.com/tetratelabs/wazero v1.6.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.21.0 // indirect go.opentelemetry.io/otel/metric v1.21.0 // indirect go.opentelemetry.io/proto/otlp v1.0.0 // indirect diff --git a/_examples/14_condition/go.sum b/_examples/14_condition/go.sum index f4e6e138..58a10076 100644 --- a/_examples/14_condition/go.sum +++ b/_examples/14_condition/go.sum @@ -32,6 +32,8 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+ github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/tetratelabs/wazero v1.6.0 h1:z0H1iikCdP8t+q341xqepY4EWvHEw8Es7tlqiVzlP3g= +github.com/tetratelabs/wazero v1.6.0/go.mod h1:0U0G41+ochRKoPKCJlh0jMg1CHkyfK8kDqiirMmKY8A= go.opentelemetry.io/otel v1.21.0 h1:hzLeKBZEL7Okw2mGzZ0cc4k/A7Fta0uoPgaJCr8fsFc= go.opentelemetry.io/otel v1.21.0/go.mod h1:QZzNPQPm1zLX4gZK4cMi+71eaorMSGT3A4znnUvNNEo= go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.21.0 h1:cl5P5/GIfFh4t6xyruOgJP5QiA1pw4fYYdv6nc6CBWw= diff --git a/_examples/15_plugin/.gitignore b/_examples/15_plugin/.gitignore new file mode 100644 index 00000000..81d0826b --- /dev/null +++ b/_examples/15_plugin/.gitignore @@ -0,0 +1,2 @@ +grpc/federation/federation.pb.go +grpc/federation/plugin.pb.go diff --git a/_examples/15_plugin/Makefile b/_examples/15_plugin/Makefile new file mode 100644 index 00000000..11fab355 --- /dev/null +++ b/_examples/15_plugin/Makefile @@ -0,0 +1,42 @@ +MAKEFILE_DIR := $(dir $(lastword $(MAKEFILE_LIST))) +GOBIN := $(MAKEFILE_DIR)/../../bin +PATH := $(GOBIN):$(PATH) + +JAEGER_IMAGE := jaegertracing/all-in-one:latest + +.PHONY: generate +generate: + $(GOBIN)/buf generate + +.PHONY: lint +lint: + @$(GOBIN)/grpc-federation-linter -Iproto -Iproto_deps ./proto/federation/federation.proto + +.PHONY: test +test: + go test -race ./ -count=1 + +.PHONY: grpc-federation/generate +grpc-federation/generate: + @$(GOBIN)/grpc-federation-generator ./proto/federation/federation.proto + +.PHONY: grpc-federation/watch +grpc-federation/watch: + @$(GOBIN)/grpc-federation-generator -w + +.PHONY: jaeger/start +jaeger/start: + @docker run \ + -e COLLECTOR_OTLP_ENABLED=true \ + -p 16686:16686 \ + -p 4317:4317 \ + -p 4318:4318 \ + -d \ + $(JAEGER_IMAGE) + +.PHONY: jaeger/stop +jaeger/stop: + @docker stop $(shell docker ps -q --filter ancestor=$(JAEGER_IMAGE)) + +build/wasm: + tinygo build -o regexp.wasm -target wasi ./cmd/plugin diff --git a/_examples/15_plugin/README.md b/_examples/15_plugin/README.md new file mode 100644 index 00000000..34f38f39 --- /dev/null +++ b/_examples/15_plugin/README.md @@ -0,0 +1,99 @@ +# CEL Plugin Example + +## 1. Write plugin definition in ProtocolBuffers + +The plugin feature allows you to define global functions, methods, and variables. + +[plugin.proto](./proto/plugin/plugin.proto) + +## 2. Run code generator + +Run `make generate` to generate code by `protoc-gen-grpc-federation`. + +## 3. Write plugin code + +[cmd/plugin/main.go](./cmd/plugin/main.go) is the plugin source. + +The helper code needed to write the plugin is already generated, so it is used. + +[The helper is here](./plugin/plugin_grpc_federation.pb.go). + +In `plugin/plugin_grpc_federation.pb.go`, there is a `RegisterRegexpPlugin` function required for plugin registration and a `RegexpPlugin` interface required for the plugin. +The code for the plugin is as follows. + +```go +package main + +import ( + pluginpb "example/plugin" + "regexp" + "unsafe" +) + +type plugin struct{} + +func (_ *plugin) Val() string { + return "hello grpc-federation plugin" +} + +func (_ *plugin) Example_Regexp_Compile(expr string) (*pluginpb.Regexp, error) { + re, err := regexp.Compile(expr) + if err != nil { + return nil, err + } + return &pluginpb.Regexp{ + Ptr: uint64(uintptr(unsafe.Pointer(re))), + }, nil +} + +func (_ *plugin) Example_Regexp_Regexp_MatchString(re *pluginpb.Regexp, s string) (bool, error) { + return (*regexp.Regexp)(unsafe.Pointer(uintptr(re.Ptr))).MatchString(s), nil +} + +func main() { + pluginpb.RegisterRegexpPlugin(&plugin{}) +} +``` + +## 4. Compile a plugin to WebAssembly + +Run `make build/wasm` to compile to WebAssembly by `tinygo`. +( `regexp.wasm` is output ) + +## 5. Calculates sha256 value for the WebAssembly file + +```console +$ sha256sum regexp.wasm +7d70b1d3cb44940f3ea7534fb49b4c5c4e2f9c1ccef5dc3c38085417a09d9e9b regexp.wasm +``` + +## 6. Load plugin ( WebAssembly ) file + +Initialize the gRPC server with the path to the wasm file and the sha256 value of the file. + +```go +federationServer, err := federation.NewFederationService(federation.FederationServiceConfig{ + CELPlugin: &federation.FederationServiceCELPluginConfig{ + Regexp: federation.FederationServiceCELPluginWasmConfig{ + Path: "regexp.wasm", + Sha256: "7d70b1d3cb44940f3ea7534fb49b4c5c4e2f9c1ccef5dc3c38085417a09d9e9b", + }, + }, +}) +``` + +## 7. Plugin usage + +You can evaluate the plugin's API in the same way you would evaluate a regular usage (e.g. `by` feature). + +```proto +message IsMatchResponse { + option (grpc.federation.message) = { + def { + name: "matched" + by: "example.regexp.compile($.expr).matchString($.target)" + } + }; + bool result = 1 [(grpc.federation.field).by = "matched"]; +} +``` \ No newline at end of file diff --git a/_examples/15_plugin/buf.gen.yaml b/_examples/15_plugin/buf.gen.yaml new file mode 100644 index 00000000..8ca94d4a --- /dev/null +++ b/_examples/15_plugin/buf.gen.yaml @@ -0,0 +1,13 @@ +version: v1 +managed: + enabled: true +plugins: + - plugin: go + out: . + opt: paths=source_relative + - plugin: go-grpc + out: . + opt: paths=source_relative + - plugin: grpc-federation + out: . + opt: paths=source_relative diff --git a/_examples/15_plugin/buf.work.yaml b/_examples/15_plugin/buf.work.yaml new file mode 100644 index 00000000..ee4e66c7 --- /dev/null +++ b/_examples/15_plugin/buf.work.yaml @@ -0,0 +1,4 @@ +version: v1 +directories: + - proto + - proto_deps diff --git a/_examples/15_plugin/cmd/plugin/main.go b/_examples/15_plugin/cmd/plugin/main.go new file mode 100644 index 00000000..132548c5 --- /dev/null +++ b/_examples/15_plugin/cmd/plugin/main.go @@ -0,0 +1,31 @@ +package main + +import ( + pluginpb "example/plugin" + "regexp" + "unsafe" +) + +type plugin struct{} + +func (_ *plugin) Val() string { + return "hello grpc-federation plugin" +} + +func (_ *plugin) Example_Regexp_Compile(expr string) (*pluginpb.Regexp, error) { + re, err := regexp.Compile(expr) + if err != nil { + return nil, err + } + return &pluginpb.Regexp{ + Ptr: uint64(uintptr(unsafe.Pointer(re))), + }, nil +} + +func (_ *plugin) Example_Regexp_Regexp_MatchString(re *pluginpb.Regexp, s string) (bool, error) { + return (*regexp.Regexp)(unsafe.Pointer(uintptr(re.Ptr))).MatchString(s), nil +} + +func main() { + pluginpb.RegisterRegexpPlugin(&plugin{}) +} diff --git a/_examples/15_plugin/federation/federation.pb.go b/_examples/15_plugin/federation/federation.pb.go new file mode 100644 index 00000000..9e959490 --- /dev/null +++ b/_examples/15_plugin/federation/federation.pb.go @@ -0,0 +1,244 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.31.0 +// protoc (unknown) +// source: federation/federation.proto + +package federation + +import ( + _ "example/plugin" + _ "github.com/mercari/grpc-federation/grpc/federation" + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +type IsMatchRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Expr string `protobuf:"bytes,1,opt,name=expr,proto3" json:"expr,omitempty"` + Target string `protobuf:"bytes,2,opt,name=target,proto3" json:"target,omitempty"` +} + +func (x *IsMatchRequest) Reset() { + *x = IsMatchRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_federation_federation_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *IsMatchRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*IsMatchRequest) ProtoMessage() {} + +func (x *IsMatchRequest) ProtoReflect() protoreflect.Message { + mi := &file_federation_federation_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use IsMatchRequest.ProtoReflect.Descriptor instead. +func (*IsMatchRequest) Descriptor() ([]byte, []int) { + return file_federation_federation_proto_rawDescGZIP(), []int{0} +} + +func (x *IsMatchRequest) GetExpr() string { + if x != nil { + return x.Expr + } + return "" +} + +func (x *IsMatchRequest) GetTarget() string { + if x != nil { + return x.Target + } + return "" +} + +type IsMatchResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Result bool `protobuf:"varint,1,opt,name=result,proto3" json:"result,omitempty"` +} + +func (x *IsMatchResponse) Reset() { + *x = IsMatchResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_federation_federation_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *IsMatchResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*IsMatchResponse) ProtoMessage() {} + +func (x *IsMatchResponse) ProtoReflect() protoreflect.Message { + mi := &file_federation_federation_proto_msgTypes[1] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use IsMatchResponse.ProtoReflect.Descriptor instead. +func (*IsMatchResponse) Descriptor() ([]byte, []int) { + return file_federation_federation_proto_rawDescGZIP(), []int{1} +} + +func (x *IsMatchResponse) GetResult() bool { + if x != nil { + return x.Result + } + return false +} + +var File_federation_federation_proto protoreflect.FileDescriptor + +var file_federation_federation_proto_rawDesc = []byte{ + 0x0a, 0x1b, 0x66, 0x65, 0x64, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x66, 0x65, 0x64, + 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0e, 0x6f, + 0x72, 0x67, 0x2e, 0x66, 0x65, 0x64, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x1a, 0x20, 0x67, + 0x72, 0x70, 0x63, 0x2f, 0x66, 0x65, 0x64, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x66, + 0x65, 0x64, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, + 0x13, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x2f, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x3c, 0x0a, 0x0e, 0x49, 0x73, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x65, 0x78, 0x70, 0x72, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x65, 0x78, 0x70, 0x72, 0x12, 0x16, 0x0a, 0x06, 0x74, 0x61, + 0x72, 0x67, 0x65, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x74, 0x61, 0x72, 0x67, + 0x65, 0x74, 0x22, 0x7f, 0x0a, 0x0f, 0x49, 0x73, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x25, 0x0a, 0x06, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x08, 0x42, 0x0d, 0x82, 0x97, 0x22, 0x09, 0x12, 0x07, 0x6d, 0x61, 0x74, + 0x63, 0x68, 0x65, 0x64, 0x52, 0x06, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x3a, 0x45, 0x82, 0x97, + 0x22, 0x41, 0x0a, 0x3f, 0x0a, 0x07, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x65, 0x64, 0x5a, 0x34, 0x65, + 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2e, 0x72, 0x65, 0x67, 0x65, 0x78, 0x70, 0x2e, 0x63, 0x6f, + 0x6d, 0x70, 0x69, 0x6c, 0x65, 0x28, 0x24, 0x2e, 0x65, 0x78, 0x70, 0x72, 0x29, 0x2e, 0x6d, 0x61, + 0x74, 0x63, 0x68, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x28, 0x24, 0x2e, 0x74, 0x61, 0x72, 0x67, + 0x65, 0x74, 0x29, 0x32, 0x67, 0x0a, 0x11, 0x46, 0x65, 0x64, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x4c, 0x0a, 0x07, 0x49, 0x73, 0x4d, 0x61, + 0x74, 0x63, 0x68, 0x12, 0x1e, 0x2e, 0x6f, 0x72, 0x67, 0x2e, 0x66, 0x65, 0x64, 0x65, 0x72, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x49, 0x73, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x1a, 0x1f, 0x2e, 0x6f, 0x72, 0x67, 0x2e, 0x66, 0x65, 0x64, 0x65, 0x72, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x49, 0x73, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x1a, 0x04, 0x82, 0x97, 0x22, 0x00, 0x42, 0x9d, 0x01, 0x0a, + 0x12, 0x63, 0x6f, 0x6d, 0x2e, 0x6f, 0x72, 0x67, 0x2e, 0x66, 0x65, 0x64, 0x65, 0x72, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x42, 0x0f, 0x46, 0x65, 0x64, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x50, + 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x1d, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2f, + 0x66, 0x65, 0x64, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x3b, 0x66, 0x65, 0x64, 0x65, 0x72, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0xa2, 0x02, 0x03, 0x4f, 0x46, 0x58, 0xaa, 0x02, 0x0e, 0x4f, 0x72, + 0x67, 0x2e, 0x46, 0x65, 0x64, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0xca, 0x02, 0x0e, 0x4f, + 0x72, 0x67, 0x5c, 0x46, 0x65, 0x64, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0xe2, 0x02, 0x1a, + 0x4f, 0x72, 0x67, 0x5c, 0x46, 0x65, 0x64, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5c, 0x47, + 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x0f, 0x4f, 0x72, 0x67, + 0x3a, 0x3a, 0x46, 0x65, 0x64, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x62, 0x06, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x33, +} + +var ( + file_federation_federation_proto_rawDescOnce sync.Once + file_federation_federation_proto_rawDescData = file_federation_federation_proto_rawDesc +) + +func file_federation_federation_proto_rawDescGZIP() []byte { + file_federation_federation_proto_rawDescOnce.Do(func() { + file_federation_federation_proto_rawDescData = protoimpl.X.CompressGZIP(file_federation_federation_proto_rawDescData) + }) + return file_federation_federation_proto_rawDescData +} + +var file_federation_federation_proto_msgTypes = make([]protoimpl.MessageInfo, 2) +var file_federation_federation_proto_goTypes = []interface{}{ + (*IsMatchRequest)(nil), // 0: org.federation.IsMatchRequest + (*IsMatchResponse)(nil), // 1: org.federation.IsMatchResponse +} +var file_federation_federation_proto_depIdxs = []int32{ + 0, // 0: org.federation.FederationService.IsMatch:input_type -> org.federation.IsMatchRequest + 1, // 1: org.federation.FederationService.IsMatch:output_type -> org.federation.IsMatchResponse + 1, // [1:2] is the sub-list for method output_type + 0, // [0:1] is the sub-list for method input_type + 0, // [0:0] is the sub-list for extension type_name + 0, // [0:0] is the sub-list for extension extendee + 0, // [0:0] is the sub-list for field type_name +} + +func init() { file_federation_federation_proto_init() } +func file_federation_federation_proto_init() { + if File_federation_federation_proto != nil { + return + } + if !protoimpl.UnsafeEnabled { + file_federation_federation_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*IsMatchRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_federation_federation_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*IsMatchResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_federation_federation_proto_rawDesc, + NumEnums: 0, + NumMessages: 2, + NumExtensions: 0, + NumServices: 1, + }, + GoTypes: file_federation_federation_proto_goTypes, + DependencyIndexes: file_federation_federation_proto_depIdxs, + MessageInfos: file_federation_federation_proto_msgTypes, + }.Build() + File_federation_federation_proto = out.File + file_federation_federation_proto_rawDesc = nil + file_federation_federation_proto_goTypes = nil + file_federation_federation_proto_depIdxs = nil +} diff --git a/_examples/15_plugin/federation/federation_grpc.pb.go b/_examples/15_plugin/federation/federation_grpc.pb.go new file mode 100644 index 00000000..c9fdd949 --- /dev/null +++ b/_examples/15_plugin/federation/federation_grpc.pb.go @@ -0,0 +1,109 @@ +// Code generated by protoc-gen-go-grpc. DO NOT EDIT. +// versions: +// - protoc-gen-go-grpc v1.3.0 +// - protoc (unknown) +// source: federation/federation.proto + +package federation + +import ( + context "context" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" +) + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +// Requires gRPC-Go v1.32.0 or later. +const _ = grpc.SupportPackageIsVersion7 + +const ( + FederationService_IsMatch_FullMethodName = "/org.federation.FederationService/IsMatch" +) + +// FederationServiceClient is the client API for FederationService service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. +type FederationServiceClient interface { + IsMatch(ctx context.Context, in *IsMatchRequest, opts ...grpc.CallOption) (*IsMatchResponse, error) +} + +type federationServiceClient struct { + cc grpc.ClientConnInterface +} + +func NewFederationServiceClient(cc grpc.ClientConnInterface) FederationServiceClient { + return &federationServiceClient{cc} +} + +func (c *federationServiceClient) IsMatch(ctx context.Context, in *IsMatchRequest, opts ...grpc.CallOption) (*IsMatchResponse, error) { + out := new(IsMatchResponse) + err := c.cc.Invoke(ctx, FederationService_IsMatch_FullMethodName, in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// FederationServiceServer is the server API for FederationService service. +// All implementations must embed UnimplementedFederationServiceServer +// for forward compatibility +type FederationServiceServer interface { + IsMatch(context.Context, *IsMatchRequest) (*IsMatchResponse, error) + mustEmbedUnimplementedFederationServiceServer() +} + +// UnimplementedFederationServiceServer must be embedded to have forward compatible implementations. +type UnimplementedFederationServiceServer struct { +} + +func (UnimplementedFederationServiceServer) IsMatch(context.Context, *IsMatchRequest) (*IsMatchResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method IsMatch not implemented") +} +func (UnimplementedFederationServiceServer) mustEmbedUnimplementedFederationServiceServer() {} + +// UnsafeFederationServiceServer may be embedded to opt out of forward compatibility for this service. +// Use of this interface is not recommended, as added methods to FederationServiceServer will +// result in compilation errors. +type UnsafeFederationServiceServer interface { + mustEmbedUnimplementedFederationServiceServer() +} + +func RegisterFederationServiceServer(s grpc.ServiceRegistrar, srv FederationServiceServer) { + s.RegisterService(&FederationService_ServiceDesc, srv) +} + +func _FederationService_IsMatch_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(IsMatchRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(FederationServiceServer).IsMatch(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: FederationService_IsMatch_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(FederationServiceServer).IsMatch(ctx, req.(*IsMatchRequest)) + } + return interceptor(ctx, in, info, handler) +} + +// FederationService_ServiceDesc is the grpc.ServiceDesc for FederationService service. +// It's only intended for direct use with grpc.RegisterService, +// and not to be introspected or modified (even as a copy) +var FederationService_ServiceDesc = grpc.ServiceDesc{ + ServiceName: "org.federation.FederationService", + HandlerType: (*FederationServiceServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "IsMatch", + Handler: _FederationService_IsMatch_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "federation/federation.proto", +} diff --git a/_examples/15_plugin/federation/federation_grpc_federation.pb.go b/_examples/15_plugin/federation/federation_grpc_federation.pb.go new file mode 100644 index 00000000..225f5644 --- /dev/null +++ b/_examples/15_plugin/federation/federation_grpc_federation.pb.go @@ -0,0 +1,247 @@ +// Code generated by protoc-gen-grpc-federation. DO NOT EDIT! +package federation + +import ( + "context" + "fmt" + "io" + "log/slog" + "runtime/debug" + + "github.com/google/cel-go/cel" + celtypes "github.com/google/cel-go/common/types" + grpcfed "github.com/mercari/grpc-federation/grpc/federation" + grpcfedcel "github.com/mercari/grpc-federation/grpc/federation/cel" + "go.opentelemetry.io/otel" + "go.opentelemetry.io/otel/trace" +) + +// Org_Federation_IsMatchResponseArgument is argument for "org.federation.IsMatchResponse" message. +type Org_Federation_IsMatchResponseArgument[T any] struct { + Expr string + Matched bool + Target string + Client T +} + +// FederationServiceConfig configuration required to initialize the service that use GRPC Federation. +type FederationServiceConfig struct { + // CELPlugin If you use the plugin feature to extend the CEL API, + // you must write a plugin and output WebAssembly. + // In this field, configure to load wasm with the path to the WebAssembly file and the sha256 value. + CELPlugin *FederationServiceCELPluginConfig + // ErrorHandler Federation Service often needs to convert errors received from downstream services. + // If an error occurs during method execution in the Federation Service, this error handler is called and the returned error is treated as a final error. + ErrorHandler grpcfed.ErrorHandler + // Logger sets the logger used to output Debug/Info/Error information. + Logger *slog.Logger +} + +// FederationServiceClientFactory provides a factory that creates the gRPC Client needed to invoke methods of the gRPC Service on which the Federation Service depends. +type FederationServiceClientFactory interface { +} + +// FederationServiceClientConfig information set in `dependencies` of the `grpc.federation.service` option. +// Hints for creating a gRPC Client. +type FederationServiceClientConfig struct { + // Service returns the name of the service on Protocol Buffers. + Service string + // Name is the value set for `name` in `dependencies` of the `grpc.federation.service` option. + // It must be unique among the services on which the Federation Service depends. + Name string +} + +// FederationServiceDependentClientSet has a gRPC client for all services on which the federation service depends. +// This is provided as an argument when implementing the custom resolver. +type FederationServiceDependentClientSet struct { +} + +// FederationServiceResolver provides an interface to directly implement message resolver and field resolver not defined in Protocol Buffers. +type FederationServiceResolver interface { +} + +type FederationServiceCELPluginWasmConfig = grpcfedcel.WasmConfig + +type FederationServiceCELPluginConfig struct { + Regexp FederationServiceCELPluginWasmConfig +} + +// FederationServiceUnimplementedResolver a structure implemented to satisfy the Resolver interface. +// An Unimplemented error is always returned. +// This is intended for use when there are many Resolver interfaces that do not need to be implemented, +// by embedding them in a resolver structure that you have created. +type FederationServiceUnimplementedResolver struct{} + +// FederationService represents Federation Service. +type FederationService struct { + *UnimplementedFederationServiceServer + cfg FederationServiceConfig + logger *slog.Logger + errorHandler grpcfed.ErrorHandler + env *cel.Env + tracer trace.Tracer + client *FederationServiceDependentClientSet +} + +// NewFederationService creates FederationService instance by FederationServiceConfig. +func NewFederationService(cfg FederationServiceConfig) (*FederationService, error) { + if cfg.CELPlugin == nil { + return nil, fmt.Errorf("CELPlugin field in FederationServiceConfig is not set. this field must be set") + } + logger := cfg.Logger + if logger == nil { + logger = slog.New(slog.NewJSONHandler(io.Discard, nil)) + } + errorHandler := cfg.ErrorHandler + if errorHandler == nil { + errorHandler = func(ctx context.Context, methodName string, err error) error { return err } + } + celHelper := grpcfed.NewCELTypeHelper(map[string]map[string]*celtypes.FieldType{ + "grpc.federation.private.IsMatchResponseArgument": { + "expr": grpcfed.NewCELFieldType(celtypes.StringType, "Expr"), + "target": grpcfed.NewCELFieldType(celtypes.StringType, "Target"), + }, + }) + envOpts := []cel.EnvOption{ + cel.StdLib(), + cel.Lib(grpcfedcel.NewLibrary()), + cel.CrossTypeNumericComparisons(true), + cel.CustomTypeAdapter(celHelper.TypeAdapter()), + cel.CustomTypeProvider(celHelper.TypeProvider()), + } + { + plugin, err := grpcfedcel.NewCELPlugin(context.Background(), grpcfedcel.CELPluginConfig{ + Name: "regexp", + Wasm: cfg.CELPlugin.Regexp, + Functions: []*grpcfedcel.CELFunction{ + { + Name: "example.regexp.compile", + ID: "example_regexp_compile_string_example_regexp_Regexp", + Args: []*cel.Type{ + celtypes.StringType, + }, + Return: celtypes.NewObjectType("example.regexp.Regexp"), + IsMethod: false, + }, + { + Name: "matchString", + ID: "example_regexp_Regexp_matchString_example_regexp_Regexp_string_bool", + Args: []*cel.Type{ + celtypes.NewObjectType("example.regexp.Regexp"), + celtypes.StringType, + }, + Return: celtypes.BoolType, + IsMethod: true, + }, + }, + }) + if err != nil { + return nil, err + } + envOpts = append(envOpts, cel.Lib(plugin)) + } + env, err := cel.NewCustomEnv(envOpts...) + if err != nil { + return nil, err + } + return &FederationService{ + cfg: cfg, + logger: logger, + errorHandler: errorHandler, + env: env, + tracer: otel.Tracer("org.federation.FederationService"), + client: &FederationServiceDependentClientSet{}, + }, nil +} + +// IsMatch implements "org.federation.FederationService/IsMatch" method. +func (s *FederationService) IsMatch(ctx context.Context, req *IsMatchRequest) (res *IsMatchResponse, e error) { + ctx, span := s.tracer.Start(ctx, "org.federation.FederationService/IsMatch") + defer span.End() + + ctx = grpcfed.WithLogger(ctx, s.logger) + defer func() { + if r := recover(); r != nil { + e = grpcfed.RecoverError(r, debug.Stack()) + grpcfed.OutputErrorLog(ctx, s.logger, e) + } + }() + res, err := s.resolve_Org_Federation_IsMatchResponse(ctx, &Org_Federation_IsMatchResponseArgument[*FederationServiceDependentClientSet]{ + Client: s.client, + Expr: req.Expr, + Target: req.Target, + }) + if err != nil { + grpcfed.RecordErrorToSpan(ctx, err) + grpcfed.OutputErrorLog(ctx, s.logger, err) + return nil, err + } + return res, nil +} + +// resolve_Org_Federation_IsMatchResponse resolve "org.federation.IsMatchResponse" message. +func (s *FederationService) resolve_Org_Federation_IsMatchResponse(ctx context.Context, req *Org_Federation_IsMatchResponseArgument[*FederationServiceDependentClientSet]) (*IsMatchResponse, error) { + ctx, span := s.tracer.Start(ctx, "org.federation.IsMatchResponse") + defer span.End() + + s.logger.DebugContext(ctx, "resolve org.federation.IsMatchResponse", slog.Any("message_args", s.logvalue_Org_Federation_IsMatchResponseArgument(req))) + type localValueType struct { + *grpcfed.LocalValue + vars struct { + matched bool + } + } + value := &localValueType{LocalValue: grpcfed.NewLocalValue(s.env, "grpc.federation.private.IsMatchResponseArgument", req)} + + // This section's codes are generated by the following proto definition. + /* + def { + name: "matched" + by: "example.regexp.compile($.expr).matchString($.target)" + } + */ + if err := grpcfed.EvalDef(ctx, value, grpcfed.Def[bool, *localValueType]{ + Name: "matched", + Type: celtypes.BoolType, + Setter: func(value *localValueType, v bool) { value.vars.matched = v }, + By: "example.regexp.compile($.expr).matchString($.target)", + }); err != nil { + grpcfed.RecordErrorToSpan(ctx, err) + return nil, err + } + + // assign named parameters to message arguments to pass to the custom resolver. + req.Matched = value.vars.matched + + // create a message value to be returned. + ret := &IsMatchResponse{} + + // field binding section. + // (grpc.federation.field).by = "matched" + if err := grpcfed.SetCELValue(ctx, value, "matched", func(v bool) { ret.Result = v }); err != nil { + grpcfed.RecordErrorToSpan(ctx, err) + return nil, err + } + + s.logger.DebugContext(ctx, "resolved org.federation.IsMatchResponse", slog.Any("org.federation.IsMatchResponse", s.logvalue_Org_Federation_IsMatchResponse(ret))) + return ret, nil +} + +func (s *FederationService) logvalue_Org_Federation_IsMatchResponse(v *IsMatchResponse) slog.Value { + if v == nil { + return slog.GroupValue() + } + return slog.GroupValue( + slog.Bool("result", v.GetResult()), + ) +} + +func (s *FederationService) logvalue_Org_Federation_IsMatchResponseArgument(v *Org_Federation_IsMatchResponseArgument[*FederationServiceDependentClientSet]) slog.Value { + if v == nil { + return slog.GroupValue() + } + return slog.GroupValue( + slog.String("expr", v.Expr), + slog.String("target", v.Target), + ) +} diff --git a/_examples/15_plugin/go.mod b/_examples/15_plugin/go.mod new file mode 100644 index 00000000..bdd15242 --- /dev/null +++ b/_examples/15_plugin/go.mod @@ -0,0 +1,39 @@ +module example + +go 1.21 + +replace github.com/mercari/grpc-federation => ../../ + +require ( + github.com/google/cel-go v0.18.2 + github.com/google/go-cmp v0.6.0 + github.com/mercari/grpc-federation v0.0.0-00010101000000-000000000000 + github.com/tetratelabs/wazero v1.6.0 + go.opentelemetry.io/otel v1.21.0 + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.21.0 + go.opentelemetry.io/otel/sdk v1.21.0 + go.opentelemetry.io/otel/trace v1.21.0 + google.golang.org/genproto/googleapis/rpc v0.0.0-20231211222908-989df2bf70f3 + google.golang.org/grpc v1.60.1 + google.golang.org/protobuf v1.31.1-0.20231027082548-f4a6c1f6e5c1 +) + +require ( + github.com/antlr4-go/antlr/v4 v4.13.0 // indirect + github.com/cenkalti/backoff/v4 v4.2.1 // indirect + github.com/go-logr/logr v1.3.0 // indirect + github.com/go-logr/stdr v1.2.2 // indirect + github.com/golang/protobuf v1.5.3 // indirect + github.com/google/uuid v1.5.0 // indirect + github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0 // indirect + github.com/stoewer/go-strcase v1.2.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.21.0 // indirect + go.opentelemetry.io/otel/metric v1.21.0 // indirect + go.opentelemetry.io/proto/otlp v1.0.0 // indirect + golang.org/x/exp v0.0.0-20230515195305-f3d0a9c9a5cc // indirect + golang.org/x/net v0.17.0 // indirect + golang.org/x/sync v0.5.0 // indirect + golang.org/x/sys v0.15.0 // indirect + golang.org/x/text v0.14.0 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20231212172506-995d672761c0 // indirect +) diff --git a/_examples/15_plugin/go.sum b/_examples/15_plugin/go.sum new file mode 100644 index 00000000..6af19162 --- /dev/null +++ b/_examples/15_plugin/go.sum @@ -0,0 +1,79 @@ +github.com/antlr4-go/antlr/v4 v4.13.0 h1:lxCg3LAv+EUK6t1i0y1V6/SLeUi0eKEKdhQAlS8TVTI= +github.com/antlr4-go/antlr/v4 v4.13.0/go.mod h1:pfChB/xh/Unjila75QW7+VU4TSnWnnk9UTnmpPaOR2g= +github.com/cenkalti/backoff/v4 v4.2.1 h1:y4OZtCnogmCPw98Zjyt5a6+QwPLGkiQsYW5oUqylYbM= +github.com/cenkalti/backoff/v4 v4.2.1/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/logr v1.3.0 h1:2y3SDp0ZXuc6/cjLSZ+Q3ir+QB9T/iG5yYRXqsagWSY= +github.com/go-logr/logr v1.3.0/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= +github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= +github.com/golang/glog v1.1.2 h1:DVjP2PbBOzHyzA+dn3WhHIq4NdVu3Q+pvivFICf/7fo= +github.com/golang/glog v1.1.2/go.mod h1:zR+okUeTbrL6EL3xHUDxZuEtGv04p5shwip1+mL/rLQ= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= +github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/google/cel-go v0.18.2 h1:L0B6sNBSVmt0OyECi8v6VOS74KOc9W/tLiWKfZABvf4= +github.com/google/cel-go v0.18.2/go.mod h1:kWcIzTsPX0zmQ+H3TirHstLLf9ep5QTsZBN9u4dOYLg= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/uuid v1.5.0 h1:1p67kYwdtXjb0gL0BPiP1Av9wiZPo5A8z2cWkTZ+eyU= +github.com/google/uuid v1.5.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0 h1:YBftPWNWd4WwGqtY2yeZL2ef8rHAxPBD8KFhJpmcqms= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0/go.mod h1:YN5jB8ie0yfIUg6VvR9Kz84aCaG7AsGZnLjhHbUqwPg= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/stoewer/go-strcase v1.2.0 h1:Z2iHWqGXH00XYgqDmNgQbIBxf3wrNq0F3feEy0ainaU= +github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/tetratelabs/wazero v1.6.0 h1:z0H1iikCdP8t+q341xqepY4EWvHEw8Es7tlqiVzlP3g= +github.com/tetratelabs/wazero v1.6.0/go.mod h1:0U0G41+ochRKoPKCJlh0jMg1CHkyfK8kDqiirMmKY8A= +go.opentelemetry.io/otel v1.21.0 h1:hzLeKBZEL7Okw2mGzZ0cc4k/A7Fta0uoPgaJCr8fsFc= +go.opentelemetry.io/otel v1.21.0/go.mod h1:QZzNPQPm1zLX4gZK4cMi+71eaorMSGT3A4znnUvNNEo= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.21.0 h1:cl5P5/GIfFh4t6xyruOgJP5QiA1pw4fYYdv6nc6CBWw= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.21.0/go.mod h1:zgBdWWAu7oEEMC06MMKc5NLbA/1YDXV1sMpSqEeLQLg= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.21.0 h1:tIqheXEFWAZ7O8A7m+J0aPTmpJN3YQ7qetUAdkkkKpk= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.21.0/go.mod h1:nUeKExfxAQVbiVFn32YXpXZZHZ61Cc3s3Rn1pDBGAb0= +go.opentelemetry.io/otel/metric v1.21.0 h1:tlYWfeo+Bocx5kLEloTjbcDwBuELRrIFxwdQ36PlJu4= +go.opentelemetry.io/otel/metric v1.21.0/go.mod h1:o1p3CA8nNHW8j5yuQLdc1eeqEaPfzug24uvsyIEJRWM= +go.opentelemetry.io/otel/sdk v1.21.0 h1:FTt8qirL1EysG6sTQRZ5TokkU8d0ugCj8htOgThZXQ8= +go.opentelemetry.io/otel/sdk v1.21.0/go.mod h1:Nna6Yv7PWTdgJHVRD9hIYywQBRx7pbox6nwBnZIxl/E= +go.opentelemetry.io/otel/trace v1.21.0 h1:WD9i5gzvoUPuXIXH24ZNBudiarZDKuekPqi/E8fpfLc= +go.opentelemetry.io/otel/trace v1.21.0/go.mod h1:LGbsEB0f9LGjN+OZaQQ26sohbOmiMR+BaslueVtS/qQ= +go.opentelemetry.io/proto/otlp v1.0.0 h1:T0TX0tmXU8a3CbNXzEKGeU5mIVOdf0oykP+u2lIVU/I= +go.opentelemetry.io/proto/otlp v1.0.0/go.mod h1:Sy6pihPLfYHkr3NkUbEhGHFhINUSI/v80hjKIs5JXpM= +go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= +go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= +golang.org/x/exp v0.0.0-20230515195305-f3d0a9c9a5cc h1:mCRnTeVUjcrhlRmO0VK8a6k6Rrf6TF9htwo2pJVSjIU= +golang.org/x/exp v0.0.0-20230515195305-f3d0a9c9a5cc/go.mod h1:V1LtkGg67GoY2N1AnLN78QLrzxkLyJw7RJb1gzOOz9w= +golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM= +golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= +golang.org/x/sync v0.5.0 h1:60k92dhOjHxJkrqnwsfl8KuaHbn/5dl0lUPUklKo3qE= +golang.org/x/sync v0.5.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc= +golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= +golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/genproto v0.0.0-20231211222908-989df2bf70f3 h1:1hfbdAfFbkmpg41000wDVqr7jUpK/Yo+LPnIxxGzmkg= +google.golang.org/genproto v0.0.0-20231211222908-989df2bf70f3/go.mod h1:5RBcpGRxr25RbDzY5w+dmaqpSEvl8Gwl1x2CICf60ic= +google.golang.org/genproto/googleapis/api v0.0.0-20231212172506-995d672761c0 h1:s1w3X6gQxwrLEpxnLd/qXTVLgQE2yXwaOaoa6IlY/+o= +google.golang.org/genproto/googleapis/api v0.0.0-20231212172506-995d672761c0/go.mod h1:CAny0tYF+0/9rmDB9fahA9YLzX3+AEVl1qXbv5hhj6c= +google.golang.org/genproto/googleapis/rpc v0.0.0-20231211222908-989df2bf70f3 h1:kzJAXnzZoFbe5bhZd4zjUuHos/I31yH4thfMb/13oVY= +google.golang.org/genproto/googleapis/rpc v0.0.0-20231211222908-989df2bf70f3/go.mod h1:eJVxU6o+4G1PSczBr85xmyvSNYAKvAYgkub40YGomFM= +google.golang.org/grpc v1.60.1 h1:26+wFr+cNqSGFcOXcabYC0lUVJVRa2Sb2ortSK7VrEU= +google.golang.org/grpc v1.60.1/go.mod h1:OlCHIeLYqSSsLi6i49B5QGdzaMZK9+M7LXN2FKz4eGM= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.31.1-0.20231027082548-f4a6c1f6e5c1 h1:fk72uXZyuZiTtW5tgd63jyVK6582lF61nRC/kGv6vCA= +google.golang.org/protobuf v1.31.1-0.20231027082548-f4a6c1f6e5c1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/_examples/15_plugin/main_test.go b/_examples/15_plugin/main_test.go new file mode 100644 index 00000000..2b62ff3e --- /dev/null +++ b/_examples/15_plugin/main_test.go @@ -0,0 +1,125 @@ +package main_test + +import ( + "context" + "log/slog" + "net" + "os" + "testing" + + "github.com/google/go-cmp/cmp" + "github.com/google/go-cmp/cmp/cmpopts" + "go.opentelemetry.io/otel" + "go.opentelemetry.io/otel/attribute" + "go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc" + "go.opentelemetry.io/otel/propagation" + "go.opentelemetry.io/otel/sdk/resource" + sdktrace "go.opentelemetry.io/otel/sdk/trace" + semconv "go.opentelemetry.io/otel/semconv/v1.4.0" + "google.golang.org/grpc" + "google.golang.org/grpc/credentials/insecure" + "google.golang.org/grpc/test/bufconn" + + "example/federation" + "example/post" +) + +const bufSize = 1024 + +var ( + listener *bufconn.Listener + postClient post.PostServiceClient +) + +func dialer(ctx context.Context, address string) (net.Conn, error) { + return listener.Dial() +} + +func TestFederation(t *testing.T) { + ctx := context.Background() + listener = bufconn.Listen(bufSize) + + if os.Getenv("ENABLE_JAEGER") != "" { + exporter, err := otlptracegrpc.New(ctx, otlptracegrpc.WithInsecure()) + if err != nil { + t.Fatal(err) + } + tp := sdktrace.NewTracerProvider( + sdktrace.WithBatcher(exporter), + sdktrace.WithResource( + resource.NewWithAttributes( + semconv.SchemaURL, + semconv.ServiceNameKey.String("example15/condition"), + semconv.ServiceVersionKey.String("1.0.0"), + attribute.String("environment", "dev"), + ), + ), + sdktrace.WithSampler(sdktrace.AlwaysSample()), + ) + defer tp.Shutdown(ctx) + otel.SetTextMapPropagator(propagation.TraceContext{}) + otel.SetTracerProvider(tp) + } + + conn, err := grpc.DialContext( + ctx, "", + grpc.WithContextDialer(dialer), + grpc.WithTransportCredentials(insecure.NewCredentials()), + ) + if err != nil { + t.Fatal(err) + } + defer conn.Close() + + grpcServer := grpc.NewServer() + logger := slog.New(slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{ + Level: slog.LevelDebug, + })) + federationServer, err := federation.NewFederationService(federation.FederationServiceConfig{ + CELPlugin: &federation.FederationServiceCELPluginConfig{ + Regexp: federation.FederationServiceCELPluginWasmConfig{ + Path: "regexp.wasm", + Sha256: "7d70b1d3cb44940f3ea7534fb49b4c5c4e2f9c1ccef5dc3c38085417a09d9e9b", + }, + }, + Logger: logger, + }) + if err != nil { + t.Fatal(err) + } + federation.RegisterFederationServiceServer(grpcServer, federationServer) + + go func() { + if err := grpcServer.Serve(listener); err != nil { + t.Fatal(err) + } + }() + + client := federation.NewFederationServiceClient(conn) + t.Run("success", func(t *testing.T) { + res, err := client.IsMatch(ctx, &federation.IsMatchRequest{ + Expr: "hello world", + Target: "hello world world", + }) + if err != nil { + t.Fatal(err) + } + if diff := cmp.Diff(res, &federation.IsMatchResponse{ + Result: true, + }, cmpopts.IgnoreUnexported( + federation.IsMatchResponse{}, + )); diff != "" { + t.Errorf("(-got, +want)\n%s", diff) + } + }) + t.Run("failure", func(t *testing.T) { + _, err := client.IsMatch(ctx, &federation.IsMatchRequest{ + Expr: "[]", + Target: "hello world world", + }) + if err == nil { + t.Fatal("expected error") + } + t.Logf("expected error is %s", err) + }) +} diff --git a/_examples/15_plugin/plugin/plugin.pb.go b/_examples/15_plugin/plugin/plugin.pb.go new file mode 100644 index 00000000..4d76d701 --- /dev/null +++ b/_examples/15_plugin/plugin/plugin.pb.go @@ -0,0 +1,182 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.31.0 +// protoc (unknown) +// source: plugin/plugin.proto + +package pluginpb + +import ( + _ "github.com/mercari/grpc-federation/grpc/federation" + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +type Regexp struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Ptr uint64 `protobuf:"varint,1,opt,name=ptr,proto3" json:"ptr,omitempty"` // store raw pointer value. +} + +func (x *Regexp) Reset() { + *x = Regexp{} + if protoimpl.UnsafeEnabled { + mi := &file_plugin_plugin_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Regexp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Regexp) ProtoMessage() {} + +func (x *Regexp) ProtoReflect() protoreflect.Message { + mi := &file_plugin_plugin_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Regexp.ProtoReflect.Descriptor instead. +func (*Regexp) Descriptor() ([]byte, []int) { + return file_plugin_plugin_proto_rawDescGZIP(), []int{0} +} + +func (x *Regexp) GetPtr() uint64 { + if x != nil { + return x.Ptr + } + return 0 +} + +var File_plugin_plugin_proto protoreflect.FileDescriptor + +var file_plugin_plugin_proto_rawDesc = []byte{ + 0x0a, 0x13, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x2f, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2e, 0x72, + 0x65, 0x67, 0x65, 0x78, 0x70, 0x1a, 0x1c, 0x67, 0x72, 0x70, 0x63, 0x2f, 0x66, 0x65, 0x64, 0x65, + 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x22, 0x1a, 0x0a, 0x06, 0x52, 0x65, 0x67, 0x65, 0x78, 0x70, 0x12, 0x10, 0x0a, + 0x03, 0x70, 0x74, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x03, 0x70, 0x74, 0x72, 0x42, + 0xe6, 0x04, 0x82, 0x97, 0x22, 0xce, 0x03, 0x0a, 0xcb, 0x03, 0x0a, 0x06, 0x72, 0x65, 0x67, 0x65, + 0x78, 0x70, 0x1a, 0xea, 0x01, 0x0a, 0x06, 0x52, 0x65, 0x67, 0x65, 0x78, 0x70, 0x12, 0x3d, 0x52, + 0x65, 0x67, 0x65, 0x78, 0x70, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x72, 0x65, 0x70, + 0x72, 0x65, 0x73, 0x65, 0x6e, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x6f, 0x66, 0x20, 0x61, + 0x20, 0x63, 0x6f, 0x6d, 0x70, 0x69, 0x6c, 0x65, 0x64, 0x20, 0x72, 0x65, 0x67, 0x75, 0x6c, 0x61, + 0x72, 0x20, 0x65, 0x78, 0x70, 0x72, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x1a, 0xa0, 0x01, 0x0a, + 0x0b, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x12, 0x55, 0x6d, 0x61, + 0x74, 0x63, 0x68, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x20, 0x72, 0x65, 0x70, 0x6f, 0x72, 0x74, + 0x73, 0x20, 0x77, 0x68, 0x65, 0x74, 0x68, 0x65, 0x72, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x74, + 0x72, 0x69, 0x6e, 0x67, 0x20, 0x73, 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x73, 0x20, + 0x61, 0x6e, 0x79, 0x20, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x72, 0x65, 0x67, 0x75, 0x6c, 0x61, 0x72, 0x20, 0x65, 0x78, 0x70, 0x72, 0x65, 0x73, 0x73, + 0x69, 0x6f, 0x6e, 0x1a, 0x18, 0x0a, 0x01, 0x73, 0x12, 0x0b, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, + 0x20, 0x74, 0x65, 0x78, 0x74, 0x1a, 0x06, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x22, 0x20, 0x0a, + 0x04, 0x62, 0x6f, 0x6f, 0x6c, 0x12, 0x18, 0x69, 0x66, 0x20, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x65, + 0x64, 0x2c, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x73, 0x20, 0x74, 0x72, 0x75, 0x65, 0x22, + 0xaf, 0x01, 0x0a, 0x07, 0x63, 0x6f, 0x6d, 0x70, 0x69, 0x6c, 0x65, 0x12, 0x6f, 0x63, 0x6f, 0x6d, + 0x70, 0x69, 0x6c, 0x65, 0x20, 0x70, 0x61, 0x72, 0x73, 0x65, 0x73, 0x20, 0x61, 0x20, 0x72, 0x65, + 0x67, 0x75, 0x6c, 0x61, 0x72, 0x20, 0x65, 0x78, 0x70, 0x72, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, + 0x20, 0x61, 0x6e, 0x64, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x73, 0x2c, 0x20, 0x69, 0x66, + 0x20, 0x73, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x66, 0x75, 0x6c, 0x2c, 0x20, 0x61, 0x20, 0x52, + 0x65, 0x67, 0x65, 0x78, 0x70, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x63, 0x61, 0x6e, 0x20, 0x62, + 0x65, 0x20, 0x75, 0x73, 0x65, 0x64, 0x20, 0x74, 0x6f, 0x20, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x20, + 0x61, 0x67, 0x61, 0x69, 0x6e, 0x73, 0x74, 0x20, 0x74, 0x65, 0x78, 0x74, 0x1a, 0x29, 0x0a, 0x04, + 0x65, 0x78, 0x70, 0x72, 0x12, 0x19, 0x61, 0x20, 0x72, 0x65, 0x67, 0x75, 0x6c, 0x61, 0x72, 0x20, + 0x65, 0x78, 0x70, 0x72, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x20, 0x74, 0x65, 0x78, 0x74, 0x1a, + 0x06, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x22, 0x08, 0x0a, 0x06, 0x52, 0x65, 0x67, 0x65, 0x78, + 0x70, 0x2a, 0x22, 0x0a, 0x03, 0x76, 0x61, 0x6c, 0x12, 0x13, 0x61, 0x20, 0x76, 0x61, 0x72, 0x69, + 0x61, 0x62, 0x6c, 0x65, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x74, 0x65, 0x73, 0x74, 0x1a, 0x06, 0x73, + 0x74, 0x72, 0x69, 0x6e, 0x67, 0x0a, 0x12, 0x63, 0x6f, 0x6d, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, + 0x6c, 0x65, 0x2e, 0x72, 0x65, 0x67, 0x65, 0x78, 0x70, 0x42, 0x0b, 0x50, 0x6c, 0x75, 0x67, 0x69, + 0x6e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x17, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, + 0x65, 0x2f, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x3b, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x70, + 0x62, 0xa2, 0x02, 0x03, 0x45, 0x52, 0x58, 0xaa, 0x02, 0x0e, 0x45, 0x78, 0x61, 0x6d, 0x70, 0x6c, + 0x65, 0x2e, 0x52, 0x65, 0x67, 0x65, 0x78, 0x70, 0xca, 0x02, 0x0e, 0x45, 0x78, 0x61, 0x6d, 0x70, + 0x6c, 0x65, 0x5c, 0x52, 0x65, 0x67, 0x65, 0x78, 0x70, 0xe2, 0x02, 0x1a, 0x45, 0x78, 0x61, 0x6d, + 0x70, 0x6c, 0x65, 0x5c, 0x52, 0x65, 0x67, 0x65, 0x78, 0x70, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, + 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x0f, 0x45, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, + 0x3a, 0x3a, 0x52, 0x65, 0x67, 0x65, 0x78, 0x70, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, +} + +var ( + file_plugin_plugin_proto_rawDescOnce sync.Once + file_plugin_plugin_proto_rawDescData = file_plugin_plugin_proto_rawDesc +) + +func file_plugin_plugin_proto_rawDescGZIP() []byte { + file_plugin_plugin_proto_rawDescOnce.Do(func() { + file_plugin_plugin_proto_rawDescData = protoimpl.X.CompressGZIP(file_plugin_plugin_proto_rawDescData) + }) + return file_plugin_plugin_proto_rawDescData +} + +var file_plugin_plugin_proto_msgTypes = make([]protoimpl.MessageInfo, 1) +var file_plugin_plugin_proto_goTypes = []interface{}{ + (*Regexp)(nil), // 0: example.regexp.Regexp +} +var file_plugin_plugin_proto_depIdxs = []int32{ + 0, // [0:0] is the sub-list for method output_type + 0, // [0:0] is the sub-list for method input_type + 0, // [0:0] is the sub-list for extension type_name + 0, // [0:0] is the sub-list for extension extendee + 0, // [0:0] is the sub-list for field type_name +} + +func init() { file_plugin_plugin_proto_init() } +func file_plugin_plugin_proto_init() { + if File_plugin_plugin_proto != nil { + return + } + if !protoimpl.UnsafeEnabled { + file_plugin_plugin_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Regexp); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_plugin_plugin_proto_rawDesc, + NumEnums: 0, + NumMessages: 1, + NumExtensions: 0, + NumServices: 0, + }, + GoTypes: file_plugin_plugin_proto_goTypes, + DependencyIndexes: file_plugin_plugin_proto_depIdxs, + MessageInfos: file_plugin_plugin_proto_msgTypes, + }.Build() + File_plugin_plugin_proto = out.File + file_plugin_plugin_proto_rawDesc = nil + file_plugin_plugin_proto_goTypes = nil + file_plugin_plugin_proto_depIdxs = nil +} diff --git a/_examples/15_plugin/plugin/plugin_grpc_federation.pb.go b/_examples/15_plugin/plugin/plugin_grpc_federation.pb.go new file mode 100644 index 00000000..d373bdc1 --- /dev/null +++ b/_examples/15_plugin/plugin/plugin_grpc_federation.pb.go @@ -0,0 +1,51 @@ +// Code generated by protoc-gen-grpc-federation. DO NOT EDIT! +package pluginpb + +import ( + "sync" + + grpcfed "github.com/mercari/grpc-federation/grpc/federation" +) + +type RegexpPlugin interface { + Example_Regexp_Compile(string) (*Regexp, error) + Example_Regexp_Regexp_MatchString(*Regexp, string) (bool, error) +} + +var ( + reg_RegexpPlugin RegexpPlugin + mu_RegexpPlugin sync.RWMutex +) + +func RegisterRegexpPlugin(plug RegexpPlugin) { + mu_RegexpPlugin.Lock() + defer mu_RegexpPlugin.Unlock() + reg_RegexpPlugin = plug +} + +//export example_regexp_compile_string_example_regexp_Regexp +func example_regexp_compile_string_example_regexp_Regexp(arg0 uint32, arg1 uint32) grpcfed.ReturnValue { + converted_arg0 := grpcfed.ToString(arg0, arg1) + + mu_RegexpPlugin.RLock() + ret, err := reg_RegexpPlugin.Example_Regexp_Compile(converted_arg0) + mu_RegexpPlugin.RUnlock() + if err != nil { + return grpcfed.ErrorToReturnValue(err) + } + return grpcfed.MessageToReturnValue(ret) +} + +//export example_regexp_Regexp_matchString_example_regexp_Regexp_string_bool +func example_regexp_Regexp_matchString_example_regexp_Regexp_string_bool(arg0 uint32, arg1 uint32, arg2 uint32) grpcfed.ReturnValue { + converted_arg0 := grpcfed.ToMessage[Regexp](arg0) + converted_arg1 := grpcfed.ToString(arg1, arg2) + + mu_RegexpPlugin.RLock() + ret, err := reg_RegexpPlugin.Example_Regexp_Regexp_MatchString(converted_arg0, converted_arg1) + mu_RegexpPlugin.RUnlock() + if err != nil { + return grpcfed.ErrorToReturnValue(err) + } + return grpcfed.BoolToReturnValue(ret) +} diff --git a/_examples/15_plugin/proto/buf.lock b/_examples/15_plugin/proto/buf.lock new file mode 100644 index 00000000..6c4355d4 --- /dev/null +++ b/_examples/15_plugin/proto/buf.lock @@ -0,0 +1,8 @@ +# Generated by buf. DO NOT EDIT. +version: v1 +deps: + - remote: buf.build + owner: googleapis + repository: googleapis + commit: 28151c0d0a1641bf938a7672c500e01d + digest: shake256:49215edf8ef57f7863004539deff8834cfb2195113f0b890dd1f67815d9353e28e668019165b9d872395871eeafcbab3ccfdb2b5f11734d3cca95be9e8d139de diff --git a/_examples/15_plugin/proto/buf.yaml b/_examples/15_plugin/proto/buf.yaml new file mode 100644 index 00000000..1a519456 --- /dev/null +++ b/_examples/15_plugin/proto/buf.yaml @@ -0,0 +1,7 @@ +version: v1 +breaking: + use: + - FILE +lint: + use: + - DEFAULT diff --git a/_examples/15_plugin/proto/federation/federation.proto b/_examples/15_plugin/proto/federation/federation.proto new file mode 100644 index 00000000..17b4d41a --- /dev/null +++ b/_examples/15_plugin/proto/federation/federation.proto @@ -0,0 +1,28 @@ +syntax = "proto3"; + +package org.federation; + +import "grpc/federation/federation.proto"; +import "plugin/plugin.proto"; + +option go_package = "example/federation;federation"; + +service FederationService { + option (grpc.federation.service) = {}; + rpc IsMatch(IsMatchRequest) returns (IsMatchResponse) {}; +} + +message IsMatchRequest { + string expr = 1; + string target = 2; +} + +message IsMatchResponse { + option (grpc.federation.message) = { + def { + name: "matched" + by: "example.regexp.compile($.expr).matchString($.target)" + } + }; + bool result = 1 [(grpc.federation.field).by = "matched"]; +} diff --git a/_examples/15_plugin/proto/plugin/plugin.proto b/_examples/15_plugin/proto/plugin/plugin.proto new file mode 100644 index 00000000..6fd234c9 --- /dev/null +++ b/_examples/15_plugin/proto/plugin/plugin.proto @@ -0,0 +1,55 @@ +syntax = "proto3"; + +package example.regexp; + +import "grpc/federation/plugin.proto"; + +option go_package = "example/plugin;pluginpb"; + +message Regexp { + uint64 ptr = 1; // store raw pointer value. +} + +option (grpc.federation.plugin).export = { + name: "regexp" + types: [ + { + name: "Regexp" + desc: "Regexp is the representation of a compiled regular expression" + methods: [ + { + name: "matchString" + desc: "matchString reports whether the string s contains any match of the regular expression" + args { + name: "s" + type: "string" + desc: "target text" + } + return { + type: "bool" + desc: "if matched, returns true" + } + } + ] + } + ] + functions: [ + { + name: "compile" + desc: "compile parses a regular expression and returns, if successful, a Regexp that can be used to match against text" + args { + name: "expr" + type: "string" + desc: "a regular expression text" + } + return { type: "Regexp" } + } + ] + variables: [ + { + name: "val" + desc: "a variable for test" + type: "string" + } + ] +}; diff --git a/_examples/15_plugin/proto_deps b/_examples/15_plugin/proto_deps new file mode 120000 index 00000000..b943f939 --- /dev/null +++ b/_examples/15_plugin/proto_deps @@ -0,0 +1 @@ +../../proto \ No newline at end of file diff --git a/_examples/15_plugin/regexp.wasm b/_examples/15_plugin/regexp.wasm new file mode 100755 index 00000000..4a87b673 Binary files /dev/null and b/_examples/15_plugin/regexp.wasm differ diff --git a/generator/code_generator.go b/generator/code_generator.go index b0aa6569..892e1dfa 100644 --- a/generator/code_generator.go +++ b/generator/code_generator.go @@ -53,6 +53,244 @@ func (f *File) Services() []*Service { return ret } +type CELPlugin struct { + file *resolver.File + *resolver.CELPlugin +} + +func (p *CELPlugin) FieldName() string { + return util.ToPublicGoVariable(p.Name) +} + +func (p *CELPlugin) PluginName() string { + return fmt.Sprintf("%sPlugin", util.ToPublicGoVariable(p.Name)) +} + +func (p *CELPlugin) Functions() []*CELFunction { + ret := make([]*CELFunction, 0, len(p.CELPlugin.Functions)) + for _, fn := range p.CELPlugin.Functions { + ret = append(ret, &CELFunction{ + file: p.file, + CELFunction: fn, + }) + } + return ret +} + +type CELFunction struct { + file *resolver.File + *resolver.CELFunction +} + +func (f *CELFunction) Name() string { + if f.Receiver != nil { + return protoFQDNToPublicGoName(fmt.Sprintf("%s.%s", f.Receiver.FQDN(), f.CELFunction.Name)) + } + return protoFQDNToPublicGoName(f.CELFunction.Name) +} + +func (f *CELFunction) IsMethod() bool { + return f.CELFunction.Receiver != nil +} + +func (f *CELFunction) ExportName() string { + return f.ID +} + +func (f *CELFunction) toInt32Arg(arg *resolver.Type, idx int) *CELFunctionArgument { + return &CELFunctionArgument{ + Name: fmt.Sprintf("arg%d", idx), + Type: "int32", + ArgIdx: idx, + arg: arg, + file: f.file, + } +} + +func (f *CELFunction) toInt64Arg(arg *resolver.Type, idx int) *CELFunctionArgument { + return &CELFunctionArgument{ + Name: fmt.Sprintf("arg%d", idx), + Type: "int64", + ArgIdx: idx, + arg: arg, + file: f.file, + } +} + +func (f *CELFunction) toUint32Arg(arg *resolver.Type, idx int) *CELFunctionArgument { + return &CELFunctionArgument{ + Name: fmt.Sprintf("arg%d", idx), + Type: "uint32", + ArgIdx: idx, + arg: arg, + file: f.file, + } +} + +func (f *CELFunction) toUint64Arg(arg *resolver.Type, idx int) *CELFunctionArgument { + return &CELFunctionArgument{ + Name: fmt.Sprintf("arg%d", idx), + Type: "uint64", + ArgIdx: idx, + arg: arg, + file: f.file, + } +} + +func (f *CELFunction) toStringArg(arg *resolver.Type, idx int) []*CELFunctionArgument { + return []*CELFunctionArgument{ + { + Name: fmt.Sprintf("arg%d", idx), + Type: "uint32", + ArgIdx: idx, + arg: arg, + file: f.file, + }, + { + Name: fmt.Sprintf("arg%d", idx+1), + Type: "uint32", + ArgIdx: idx + 1, + arg: arg, + Skip: true, + file: f.file, + }, + } +} + +func (f *CELFunction) Args() []*CELFunctionArgument { + ret := make([]*CELFunctionArgument, 0, len(f.CELFunction.Args)) + for _, arg := range f.CELFunction.Args { + ret = append(ret, &CELFunctionArgument{ + Type: toTypeText(f.file, arg), + file: f.file, + arg: arg, + }) + } + return ret +} + +func (f *CELFunction) Return() *CELFunctionReturn { + return &CELFunctionReturn{ + Type: toTypeText(f.file, f.CELFunction.Return), + ret: f.CELFunction.Return, + } +} + +func (f *CELFunction) WasmArgs() []*CELFunctionArgument { + ret := make([]*CELFunctionArgument, 0, len(f.CELFunction.Args)) + var idx int + for _, arg := range f.CELFunction.Args { + switch arg.Kind { + case types.Bool: + ret = append(ret, f.toInt32Arg(arg, idx)) + case types.Int32: + ret = append(ret, f.toInt32Arg(arg, idx)) + case types.Sint32: + ret = append(ret, f.toInt32Arg(arg, idx)) + case types.Message: + ret = append(ret, f.toUint32Arg(arg, idx)) + case types.Uint32: + ret = append(ret, f.toUint32Arg(arg, idx)) + case types.Enum: + ret = append(ret, f.toUint32Arg(arg, idx)) + case types.Sfixed32: + ret = append(ret, f.toUint32Arg(arg, idx)) + case types.Sfixed64: + ret = append(ret, f.toUint32Arg(arg, idx)) + case types.Float: + ret = append(ret, f.toUint32Arg(arg, idx)) + case types.Fixed32: + ret = append(ret, f.toUint32Arg(arg, idx)) + case types.Int64: + ret = append(ret, f.toUint32Arg(arg, idx)) + case types.Sint64: + ret = append(ret, f.toInt64Arg(arg, idx)) + case types.Double: + ret = append(ret, f.toUint64Arg(arg, idx)) + case types.Uint64: + ret = append(ret, f.toUint64Arg(arg, idx)) + case types.Fixed64: + ret = append(ret, f.toUint64Arg(arg, idx)) + case types.String: + ret = append(ret, f.toStringArg(arg, idx)...) + idx++ + case types.Bytes: + ret = append(ret, f.toStringArg(arg, idx)...) + idx++ + default: + } + idx++ + } + return ret +} + +type CELFunctionArgument struct { + Name string + Type string + ArgIdx int + Skip bool + arg *resolver.Type + file *resolver.File +} + +type CELFunctionReturn struct { + Type string + ret *resolver.Type +} + +func (r *CELFunctionReturn) CELType() string { + return toCELTypeDeclare(r.ret) +} + +func (r *CELFunctionReturn) FuncName() string { + return util.ToPublicGoVariable(r.ret.Kind.ToString()) +} + +func (f *CELFunctionArgument) CELType() string { + return toCELTypeDeclare(f.arg) +} + +func (f *CELFunctionArgument) ConvertProcess() string { + switch f.arg.Kind { + case types.Double: + return fmt.Sprintf("grpcfed.ToFloat64(%s)", f.Name) + case types.Float: + return fmt.Sprintf("grpcfed.ToFloat32(%s)", f.Name) + case types.Bool: + return fmt.Sprintf("grpcfed.ToBool(%s)", f.Name) + case types.String: + return fmt.Sprintf("grpcfed.ToString(arg%d, arg%d)", f.ArgIdx, f.ArgIdx+1) + case types.Bytes: + return fmt.Sprintf("grpcfed.ToBytes(arg%d, arg%d)", f.ArgIdx, f.ArgIdx+1) + case types.Message: + msg := strings.TrimPrefix(toTypeText(f.file, f.arg), "*") + return fmt.Sprintf("grpcfed.ToMessage[%s](%s)", msg, f.Name) + } + return f.Name +} + +func (p *CELPlugin) PluginFunctions() []*CELFunction { + ret := make([]*CELFunction, 0, len(p.CELPlugin.Functions)) + for _, fn := range p.CELPlugin.Functions { + ret = append(ret, &CELFunction{ + file: p.file, + CELFunction: fn, + }) + } + return ret +} + +func (f *File) CELPlugins() []*CELPlugin { + ret := make([]*CELPlugin, 0, len(f.File.CELPlugins)) + for _, plug := range f.File.CELPlugins { + ret = append(ret, &CELPlugin{ + file: f.File, + CELPlugin: plug, + }) + } + return ret +} + type Service struct { *resolver.Service nameToLogValueMap map[string]*LogValue @@ -253,6 +491,17 @@ type OneofType struct { ReturnZeroValue string } +func (s *Service) CELPlugins() []*CELPlugin { + ret := make([]*CELPlugin, 0, len(s.Service.CELPlugins)) + for _, plugin := range s.Service.CELPlugins { + ret = append(ret, &CELPlugin{ + CELPlugin: plugin, + file: s.File, + }) + } + return ret +} + func (s *Service) Types() Types { return newTypeDeclares(s.Service.File, s.Service.Messages) } @@ -537,7 +786,7 @@ func toTypeText(file *resolver.File, t *resolver.Type) string { typ = messageTypeToText(file, t.Message) } default: - log.Fatalf("grpc-federation: specified unsupported type value %s", t.Kind) + log.Fatalf("grpc-federation: specified unsupported type value %s", t.Kind.ToString()) } if t.Repeated { return "[]" + typ @@ -824,7 +1073,7 @@ func (s *Service) logType(typ *resolver.Type) string { case types.Group, types.Message: return "Any" } - log.Fatalf("grpc-federation: specified unknown type value %s", typ.Kind) + log.Fatalf("grpc-federation: specified unknown type value %s", typ.Kind.ToString()) return "" } @@ -2057,7 +2306,7 @@ func toCELNativeType(t *resolver.Type) string { case types.Message: return fmt.Sprintf("cel.ObjectType(%q)", t.Message.FQDN()) default: - log.Fatalf("grpc-federation: specified unsupported type value %s", t.Kind) + log.Fatalf("grpc-federation: specified unsupported type value %s", t.Kind.ToString()) } return "" } diff --git a/generator/templates/plugin.go.tmpl b/generator/templates/plugin.go.tmpl new file mode 100644 index 00000000..0a2593b9 --- /dev/null +++ b/generator/templates/plugin.go.tmpl @@ -0,0 +1,41 @@ +{{- define "plugin" }} +{{- range . }} +{{ $pluginName := .PluginName }} +{{ $pluginFunctions := .PluginFunctions }} +type {{ $pluginName }} interface { + {{- range $pluginFunctions }} + {{ .Name }}({{- range .Args }}{{ .Type }},{{- end }}) ({{- .Return.Type }}, error) + {{- end }} +} + +var ( + reg_{{ $pluginName }} {{ $pluginName }} + mu_{{ $pluginName }} sync.RWMutex +) + +func Register{{ $pluginName }}(plug {{ $pluginName }}) { + mu_{{ $pluginName }}.Lock() + defer mu_{{ $pluginName }}.Unlock() + reg_{{ $pluginName }} = plug +} + +{{ range $pluginFunctions }} +//export {{ .ExportName }} +func {{ .ExportName }}({{- range .WasmArgs }}{{ .Name }} {{ .Type }},{{- end }}) grpcfed.ReturnValue { + {{- range .WasmArgs }} + {{- if not .Skip }} + converted_{{ .Name }} := {{ .ConvertProcess }} + {{- end }} + {{- end }} + + mu_{{ $pluginName }}.RLock() + ret, err := reg_{{ $pluginName }}.{{ .Name }}({{- range .WasmArgs }}{{- if not .Skip }}converted_{{ .Name }},{{- end }}{{- end }}) + mu_{{ $pluginName }}.RUnlock() + if err != nil { + return grpcfed.ErrorToReturnValue(err) + } + return grpcfed.{{ .Return.FuncName }}ToReturnValue(ret) +} +{{ end }} +{{- end }} +{{- end }} diff --git a/generator/templates/server.go.tmpl b/generator/templates/server.go.tmpl index 15ccbffd..766a9e49 100644 --- a/generator/templates/server.go.tmpl +++ b/generator/templates/server.go.tmpl @@ -9,6 +9,7 @@ import ( "time" "runtime/debug" "log/slog" + "unsafe" {{- range .DefaultImports }} {{- if .Alias }} @@ -46,6 +47,7 @@ type {{ .Name }}[T any] struct { {{- $customResolvers := .CustomResolvers }} {{- $types := .Types }} {{- $oneofTypes := .OneofTypes }} +{{- $celPlugins := .CELPlugins }} // {{ $serviceName }}Config configuration required to initialize the service that use GRPC Federation. type {{ $serviceName }}Config struct { @@ -59,6 +61,12 @@ type {{ $serviceName }}Config struct { // If this interface is not provided, an error is returned during initialization. Resolver {{ $serviceName }}Resolver // required {{- end }} + {{- if $celPlugins }} + // CELPlugin If you use the plugin feature to extend the CEL API, + // you must write a plugin and output WebAssembly. + // In this field, configure to load wasm with the path to the WebAssembly file and the sha256 value. + CELPlugin *{{ $serviceName }}CELPluginConfig + {{- end }} // ErrorHandler Federation Service often needs to convert errors received from downstream services. // If an error occurs during method execution in the Federation Service, this error handler is called and the returned error is treated as a final error. ErrorHandler grpcfed.ErrorHandler @@ -100,6 +108,14 @@ type {{ $serviceName }}Resolver interface { {{- end }} } +type {{ $serviceName }}CELPluginWasmConfig = grpcfedcel.WasmConfig + +type {{ $serviceName }}CELPluginConfig struct { + {{- range $celPlugins }} + {{ .FieldName }} {{ $serviceName }}CELPluginWasmConfig + {{- end }} +} + // {{ $serviceName }}UnimplementedResolver a structure implemented to satisfy the Resolver interface. // An Unimplemented error is always returned. // This is intended for use when there are many Resolver interfaces that do not need to be implemented, @@ -150,6 +166,11 @@ func New{{ $serviceName }}(cfg {{ $serviceName }}Config) (*{{ $serviceName }}, e return nil, fmt.Errorf("Resolver field in {{ $serviceName }}Config is not set. this field must be set") } {{- end }} + {{- if $celPlugins }} + if cfg.CELPlugin == nil { + return nil, fmt.Errorf("CELPlugin field in {{ $serviceName }}Config is not set. this field must be set") + } + {{- end }} {{- range $serviceDependencies }} {{ .ClientName }}, err := cfg.Client.{{ .ClientName }}({{ $serviceName }}ClientConfig{ Service: "{{ .ServiceName }}", @@ -191,13 +212,41 @@ func New{{ $serviceName }}(cfg {{ $serviceName }}Config) (*{{ $serviceName }}, e }, {{- end }} }) - env, err := cel.NewCustomEnv( + envOpts := []cel.EnvOption{ cel.StdLib(), cel.Lib(grpcfedcel.NewLibrary()), cel.CrossTypeNumericComparisons(true), cel.CustomTypeAdapter(celHelper.TypeAdapter()), cel.CustomTypeProvider(celHelper.TypeProvider()), - ) + } + {{- range $celPlugins }} + { + plugin, err := grpcfedcel.NewCELPlugin(context.Background(), grpcfedcel.CELPluginConfig{ + Name: "{{ .Name }}", + Wasm: cfg.CELPlugin.{{ .FieldName }}, + Functions: []*grpcfedcel.CELFunction{ + {{- range .Functions }} + { + Name: "{{ .CELFunction.Name }}", + ID: "{{ .ID }}", + Args: []*cel.Type{ + {{- range .Args }} + {{ .CELType }}, + {{- end }} + }, + Return: {{ .Return.CELType }}, + IsMethod: {{ .IsMethod }}, + }, + {{- end }} + }, + }) + if err != nil { + return nil, err + } + envOpts = append(envOpts, cel.Lib(plugin)) + } + {{- end }} + env, err := cel.NewCustomEnv(envOpts...) if err != nil { return nil, err } @@ -509,3 +558,5 @@ func (s *{{ $serviceName }}) {{ .Name }}(v {{ .ValueType }}) slog.Value { {{ end }} {{- end }} + +{{- template "plugin" .CELPlugins }} diff --git a/generator/testdata/expected_alias.go b/generator/testdata/expected_alias.go index 8e416860..33fd6179 100644 --- a/generator/testdata/expected_alias.go +++ b/generator/testdata/expected_alias.go @@ -81,6 +81,11 @@ type FederationServiceDependentClientSet struct { type FederationServiceResolver interface { } +type FederationServiceCELPluginWasmConfig = grpcfedcel.WasmConfig + +type FederationServiceCELPluginConfig struct { +} + // FederationServiceUnimplementedResolver a structure implemented to satisfy the Resolver interface. // An Unimplemented error is always returned. // This is intended for use when there are many Resolver interfaces that do not need to be implemented, @@ -130,13 +135,14 @@ func NewFederationService(cfg FederationServiceConfig) (*FederationService, erro "id": grpcfed.NewCELFieldType(celtypes.StringType, "Id"), }, }) - env, err := cel.NewCustomEnv( + envOpts := []cel.EnvOption{ cel.StdLib(), cel.Lib(grpcfedcel.NewLibrary()), cel.CrossTypeNumericComparisons(true), cel.CustomTypeAdapter(celHelper.TypeAdapter()), cel.CustomTypeProvider(celHelper.TypeProvider()), - ) + } + env, err := cel.NewCustomEnv(envOpts...) if err != nil { return nil, err } diff --git a/generator/testdata/expected_async.go b/generator/testdata/expected_async.go index b1559f0e..848cc2d4 100644 --- a/generator/testdata/expected_async.go +++ b/generator/testdata/expected_async.go @@ -133,6 +133,11 @@ type FederationServiceDependentClientSet struct { type FederationServiceResolver interface { } +type FederationServiceCELPluginWasmConfig = grpcfedcel.WasmConfig + +type FederationServiceCELPluginConfig struct { +} + // FederationServiceUnimplementedResolver a structure implemented to satisfy the Resolver interface. // An Unimplemented error is always returned. // This is intended for use when there are many Resolver interfaces that do not need to be implemented, @@ -191,13 +196,14 @@ func NewFederationService(cfg FederationServiceConfig) (*FederationService, erro "i": grpcfed.NewCELFieldType(celtypes.StringType, "I"), }, }) - env, err := cel.NewCustomEnv( + envOpts := []cel.EnvOption{ cel.StdLib(), cel.Lib(grpcfedcel.NewLibrary()), cel.CrossTypeNumericComparisons(true), cel.CustomTypeAdapter(celHelper.TypeAdapter()), cel.CustomTypeProvider(celHelper.TypeProvider()), - ) + } + env, err := cel.NewCustomEnv(envOpts...) if err != nil { return nil, err } diff --git a/generator/testdata/expected_autobind.go b/generator/testdata/expected_autobind.go index e0e2972a..44ab93aa 100644 --- a/generator/testdata/expected_autobind.go +++ b/generator/testdata/expected_autobind.go @@ -79,6 +79,11 @@ type FederationServiceDependentClientSet struct { type FederationServiceResolver interface { } +type FederationServiceCELPluginWasmConfig = grpcfedcel.WasmConfig + +type FederationServiceCELPluginConfig struct { +} + // FederationServiceUnimplementedResolver a structure implemented to satisfy the Resolver interface. // An Unimplemented error is always returned. // This is intended for use when there are many Resolver interfaces that do not need to be implemented, @@ -131,13 +136,14 @@ func NewFederationService(cfg FederationServiceConfig) (*FederationService, erro "user_id": grpcfed.NewCELFieldType(celtypes.StringType, "UserId"), }, }) - env, err := cel.NewCustomEnv( + envOpts := []cel.EnvOption{ cel.StdLib(), cel.Lib(grpcfedcel.NewLibrary()), cel.CrossTypeNumericComparisons(true), cel.CustomTypeAdapter(celHelper.TypeAdapter()), cel.CustomTypeProvider(celHelper.TypeProvider()), - ) + } + env, err := cel.NewCustomEnv(envOpts...) if err != nil { return nil, err } diff --git a/generator/testdata/expected_condition.go b/generator/testdata/expected_condition.go index fad4dfda..79cf92b1 100644 --- a/generator/testdata/expected_condition.go +++ b/generator/testdata/expected_condition.go @@ -83,6 +83,11 @@ type FederationServiceDependentClientSet struct { type FederationServiceResolver interface { } +type FederationServiceCELPluginWasmConfig = grpcfedcel.WasmConfig + +type FederationServiceCELPluginConfig struct { +} + // FederationServiceUnimplementedResolver a structure implemented to satisfy the Resolver interface. // An Unimplemented error is always returned. // This is intended for use when there are many Resolver interfaces that do not need to be implemented, @@ -135,13 +140,14 @@ func NewFederationService(cfg FederationServiceConfig) (*FederationService, erro "user_id": grpcfed.NewCELFieldType(celtypes.StringType, "UserId"), }, }) - env, err := cel.NewCustomEnv( + envOpts := []cel.EnvOption{ cel.StdLib(), cel.Lib(grpcfedcel.NewLibrary()), cel.CrossTypeNumericComparisons(true), cel.CustomTypeAdapter(celHelper.TypeAdapter()), cel.CustomTypeProvider(celHelper.TypeProvider()), - ) + } + env, err := cel.NewCustomEnv(envOpts...) if err != nil { return nil, err } diff --git a/generator/testdata/expected_const_value.go b/generator/testdata/expected_const_value.go index f691921e..fd94b3e0 100644 --- a/generator/testdata/expected_const_value.go +++ b/generator/testdata/expected_const_value.go @@ -109,6 +109,11 @@ type FederationServiceDependentClientSet struct { type FederationServiceResolver interface { } +type FederationServiceCELPluginWasmConfig = grpcfedcel.WasmConfig + +type FederationServiceCELPluginConfig struct { +} + // FederationServiceUnimplementedResolver a structure implemented to satisfy the Resolver interface. // An Unimplemented error is always returned. // This is intended for use when there are many Resolver interfaces that do not need to be implemented, @@ -194,13 +199,14 @@ func NewFederationService(cfg FederationServiceConfig) (*FederationService, erro "id": grpcfed.NewCELFieldType(celtypes.StringType, "Id"), }, }) - env, err := cel.NewCustomEnv( + envOpts := []cel.EnvOption{ cel.StdLib(), cel.Lib(grpcfedcel.NewLibrary()), cel.CrossTypeNumericComparisons(true), cel.CustomTypeAdapter(celHelper.TypeAdapter()), cel.CustomTypeProvider(celHelper.TypeProvider()), - ) + } + env, err := cel.NewCustomEnv(envOpts...) if err != nil { return nil, err } diff --git a/generator/testdata/expected_create_post.go b/generator/testdata/expected_create_post.go index a8938b6b..5d7f3da0 100644 --- a/generator/testdata/expected_create_post.go +++ b/generator/testdata/expected_create_post.go @@ -80,6 +80,11 @@ type FederationServiceDependentClientSet struct { type FederationServiceResolver interface { } +type FederationServiceCELPluginWasmConfig = grpcfedcel.WasmConfig + +type FederationServiceCELPluginConfig struct { +} + // FederationServiceUnimplementedResolver a structure implemented to satisfy the Resolver interface. // An Unimplemented error is always returned. // This is intended for use when there are many Resolver interfaces that do not need to be implemented, @@ -133,13 +138,14 @@ func NewFederationService(cfg FederationServiceConfig) (*FederationService, erro "user_id": grpcfed.NewCELFieldType(celtypes.StringType, "UserId"), }, }) - env, err := cel.NewCustomEnv( + envOpts := []cel.EnvOption{ cel.StdLib(), cel.Lib(grpcfedcel.NewLibrary()), cel.CrossTypeNumericComparisons(true), cel.CustomTypeAdapter(celHelper.TypeAdapter()), cel.CustomTypeProvider(celHelper.TypeProvider()), - ) + } + env, err := cel.NewCustomEnv(envOpts...) if err != nil { return nil, err } diff --git a/generator/testdata/expected_custom_resolver.go b/generator/testdata/expected_custom_resolver.go index 43bc5a0f..c65fe031 100644 --- a/generator/testdata/expected_custom_resolver.go +++ b/generator/testdata/expected_custom_resolver.go @@ -111,6 +111,11 @@ type FederationServiceResolver interface { Resolve_Org_Federation_User_Name(context.Context, *Org_Federation_User_NameArgument[*FederationServiceDependentClientSet]) (string, error) } +type FederationServiceCELPluginWasmConfig = grpcfedcel.WasmConfig + +type FederationServiceCELPluginConfig struct { +} + // FederationServiceUnimplementedResolver a structure implemented to satisfy the Resolver interface. // An Unimplemented error is always returned. // This is intended for use when there are many Resolver interfaces that do not need to be implemented, @@ -199,13 +204,14 @@ func NewFederationService(cfg FederationServiceConfig) (*FederationService, erro "user_id": grpcfed.NewCELFieldType(celtypes.StringType, "UserId"), }, }) - env, err := cel.NewCustomEnv( + envOpts := []cel.EnvOption{ cel.StdLib(), cel.Lib(grpcfedcel.NewLibrary()), cel.CrossTypeNumericComparisons(true), cel.CustomTypeAdapter(celHelper.TypeAdapter()), cel.CustomTypeProvider(celHelper.TypeProvider()), - ) + } + env, err := cel.NewCustomEnv(envOpts...) if err != nil { return nil, err } diff --git a/generator/testdata/expected_map.go b/generator/testdata/expected_map.go index 6cb51b98..ba274c6a 100644 --- a/generator/testdata/expected_map.go +++ b/generator/testdata/expected_map.go @@ -94,6 +94,11 @@ type FederationServiceResolver interface { Resolve_Org_Federation_User(context.Context, *Org_Federation_UserArgument[*FederationServiceDependentClientSet]) (*User, error) } +type FederationServiceCELPluginWasmConfig = grpcfedcel.WasmConfig + +type FederationServiceCELPluginConfig struct { +} + // FederationServiceUnimplementedResolver a structure implemented to satisfy the Resolver interface. // An Unimplemented error is always returned. // This is intended for use when there are many Resolver interfaces that do not need to be implemented, @@ -165,13 +170,14 @@ func NewFederationService(cfg FederationServiceConfig) (*FederationService, erro "user_id": grpcfed.NewCELFieldType(celtypes.StringType, "UserId"), }, }) - env, err := cel.NewCustomEnv( + envOpts := []cel.EnvOption{ cel.StdLib(), cel.Lib(grpcfedcel.NewLibrary()), cel.CrossTypeNumericComparisons(true), cel.CustomTypeAdapter(celHelper.TypeAdapter()), cel.CustomTypeProvider(celHelper.TypeProvider()), - ) + } + env, err := cel.NewCustomEnv(envOpts...) if err != nil { return nil, err } diff --git a/generator/testdata/expected_minimum.go b/generator/testdata/expected_minimum.go index 9ee605be..5084a383 100644 --- a/generator/testdata/expected_minimum.go +++ b/generator/testdata/expected_minimum.go @@ -62,6 +62,11 @@ type FederationServiceResolver interface { Resolve_Org_Federation_GetPostResponse(context.Context, *Org_Federation_GetPostResponseArgument[*FederationServiceDependentClientSet]) (*GetPostResponse, error) } +type FederationServiceCELPluginWasmConfig = grpcfedcel.WasmConfig + +type FederationServiceCELPluginConfig struct { +} + // FederationServiceUnimplementedResolver a structure implemented to satisfy the Resolver interface. // An Unimplemented error is always returned. // This is intended for use when there are many Resolver interfaces that do not need to be implemented, @@ -106,13 +111,14 @@ func NewFederationService(cfg FederationServiceConfig) (*FederationService, erro "type": grpcfed.NewCELFieldType(celtypes.IntType, "Type"), }, }) - env, err := cel.NewCustomEnv( + envOpts := []cel.EnvOption{ cel.StdLib(), cel.Lib(grpcfedcel.NewLibrary()), cel.CrossTypeNumericComparisons(true), cel.CustomTypeAdapter(celHelper.TypeAdapter()), cel.CustomTypeProvider(celHelper.TypeProvider()), - ) + } + env, err := cel.NewCustomEnv(envOpts...) if err != nil { return nil, err } diff --git a/generator/testdata/expected_multi_user.go b/generator/testdata/expected_multi_user.go index 5a5a9379..98b835ff 100644 --- a/generator/testdata/expected_multi_user.go +++ b/generator/testdata/expected_multi_user.go @@ -99,6 +99,11 @@ type FederationServiceResolver interface { Resolve_Org_Federation_User_Name(context.Context, *Org_Federation_User_NameArgument[*FederationServiceDependentClientSet]) (string, error) } +type FederationServiceCELPluginWasmConfig = grpcfedcel.WasmConfig + +type FederationServiceCELPluginConfig struct { +} + // FederationServiceUnimplementedResolver a structure implemented to satisfy the Resolver interface. // An Unimplemented error is always returned. // This is intended for use when there are many Resolver interfaces that do not need to be implemented, @@ -166,13 +171,14 @@ func NewFederationService(cfg FederationServiceConfig) (*FederationService, erro }, "grpc.federation.private.UserIDArgument": {}, }) - env, err := cel.NewCustomEnv( + envOpts := []cel.EnvOption{ cel.StdLib(), cel.Lib(grpcfedcel.NewLibrary()), cel.CrossTypeNumericComparisons(true), cel.CustomTypeAdapter(celHelper.TypeAdapter()), cel.CustomTypeProvider(celHelper.TypeProvider()), - ) + } + env, err := cel.NewCustomEnv(envOpts...) if err != nil { return nil, err } diff --git a/generator/testdata/expected_oneof.go b/generator/testdata/expected_oneof.go index a1bf78a7..fa84dc50 100644 --- a/generator/testdata/expected_oneof.go +++ b/generator/testdata/expected_oneof.go @@ -81,6 +81,11 @@ type FederationServiceDependentClientSet struct { type FederationServiceResolver interface { } +type FederationServiceCELPluginWasmConfig = grpcfedcel.WasmConfig + +type FederationServiceCELPluginConfig struct { +} + // FederationServiceUnimplementedResolver a structure implemented to satisfy the Resolver interface. // An Unimplemented error is always returned. // This is intended for use when there are many Resolver interfaces that do not need to be implemented, @@ -140,13 +145,14 @@ func NewFederationService(cfg FederationServiceConfig) (*FederationService, erro ), }, }) - env, err := cel.NewCustomEnv( + envOpts := []cel.EnvOption{ cel.StdLib(), cel.Lib(grpcfedcel.NewLibrary()), cel.CrossTypeNumericComparisons(true), cel.CustomTypeAdapter(celHelper.TypeAdapter()), cel.CustomTypeProvider(celHelper.TypeProvider()), - ) + } + env, err := cel.NewCustomEnv(envOpts...) if err != nil { return nil, err } diff --git a/generator/testdata/expected_resolver_overlaps.go b/generator/testdata/expected_resolver_overlaps.go index 02902fbc..a8d1c6e2 100644 --- a/generator/testdata/expected_resolver_overlaps.go +++ b/generator/testdata/expected_resolver_overlaps.go @@ -77,6 +77,11 @@ type FederationServiceDependentClientSet struct { type FederationServiceResolver interface { } +type FederationServiceCELPluginWasmConfig = grpcfedcel.WasmConfig + +type FederationServiceCELPluginConfig struct { +} + // FederationServiceUnimplementedResolver a structure implemented to satisfy the Resolver interface. // An Unimplemented error is always returned. // This is intended for use when there are many Resolver interfaces that do not need to be implemented, @@ -129,13 +134,14 @@ func NewFederationService(cfg FederationServiceConfig) (*FederationService, erro "id": grpcfed.NewCELFieldType(celtypes.StringType, "Id"), }, }) - env, err := cel.NewCustomEnv( + envOpts := []cel.EnvOption{ cel.StdLib(), cel.Lib(grpcfedcel.NewLibrary()), cel.CrossTypeNumericComparisons(true), cel.CustomTypeAdapter(celHelper.TypeAdapter()), cel.CustomTypeProvider(celHelper.TypeProvider()), - ) + } + env, err := cel.NewCustomEnv(envOpts...) if err != nil { return nil, err } diff --git a/generator/testdata/expected_simple_aggregation.go b/generator/testdata/expected_simple_aggregation.go index 99d74155..ba4d913f 100644 --- a/generator/testdata/expected_simple_aggregation.go +++ b/generator/testdata/expected_simple_aggregation.go @@ -122,6 +122,11 @@ type FederationServiceResolver interface { Resolve_Org_Federation_Z(context.Context, *Org_Federation_ZArgument[*FederationServiceDependentClientSet]) (*Z, error) } +type FederationServiceCELPluginWasmConfig = grpcfedcel.WasmConfig + +type FederationServiceCELPluginConfig struct { +} + // FederationServiceUnimplementedResolver a structure implemented to satisfy the Resolver interface. // An Unimplemented error is always returned. // This is intended for use when there are many Resolver interfaces that do not need to be implemented, @@ -205,13 +210,14 @@ func NewFederationService(cfg FederationServiceConfig) (*FederationService, erro }, "grpc.federation.private.ZArgument": {}, }) - env, err := cel.NewCustomEnv( + envOpts := []cel.EnvOption{ cel.StdLib(), cel.Lib(grpcfedcel.NewLibrary()), cel.CrossTypeNumericComparisons(true), cel.CustomTypeAdapter(celHelper.TypeAdapter()), cel.CustomTypeProvider(celHelper.TypeProvider()), - ) + } + env, err := cel.NewCustomEnv(envOpts...) if err != nil { return nil, err } diff --git a/generator/testdata/expected_validation.go b/generator/testdata/expected_validation.go index 3634b98c..7cff674d 100644 --- a/generator/testdata/expected_validation.go +++ b/generator/testdata/expected_validation.go @@ -69,6 +69,11 @@ type FederationServiceDependentClientSet struct { type FederationServiceResolver interface { } +type FederationServiceCELPluginWasmConfig = grpcfedcel.WasmConfig + +type FederationServiceCELPluginConfig struct { +} + // FederationServiceUnimplementedResolver a structure implemented to satisfy the Resolver interface. // An Unimplemented error is always returned. // This is intended for use when there are many Resolver interfaces that do not need to be implemented, @@ -105,13 +110,14 @@ func NewFederationService(cfg FederationServiceConfig) (*FederationService, erro }, "grpc.federation.private.PostArgument": {}, }) - env, err := cel.NewCustomEnv( + envOpts := []cel.EnvOption{ cel.StdLib(), cel.Lib(grpcfedcel.NewLibrary()), cel.CrossTypeNumericComparisons(true), cel.CustomTypeAdapter(celHelper.TypeAdapter()), cel.CustomTypeProvider(celHelper.TypeProvider()), - ) + } + env, err := cel.NewCustomEnv(envOpts...) if err != nil { return nil, err } diff --git a/go.mod b/go.mod index 5b789e1f..29c461c2 100644 --- a/go.mod +++ b/go.mod @@ -11,6 +11,7 @@ require ( github.com/google/go-cmp v0.6.0 github.com/google/uuid v1.5.0 github.com/jessevdk/go-flags v1.5.0 + github.com/tetratelabs/wazero v1.6.0 go.lsp.dev/jsonrpc2 v0.10.0 go.lsp.dev/protocol v0.12.0 go.lsp.dev/uri v0.3.0 diff --git a/go.sum b/go.sum index 70846686..909f2662 100644 --- a/go.sum +++ b/go.sum @@ -57,6 +57,8 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+ github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/tetratelabs/wazero v1.6.0 h1:z0H1iikCdP8t+q341xqepY4EWvHEw8Es7tlqiVzlP3g= +github.com/tetratelabs/wazero v1.6.0/go.mod h1:0U0G41+ochRKoPKCJlh0jMg1CHkyfK8kDqiirMmKY8A= go.lsp.dev/jsonrpc2 v0.10.0 h1:Pr/YcXJoEOTMc/b6OTmcR1DPJ3mSWl/SWiU1Cct6VmI= go.lsp.dev/jsonrpc2 v0.10.0/go.mod h1:fmEzIdXPi/rf6d4uFcayi8HpFP1nBF99ERP1htC72Ac= go.lsp.dev/pkg v0.0.0-20210717090340-384b27a52fb2 h1:hCzQgh6UcwbKgNSRurYWSqh8MufqRRPODRBblutn4TE= diff --git a/grpc/federation/cel.go b/grpc/federation/cel.go index c7a32ab9..f65b6f40 100644 --- a/grpc/federation/cel.go +++ b/grpc/federation/cel.go @@ -1,3 +1,5 @@ +//go:build !tinygo.wasm + package federation import ( diff --git a/grpc/federation/cel/plugin.go b/grpc/federation/cel/plugin.go new file mode 100644 index 00000000..7dfca091 --- /dev/null +++ b/grpc/federation/cel/plugin.go @@ -0,0 +1,71 @@ +package cel + +import ( + "context" + + "github.com/google/cel-go/cel" + "github.com/google/cel-go/common/types/ref" +) + +type CELPlugin struct { + Name string + Functions []*CELFunction + wasm *WasmPlugin +} + +type CELFunction struct { + Name string + ID string + Args []*cel.Type + Return *cel.Type + IsMethod bool +} + +type CELPluginConfig struct { + Name string + Wasm WasmConfig + Functions []*CELFunction +} + +type WasmConfig struct { + Path string + Sha256 string +} + +func NewCELPlugin(ctx context.Context, cfg CELPluginConfig) (*CELPlugin, error) { + wasm, err := NewWasmPlugin(ctx, cfg.Wasm) + if err != nil { + return nil, err + } + return &CELPlugin{ + Name: cfg.Name, + Functions: cfg.Functions, + wasm: wasm, + }, nil +} + +func (p *CELPlugin) LibraryName() string { + return p.Name +} + +func (p *CELPlugin) CompileOptions() []cel.EnvOption { + var opts []cel.EnvOption + for _, fn := range p.Functions { + fn := fn + bindFunc := cel.FunctionBinding(func(args ...ref.Val) ref.Val { + return p.wasm.Call(fn, args...) + }) + var overload cel.FunctionOpt + if fn.IsMethod { + overload = cel.MemberOverload(fn.ID, fn.Args, fn.Return, bindFunc) + } else { + overload = cel.Overload(fn.ID, fn.Args, fn.Return, bindFunc) + } + opts = append(opts, cel.Function(fn.Name, overload)) + } + return opts +} + +func (p *CELPlugin) ProgramOptions() []cel.ProgramOption { + return []cel.ProgramOption{} +} diff --git a/grpc/federation/cel/wasm.go b/grpc/federation/cel/wasm.go new file mode 100644 index 00000000..b957bb39 --- /dev/null +++ b/grpc/federation/cel/wasm.go @@ -0,0 +1,270 @@ +package cel + +import ( + "context" + "crypto/sha256" + "encoding/hex" + "errors" + "fmt" + "log" + "os" + "reflect" + "unsafe" + + "github.com/google/cel-go/cel" + "github.com/google/cel-go/common/types" + "github.com/google/cel-go/common/types/ref" + "github.com/tetratelabs/wazero" + "github.com/tetratelabs/wazero/api" + "github.com/tetratelabs/wazero/imports/wasi_snapshot_preview1" +) + +var ( + ErrOutOfRangeAccessWasmMemory = errors.New( + `grpc-federation: detected out of range access`, + ) + ErrWasmContentMismatch = errors.New( + `grpc-federation: wasm file content mismatch`, + ) +) + +type WasmPlugin struct { + File string + r wazero.Runtime + mod api.Module + malloc api.Function + free api.Function +} + +func NewWasmPlugin(ctx context.Context, wasmCfg WasmConfig) (*WasmPlugin, error) { + wasmFile, err := os.ReadFile(wasmCfg.Path) + if err != nil { + return nil, err + } + hash := sha256.Sum256(wasmFile) + gotHash := hex.EncodeToString(hash[:]) + if wasmCfg.Sha256 != gotHash { + return nil, fmt.Errorf(`expected [%s] but got [%s]: %w`, wasmCfg.Sha256, gotHash, ErrWasmContentMismatch) + } + cfg := wazero.NewRuntimeConfig() + r := wazero.NewRuntimeWithConfig(ctx, cfg) + + if _, err := r.NewHostModuleBuilder("env"). + NewFunctionBuilder().WithFunc(wasmDebugLog).Export("grpc_federation_log"). + Instantiate(ctx); err != nil { + return nil, err + } + + wasi_snapshot_preview1.MustInstantiate(ctx, r) + + mod, err := r.Instantiate(ctx, wasmFile) + if err != nil { + return nil, err + } + return &WasmPlugin{ + File: wasmCfg.Path, + r: r, + mod: mod, + malloc: mod.ExportedFunction("malloc"), + free: mod.ExportedFunction("free"), + }, nil +} + +func (p *WasmPlugin) Call(fn *CELFunction, args ...ref.Val) ref.Val { + ctx := context.Background() + f := p.mod.ExportedFunction(fn.ID) + if f == nil { + return types.NewErr(fmt.Sprintf("grpc-federation: failed to find exported function %s in %s", fn.Name, p.File)) + } + + var wasmArgs []uint64 + for idx, arg := range args { + wasmArg, err := p.refToWASMType(ctx, fn.Args[idx], arg) + if err != nil { + return types.NewErr(err.Error()) + } + wasmArgs = append(wasmArgs, wasmArg...) + } + result, err := f.Call(ctx, wasmArgs...) + if err != nil { + return types.NewErr(err.Error()) + } + ret := ReturnValue(result[0]) + if err := p.returnValueToError(ret); err != nil { + return types.NewErr(err.Error()) + } + return p.returnValueToCELValue(fn, fn.Return, ret) +} + +func (p *WasmPlugin) refToWASMType(ctx context.Context, typ *cel.Type, v ref.Val) ([]uint64, error) { + switch typ.Kind() { + case types.BoolKind: + vv := v.(types.Bool) + if vv { + return []uint64{uint64(1)}, nil + } + return []uint64{uint64(0)}, nil + case types.DoubleKind: + vv := v.(types.Double) + return []uint64{api.EncodeF64(float64(vv))}, nil + case types.IntKind: + vv := v.(types.Int) + return []uint64{api.EncodeI64(int64(vv))}, nil + case types.BytesKind: + vv := v.(types.Bytes) + ptr, size, err := p.stringToPtr(ctx, string(vv)) + if err != nil { + return nil, err + } + return []uint64{api.EncodeU32(ptr), api.EncodeU32(size)}, nil + case types.StringKind: + vv := v.(types.String) + ptr, size, err := p.stringToPtr(ctx, string(vv)) + if err != nil { + return nil, err + } + return []uint64{api.EncodeU32(ptr), api.EncodeU32(size)}, nil + case types.UintKind: + vv := v.(types.Uint) + return []uint64{uint64(vv)}, nil + case types.StructKind: + switch obj := v.Value().(type) { + case *objectValueWrapper: + return []uint64{obj.wasmValue()}, nil + default: + return nil, fmt.Errorf( + `grpc-federation: currently unsupported native proto message "%T"`, + obj, + ) + } + } + return nil, fmt.Errorf(`grpc-federation: found unexpected cel function's argument type "%s"`, typ) +} + +type objectValueWrapper struct { + typ *cel.Type + ptr unsafe.Pointer +} + +func (w *objectValueWrapper) wasmValue() uint64 { + return uint64(uintptr(w.ptr)) +} + +func (w *objectValueWrapper) ConvertToNative(typeDesc reflect.Type) (any, error) { return w, nil } + +func (w *objectValueWrapper) ConvertToType(typeValue ref.Type) ref.Val { return w } + +func (w *objectValueWrapper) Equal(other ref.Val) ref.Val { return nil } + +func (w *objectValueWrapper) Type() ref.Type { return w.typ } + +func (w *objectValueWrapper) Value() any { return w } + +func (p *WasmPlugin) returnValueToCELValue(fn *CELFunction, typ *cel.Type, v ReturnValue) ref.Val { + switch typ.Kind() { + case types.BoolKind: + return types.Bool(p.returnValueToBool(v)) + case types.BytesKind: + return types.Bytes(p.returnValueToBytes(v)) + case types.DoubleKind: + return types.Double(p.returnValueToFloat64(v)) + case types.ErrorKind: + return types.NewErr(p.returnValueToString(v)) + case types.IntKind: + return types.Int(p.returnValueToInt64(v)) + case types.StringKind: + return types.String(p.returnValueToString(v)) + case types.UintKind: + return types.Uint(p.returnValueToUint64(v)) + case types.StructKind: + return &objectValueWrapper{ + typ: typ, + ptr: p.returnValueToPtr(v), + } + } + return types.NewErr("grpc-federation: unknown result type %s from %s function", typ, fn.Name) +} + +type ReturnValue uint64 + +func (p *WasmPlugin) returnValueToPtr(v ReturnValue) unsafe.Pointer { + return unsafe.Pointer(uintptr(v >> 32)) +} + +func (p *WasmPlugin) returnValueToBool(v ReturnValue) bool { + return uint32(v>>32) == 1 +} + +func (p *WasmPlugin) returnValueToInt64(v ReturnValue) int64 { + return int64(v >> 32) +} + +func (p *WasmPlugin) returnValueToUint64(v ReturnValue) uint64 { + return uint64(v) >> 32 +} + +func (p *WasmPlugin) returnValueToFloat64(v ReturnValue) float64 { + return api.DecodeF64(uint64(v) >> 32) +} + +func (p *WasmPlugin) returnValueToString(v ReturnValue) string { + ptr := uint32(v >> 32) + size := uint32(v) + return p.ptrToString(ptr, size) +} + +func (p *WasmPlugin) returnValueToBytes(v ReturnValue) []byte { + return []byte(p.returnValueToString(v)) +} + +func (p *WasmPlugin) returnValueToError(v ReturnValue) error { + ptr := uint32(v >> 32) + size := uint32(v) + + if (size & (1 << 31)) <= 0 { + return nil + } + + size &^= (1 << 31) + bytes, ok := p.mod.Memory().Read(ptr, size) + if !ok { + return fmt.Errorf( + `failed to read wasm memory: (ptr, size) = (%d, %d) and memory size is %d: %w`, + ptr, size, p.mod.Memory().Size(), + ErrOutOfRangeAccessWasmMemory, + ) + } + return errors.New(string(bytes)) +} + +func (p *WasmPlugin) stringToPtr(ctx context.Context, s string) (uint32, uint32, error) { + results, err := p.malloc.Call(ctx, uint64(len(s))) + if err != nil { + return 0, 0, err + } + ptr := uint32(results[0]) + size := uint32(len(s)) + if !p.mod.Memory().Write(ptr, []byte(s)) { + return 0, 0, fmt.Errorf( + `failed to write wasm memory: (ptr, size) = (%d, %d) and memory size is %d: %w`, + ptr, size, p.mod.Memory().Size(), + ErrOutOfRangeAccessWasmMemory, + ) + } + return ptr, size, nil +} + +func (p *WasmPlugin) ptrToString(ptr, size uint32) string { + return unsafe.String((*byte)(unsafe.Pointer(uintptr(ptr))), size) +} + +func wasmDebugLog(_ context.Context, m api.Module, offset, byteCount uint32) { + buf, ok := m.Memory().Read(offset, byteCount) + if !ok { + log.Panicf( + `grpc-federation: failed to output debug log: detected out of range access. (ptr, size) = (%d, %d)`, + offset, byteCount, + ) + } + fmt.Fprintln(os.Stdout, string(buf)) +} diff --git a/grpc/federation/context.go b/grpc/federation/context.go index c3a84420..0b57a45a 100644 --- a/grpc/federation/context.go +++ b/grpc/federation/context.go @@ -1,3 +1,5 @@ +//go:build !tinygo.wasm + package federation import ( diff --git a/grpc/federation/error.go b/grpc/federation/error.go index cf367e12..6df65894 100644 --- a/grpc/federation/error.go +++ b/grpc/federation/error.go @@ -1,3 +1,5 @@ +//go:build !tinygo.wasm + package federation import ( diff --git a/grpc/federation/lib.go b/grpc/federation/lib.go index b85f553e..9df5a99a 100644 --- a/grpc/federation/lib.go +++ b/grpc/federation/lib.go @@ -1,3 +1,5 @@ +//go:build !tinygo.wasm + package federation import ( diff --git a/grpc/federation/otel.go b/grpc/federation/otel.go index 297b7ae7..a1aa3b28 100644 --- a/grpc/federation/otel.go +++ b/grpc/federation/otel.go @@ -1,3 +1,5 @@ +//go:build !tinygo.wasm + package federation import ( diff --git a/grpc/federation/plugin.go b/grpc/federation/plugin.go new file mode 100644 index 00000000..f4bcbc4f --- /dev/null +++ b/grpc/federation/plugin.go @@ -0,0 +1,130 @@ +//go:build tinygo.wasm + +package federation + +import ( + "reflect" + "runtime" + "unsafe" + + "github.com/tetratelabs/wazero/api" +) + +// #include +import "C" + +type ReturnValue uint64 + +func MessageToReturnValue[T any](v *T) ReturnValue { + return ReturnValue(uint64(uintptr(unsafe.Pointer(v))) << uint64(32)) +} + +func StringToReturnValue(v string) ReturnValue { + return BytesToReturnValue([]byte(v)) +} + +func BytesToReturnValue(v []byte) ReturnValue { + ptr, size := BytesToPtrWithAllocation(v) + return ReturnValue((uint64(ptr) << uint64(32)) | uint64(size)) +} + +func BoolToReturnValue(v bool) ReturnValue { + if v { + return ReturnValue(1 << uint64(32)) + } + return ReturnValue(0 << uint64(32)) +} + +func Int32ToReturnValue(v int32) ReturnValue { + return ReturnValue(api.EncodeI32(v) << uint64(32)) +} + +func Int64ToReturnValue(v int64) ReturnValue { + return ReturnValue(api.EncodeI64(v) << uint64(32)) +} + +func Uint32ToReturnValue(v uint32) ReturnValue { + return ReturnValue(api.EncodeU32(v) << uint64(32)) +} + +func Uint64ToReturnValue(v uint64) ReturnValue { + return ReturnValue(v << uint64(32)) +} + +func Float32ToReturnValue(v float32) ReturnValue { + return ReturnValue(api.EncodeF32(v) << uint64(32)) +} + +func Float64ToReturnValue(v float64) ReturnValue { + return ReturnValue(api.EncodeF64(v) << uint64(32)) +} + +func ErrorToReturnValue(err error) ReturnValue { + ptr, size := BytesToPtrWithAllocation([]byte(err.Error())) + return ReturnValue((uint64(ptr) << uint64(32)) | uint64(size) | (1 << 31)) +} + +func StringToPtr(s string) (uint32, uint32) { + ptr := unsafe.Pointer(unsafe.StringData(s)) + return uint32(uintptr(ptr)), uint32(len(s)) +} + +func BytesToPtr(b []byte) (uint32, uint32) { + return StringToPtr(string(b)) +} + +func StringToPtrWithAllocation(s string) (uint32, uint32) { + return BytesToPtrWithAllocation([]byte(s)) +} + +func BytesToPtrWithAllocation(b []byte) (uint32, uint32) { + if len(b) == 0 { + return 0, 0 + } + + size := C.ulong(len(b)) + ptr := unsafe.Pointer(C.malloc(size)) + + copy(unsafe.Slice((*byte)(ptr), size), b) + + return uint32(uintptr(ptr)), uint32(len(b)) +} + +func ToFloat64(v uint64) float64 { + return api.DecodeF64(v) +} + +func ToFloat32(v uint32) float32 { + return api.DecodeF32(uint64(v)) +} + +func ToString(ptr, size uint32) string { + return unsafe.String((*byte)(unsafe.Pointer(uintptr(ptr))), size) +} + +func ToMessage[T any](ptr uint32) *T { + return (*T)(unsafe.Pointer(uintptr(ptr))) +} + +func ToBytes(ptr, size uint32) []byte { + var b []byte + s := (*reflect.SliceHeader)(unsafe.Pointer(&b)) + s.Len = uintptr(size) + s.Cap = uintptr(size) + s.Data = uintptr(ptr) + return b +} + +func FreePtr(ptr uint32) { + C.free(unsafe.Pointer(uintptr(ptr))) +} + +func DebugLog(msg string) { + ptr, size := StringToPtr(msg) + grpc_federation_log(ptr, size) + runtime.KeepAlive(msg) +} + +//go:wasm-module env +//export grpc_federation_log +func grpc_federation_log(ptr, size uint32) diff --git a/grpc/federation/plugin.pb.go b/grpc/federation/plugin.pb.go new file mode 100644 index 00000000..81dd7089 --- /dev/null +++ b/grpc/federation/plugin.pb.go @@ -0,0 +1,720 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.31.0 +// protoc (unknown) +// source: grpc/federation/plugin.proto + +package federation + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + descriptorpb "google.golang.org/protobuf/types/descriptorpb" + reflect "reflect" + sync "sync" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +type PluginRule struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Export *Export `protobuf:"bytes,1,opt,name=export,proto3" json:"export,omitempty"` +} + +func (x *PluginRule) Reset() { + *x = PluginRule{} + if protoimpl.UnsafeEnabled { + mi := &file_grpc_federation_plugin_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *PluginRule) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*PluginRule) ProtoMessage() {} + +func (x *PluginRule) ProtoReflect() protoreflect.Message { + mi := &file_grpc_federation_plugin_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use PluginRule.ProtoReflect.Descriptor instead. +func (*PluginRule) Descriptor() ([]byte, []int) { + return file_grpc_federation_plugin_proto_rawDescGZIP(), []int{0} +} + +func (x *PluginRule) GetExport() *Export { + if x != nil { + return x.Export + } + return nil +} + +type Export struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` + Desc string `protobuf:"bytes,2,opt,name=desc,proto3" json:"desc,omitempty"` + Types []*ReceiverType `protobuf:"bytes,3,rep,name=types,proto3" json:"types,omitempty"` + Functions []*CELFunction `protobuf:"bytes,4,rep,name=functions,proto3" json:"functions,omitempty"` + Variables []*CELVariable `protobuf:"bytes,5,rep,name=variables,proto3" json:"variables,omitempty"` +} + +func (x *Export) Reset() { + *x = Export{} + if protoimpl.UnsafeEnabled { + mi := &file_grpc_federation_plugin_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Export) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Export) ProtoMessage() {} + +func (x *Export) ProtoReflect() protoreflect.Message { + mi := &file_grpc_federation_plugin_proto_msgTypes[1] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Export.ProtoReflect.Descriptor instead. +func (*Export) Descriptor() ([]byte, []int) { + return file_grpc_federation_plugin_proto_rawDescGZIP(), []int{1} +} + +func (x *Export) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *Export) GetDesc() string { + if x != nil { + return x.Desc + } + return "" +} + +func (x *Export) GetTypes() []*ReceiverType { + if x != nil { + return x.Types + } + return nil +} + +func (x *Export) GetFunctions() []*CELFunction { + if x != nil { + return x.Functions + } + return nil +} + +func (x *Export) GetVariables() []*CELVariable { + if x != nil { + return x.Variables + } + return nil +} + +type CELFunction struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` + Desc string `protobuf:"bytes,2,opt,name=desc,proto3" json:"desc,omitempty"` + Args []*CELFunctionArgument `protobuf:"bytes,3,rep,name=args,proto3" json:"args,omitempty"` + Return *CELType `protobuf:"bytes,4,opt,name=return,proto3" json:"return,omitempty"` +} + +func (x *CELFunction) Reset() { + *x = CELFunction{} + if protoimpl.UnsafeEnabled { + mi := &file_grpc_federation_plugin_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *CELFunction) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CELFunction) ProtoMessage() {} + +func (x *CELFunction) ProtoReflect() protoreflect.Message { + mi := &file_grpc_federation_plugin_proto_msgTypes[2] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CELFunction.ProtoReflect.Descriptor instead. +func (*CELFunction) Descriptor() ([]byte, []int) { + return file_grpc_federation_plugin_proto_rawDescGZIP(), []int{2} +} + +func (x *CELFunction) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *CELFunction) GetDesc() string { + if x != nil { + return x.Desc + } + return "" +} + +func (x *CELFunction) GetArgs() []*CELFunctionArgument { + if x != nil { + return x.Args + } + return nil +} + +func (x *CELFunction) GetReturn() *CELType { + if x != nil { + return x.Return + } + return nil +} + +type ReceiverType struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` + Desc string `protobuf:"bytes,2,opt,name=desc,proto3" json:"desc,omitempty"` + Methods []*CELFunction `protobuf:"bytes,3,rep,name=methods,proto3" json:"methods,omitempty"` +} + +func (x *ReceiverType) Reset() { + *x = ReceiverType{} + if protoimpl.UnsafeEnabled { + mi := &file_grpc_federation_plugin_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ReceiverType) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ReceiverType) ProtoMessage() {} + +func (x *ReceiverType) ProtoReflect() protoreflect.Message { + mi := &file_grpc_federation_plugin_proto_msgTypes[3] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ReceiverType.ProtoReflect.Descriptor instead. +func (*ReceiverType) Descriptor() ([]byte, []int) { + return file_grpc_federation_plugin_proto_rawDescGZIP(), []int{3} +} + +func (x *ReceiverType) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *ReceiverType) GetDesc() string { + if x != nil { + return x.Desc + } + return "" +} + +func (x *ReceiverType) GetMethods() []*CELFunction { + if x != nil { + return x.Methods + } + return nil +} + +type CELFunctionArgument struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` + Desc string `protobuf:"bytes,2,opt,name=desc,proto3" json:"desc,omitempty"` + Type string `protobuf:"bytes,3,opt,name=type,proto3" json:"type,omitempty"` + Repeated bool `protobuf:"varint,4,opt,name=repeated,proto3" json:"repeated,omitempty"` +} + +func (x *CELFunctionArgument) Reset() { + *x = CELFunctionArgument{} + if protoimpl.UnsafeEnabled { + mi := &file_grpc_federation_plugin_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *CELFunctionArgument) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CELFunctionArgument) ProtoMessage() {} + +func (x *CELFunctionArgument) ProtoReflect() protoreflect.Message { + mi := &file_grpc_federation_plugin_proto_msgTypes[4] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CELFunctionArgument.ProtoReflect.Descriptor instead. +func (*CELFunctionArgument) Descriptor() ([]byte, []int) { + return file_grpc_federation_plugin_proto_rawDescGZIP(), []int{4} +} + +func (x *CELFunctionArgument) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *CELFunctionArgument) GetDesc() string { + if x != nil { + return x.Desc + } + return "" +} + +func (x *CELFunctionArgument) GetType() string { + if x != nil { + return x.Type + } + return "" +} + +func (x *CELFunctionArgument) GetRepeated() bool { + if x != nil { + return x.Repeated + } + return false +} + +type CELType struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Type string `protobuf:"bytes,1,opt,name=type,proto3" json:"type,omitempty"` + Desc string `protobuf:"bytes,2,opt,name=desc,proto3" json:"desc,omitempty"` + Repeated bool `protobuf:"varint,3,opt,name=repeated,proto3" json:"repeated,omitempty"` +} + +func (x *CELType) Reset() { + *x = CELType{} + if protoimpl.UnsafeEnabled { + mi := &file_grpc_federation_plugin_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *CELType) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CELType) ProtoMessage() {} + +func (x *CELType) ProtoReflect() protoreflect.Message { + mi := &file_grpc_federation_plugin_proto_msgTypes[5] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CELType.ProtoReflect.Descriptor instead. +func (*CELType) Descriptor() ([]byte, []int) { + return file_grpc_federation_plugin_proto_rawDescGZIP(), []int{5} +} + +func (x *CELType) GetType() string { + if x != nil { + return x.Type + } + return "" +} + +func (x *CELType) GetDesc() string { + if x != nil { + return x.Desc + } + return "" +} + +func (x *CELType) GetRepeated() bool { + if x != nil { + return x.Repeated + } + return false +} + +type CELVariable struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` + Desc string `protobuf:"bytes,2,opt,name=desc,proto3" json:"desc,omitempty"` + Type string `protobuf:"bytes,3,opt,name=type,proto3" json:"type,omitempty"` +} + +func (x *CELVariable) Reset() { + *x = CELVariable{} + if protoimpl.UnsafeEnabled { + mi := &file_grpc_federation_plugin_proto_msgTypes[6] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *CELVariable) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CELVariable) ProtoMessage() {} + +func (x *CELVariable) ProtoReflect() protoreflect.Message { + mi := &file_grpc_federation_plugin_proto_msgTypes[6] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CELVariable.ProtoReflect.Descriptor instead. +func (*CELVariable) Descriptor() ([]byte, []int) { + return file_grpc_federation_plugin_proto_rawDescGZIP(), []int{6} +} + +func (x *CELVariable) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *CELVariable) GetDesc() string { + if x != nil { + return x.Desc + } + return "" +} + +func (x *CELVariable) GetType() string { + if x != nil { + return x.Type + } + return "" +} + +var file_grpc_federation_plugin_proto_extTypes = []protoimpl.ExtensionInfo{ + { + ExtendedType: (*descriptorpb.FileOptions)(nil), + ExtensionType: (*PluginRule)(nil), + Field: 70000, + Name: "grpc.federation.plugin", + Tag: "bytes,70000,opt,name=plugin", + Filename: "grpc/federation/plugin.proto", + }, +} + +// Extension fields to descriptorpb.FileOptions. +var ( + // optional grpc.federation.PluginRule plugin = 70000; + E_Plugin = &file_grpc_federation_plugin_proto_extTypes[0] +) + +var File_grpc_federation_plugin_proto protoreflect.FileDescriptor + +var file_grpc_federation_plugin_proto_rawDesc = []byte{ + 0x0a, 0x1c, 0x67, 0x72, 0x70, 0x63, 0x2f, 0x66, 0x65, 0x64, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x2f, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0f, + 0x67, 0x72, 0x70, 0x63, 0x2e, 0x66, 0x65, 0x64, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x1a, + 0x20, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, + 0x2f, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x22, 0x3d, 0x0a, 0x0a, 0x50, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x52, 0x75, 0x6c, 0x65, 0x12, + 0x2f, 0x0a, 0x06, 0x65, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x17, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x66, 0x65, 0x64, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x2e, 0x45, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x52, 0x06, 0x65, 0x78, 0x70, 0x6f, 0x72, 0x74, + 0x22, 0xdd, 0x01, 0x0a, 0x06, 0x45, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x6e, + 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, + 0x12, 0x0a, 0x04, 0x64, 0x65, 0x73, 0x63, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x64, + 0x65, 0x73, 0x63, 0x12, 0x33, 0x0a, 0x05, 0x74, 0x79, 0x70, 0x65, 0x73, 0x18, 0x03, 0x20, 0x03, + 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x66, 0x65, 0x64, 0x65, 0x72, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x52, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x72, 0x54, 0x79, 0x70, + 0x65, 0x52, 0x05, 0x74, 0x79, 0x70, 0x65, 0x73, 0x12, 0x3a, 0x0a, 0x09, 0x66, 0x75, 0x6e, 0x63, + 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x67, 0x72, + 0x70, 0x63, 0x2e, 0x66, 0x65, 0x64, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x43, 0x45, + 0x4c, 0x46, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x09, 0x66, 0x75, 0x6e, 0x63, 0x74, + 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x3a, 0x0a, 0x09, 0x76, 0x61, 0x72, 0x69, 0x61, 0x62, 0x6c, 0x65, + 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x66, + 0x65, 0x64, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x43, 0x45, 0x4c, 0x56, 0x61, 0x72, + 0x69, 0x61, 0x62, 0x6c, 0x65, 0x52, 0x09, 0x76, 0x61, 0x72, 0x69, 0x61, 0x62, 0x6c, 0x65, 0x73, + 0x22, 0xa1, 0x01, 0x0a, 0x0b, 0x43, 0x45, 0x4c, 0x46, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, + 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, + 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x64, 0x65, 0x73, 0x63, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x04, 0x64, 0x65, 0x73, 0x63, 0x12, 0x38, 0x0a, 0x04, 0x61, 0x72, 0x67, 0x73, + 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x66, 0x65, + 0x64, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x43, 0x45, 0x4c, 0x46, 0x75, 0x6e, 0x63, + 0x74, 0x69, 0x6f, 0x6e, 0x41, 0x72, 0x67, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x52, 0x04, 0x61, 0x72, + 0x67, 0x73, 0x12, 0x30, 0x0a, 0x06, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x18, 0x04, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x66, 0x65, 0x64, 0x65, 0x72, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x43, 0x45, 0x4c, 0x54, 0x79, 0x70, 0x65, 0x52, 0x06, 0x72, 0x65, + 0x74, 0x75, 0x72, 0x6e, 0x22, 0x6e, 0x0a, 0x0c, 0x52, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x72, + 0x54, 0x79, 0x70, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x64, 0x65, 0x73, 0x63, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x64, 0x65, 0x73, 0x63, 0x12, 0x36, 0x0a, 0x07, + 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1c, 0x2e, + 0x67, 0x72, 0x70, 0x63, 0x2e, 0x66, 0x65, 0x64, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, + 0x43, 0x45, 0x4c, 0x46, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x07, 0x6d, 0x65, 0x74, + 0x68, 0x6f, 0x64, 0x73, 0x22, 0x6d, 0x0a, 0x13, 0x43, 0x45, 0x4c, 0x46, 0x75, 0x6e, 0x63, 0x74, + 0x69, 0x6f, 0x6e, 0x41, 0x72, 0x67, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x6e, + 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, + 0x12, 0x0a, 0x04, 0x64, 0x65, 0x73, 0x63, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x64, + 0x65, 0x73, 0x63, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x72, 0x65, 0x70, 0x65, 0x61, + 0x74, 0x65, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x72, 0x65, 0x70, 0x65, 0x61, + 0x74, 0x65, 0x64, 0x22, 0x4d, 0x0a, 0x07, 0x43, 0x45, 0x4c, 0x54, 0x79, 0x70, 0x65, 0x12, 0x12, + 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x79, + 0x70, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x64, 0x65, 0x73, 0x63, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x04, 0x64, 0x65, 0x73, 0x63, 0x12, 0x1a, 0x0a, 0x08, 0x72, 0x65, 0x70, 0x65, 0x61, 0x74, + 0x65, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x72, 0x65, 0x70, 0x65, 0x61, 0x74, + 0x65, 0x64, 0x22, 0x49, 0x0a, 0x0b, 0x43, 0x45, 0x4c, 0x56, 0x61, 0x72, 0x69, 0x61, 0x62, 0x6c, + 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x64, 0x65, 0x73, 0x63, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x04, 0x64, 0x65, 0x73, 0x63, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, + 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x3a, 0x53, 0x0a, + 0x06, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x12, 0x1c, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x46, 0x69, 0x6c, 0x65, 0x4f, 0x70, + 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0xf0, 0xa2, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, + 0x67, 0x72, 0x70, 0x63, 0x2e, 0x66, 0x65, 0x64, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, + 0x50, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x52, 0x75, 0x6c, 0x65, 0x52, 0x06, 0x70, 0x6c, 0x75, 0x67, + 0x69, 0x6e, 0x42, 0x3f, 0x5a, 0x3d, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, + 0x2f, 0x6d, 0x65, 0x72, 0x63, 0x61, 0x72, 0x69, 0x2f, 0x67, 0x72, 0x70, 0x63, 0x2d, 0x66, 0x65, + 0x64, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x67, 0x72, 0x70, 0x63, 0x2f, 0x66, 0x65, + 0x64, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x3b, 0x66, 0x65, 0x64, 0x65, 0x72, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, +} + +var ( + file_grpc_federation_plugin_proto_rawDescOnce sync.Once + file_grpc_federation_plugin_proto_rawDescData = file_grpc_federation_plugin_proto_rawDesc +) + +func file_grpc_federation_plugin_proto_rawDescGZIP() []byte { + file_grpc_federation_plugin_proto_rawDescOnce.Do(func() { + file_grpc_federation_plugin_proto_rawDescData = protoimpl.X.CompressGZIP(file_grpc_federation_plugin_proto_rawDescData) + }) + return file_grpc_federation_plugin_proto_rawDescData +} + +var file_grpc_federation_plugin_proto_msgTypes = make([]protoimpl.MessageInfo, 7) +var file_grpc_federation_plugin_proto_goTypes = []interface{}{ + (*PluginRule)(nil), // 0: grpc.federation.PluginRule + (*Export)(nil), // 1: grpc.federation.Export + (*CELFunction)(nil), // 2: grpc.federation.CELFunction + (*ReceiverType)(nil), // 3: grpc.federation.ReceiverType + (*CELFunctionArgument)(nil), // 4: grpc.federation.CELFunctionArgument + (*CELType)(nil), // 5: grpc.federation.CELType + (*CELVariable)(nil), // 6: grpc.federation.CELVariable + (*descriptorpb.FileOptions)(nil), // 7: google.protobuf.FileOptions +} +var file_grpc_federation_plugin_proto_depIdxs = []int32{ + 1, // 0: grpc.federation.PluginRule.export:type_name -> grpc.federation.Export + 3, // 1: grpc.federation.Export.types:type_name -> grpc.federation.ReceiverType + 2, // 2: grpc.federation.Export.functions:type_name -> grpc.federation.CELFunction + 6, // 3: grpc.federation.Export.variables:type_name -> grpc.federation.CELVariable + 4, // 4: grpc.federation.CELFunction.args:type_name -> grpc.federation.CELFunctionArgument + 5, // 5: grpc.federation.CELFunction.return:type_name -> grpc.federation.CELType + 2, // 6: grpc.federation.ReceiverType.methods:type_name -> grpc.federation.CELFunction + 7, // 7: grpc.federation.plugin:extendee -> google.protobuf.FileOptions + 0, // 8: grpc.federation.plugin:type_name -> grpc.federation.PluginRule + 9, // [9:9] is the sub-list for method output_type + 9, // [9:9] is the sub-list for method input_type + 8, // [8:9] is the sub-list for extension type_name + 7, // [7:8] is the sub-list for extension extendee + 0, // [0:7] is the sub-list for field type_name +} + +func init() { file_grpc_federation_plugin_proto_init() } +func file_grpc_federation_plugin_proto_init() { + if File_grpc_federation_plugin_proto != nil { + return + } + if !protoimpl.UnsafeEnabled { + file_grpc_federation_plugin_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*PluginRule); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_grpc_federation_plugin_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Export); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_grpc_federation_plugin_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*CELFunction); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_grpc_federation_plugin_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ReceiverType); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_grpc_federation_plugin_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*CELFunctionArgument); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_grpc_federation_plugin_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*CELType); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_grpc_federation_plugin_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*CELVariable); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_grpc_federation_plugin_proto_rawDesc, + NumEnums: 0, + NumMessages: 7, + NumExtensions: 1, + NumServices: 0, + }, + GoTypes: file_grpc_federation_plugin_proto_goTypes, + DependencyIndexes: file_grpc_federation_plugin_proto_depIdxs, + MessageInfos: file_grpc_federation_plugin_proto_msgTypes, + ExtensionInfos: file_grpc_federation_plugin_proto_extTypes, + }.Build() + File_grpc_federation_plugin_proto = out.File + file_grpc_federation_plugin_proto_rawDesc = nil + file_grpc_federation_plugin_proto_goTypes = nil + file_grpc_federation_plugin_proto_depIdxs = nil +} diff --git a/grpc/federation/plugin_host.go b/grpc/federation/plugin_host.go new file mode 100644 index 00000000..a61823f0 --- /dev/null +++ b/grpc/federation/plugin_host.go @@ -0,0 +1,29 @@ +//go:build !tinygo.wasm + +package federation + +type ReturnValue uint64 + +// These are dummy APIs to compile plugin SDK at host context. +func MessageToReturnValue[T any](v *T) ReturnValue { return 0 } +func StringToReturnValue(v string) ReturnValue { return 0 } +func BytesToReturnValue(v []byte) ReturnValue { return 0 } +func BoolToReturnValue(v bool) ReturnValue { return 0 } +func Int32ToReturnValue(v int32) ReturnValue { return 0 } +func Int64ToReturnValue(v int64) ReturnValue { return 0 } +func Uint32ToReturnValue(v uint32) ReturnValue { return 0 } +func Uint64ToReturnValue(v uint64) ReturnValue { return 0 } +func Float32ToReturnValue(v float32) ReturnValue { return 0 } +func Float64ToReturnValue(v float64) ReturnValue { return 0 } +func ErrorToReturnValue(err error) ReturnValue { return 0 } +func StringToPtr(s string) (uint32, uint32) { return 0, 0 } +func BytesToPtr(b []byte) (uint32, uint32) { return 0, 0 } +func StringToPtrWithAllocation(s string) (uint32, uint32) { return 0, 0 } +func BytesToPtrWithAllocation(b []byte) (uint32, uint32) { return 0, 0 } +func ToFloat64(v uint64) float64 { return 0 } +func ToFloat32(v uint32) float32 { return 0 } +func ToString(ptr, size uint32) string { return "" } +func ToMessage[T any](ptr uint32) *T { return nil } +func ToBytes(ptr, size uint32) []byte { return nil } +func FreePtr(ptr uint32) {} +func DebugLog(msg string) {} diff --git a/grpc/federation/validation.go b/grpc/federation/validation.go index dbfc7f47..19a36960 100644 --- a/grpc/federation/validation.go +++ b/grpc/federation/validation.go @@ -1,3 +1,5 @@ +//go:build !tinygo.wasm + package federation import ( diff --git a/internal/testutil/cmpopt.go b/internal/testutil/cmpopt.go index bdba7689..9a9ef966 100644 --- a/internal/testutil/cmpopt.go +++ b/internal/testutil/cmpopt.go @@ -9,7 +9,8 @@ import ( func ResolverCmpOpts() []cmp.Option { return []cmp.Option{ - cmpopts.IgnoreFields(resolver.File{}, "Messages", "Services", "Enums", "Desc"), + cmpopts.IgnoreFields(resolver.File{}, "Messages", "Services", "Enums", "Desc", "CELPlugins"), + cmpopts.IgnoreFields(resolver.Service{}, "CELPlugins"), cmpopts.IgnoreFields(resolver.Package{}, "Files"), cmpopts.IgnoreFields(resolver.Method{}, "Service"), cmpopts.IgnoreFields(resolver.Message{}, "File", "ParentMessage"), diff --git a/proto/grpc/federation/plugin.proto b/proto/grpc/federation/plugin.proto new file mode 100644 index 00000000..7956cc23 --- /dev/null +++ b/proto/grpc/federation/plugin.proto @@ -0,0 +1,55 @@ +syntax = "proto3"; + +package grpc.federation; + +import "google/protobuf/descriptor.proto"; + +option go_package = "github.com/mercari/grpc-federation/grpc/federation;federation"; + +extend google.protobuf.FileOptions { + PluginRule plugin = 70000; +} + +message PluginRule { + Export export = 1; +} + +message Export { + string name = 1; + string desc = 2; + repeated ReceiverType types = 3; + repeated CELFunction functions = 4; + repeated CELVariable variables = 5; +} + +message CELFunction { + string name = 1; + string desc = 2; + repeated CELFunctionArgument args = 3; + CELType return = 4; +} + +message ReceiverType { + string name = 1; + string desc = 2; + repeated CELFunction methods = 3; +} + +message CELFunctionArgument { + string name = 1; + string desc = 2; + string type = 3; + bool repeated = 4; +} + +message CELType { + string type = 1; + string desc = 2; + bool repeated = 3; +} + +message CELVariable { + string name = 1; + string desc = 2; + string type = 3; +} diff --git a/resolver/cel.go b/resolver/cel.go index 15b6f931..d73d8a67 100644 --- a/resolver/cel.go +++ b/resolver/cel.go @@ -5,6 +5,7 @@ import ( "github.com/google/cel-go/cel" celtypes "github.com/google/cel-go/common/types" + "github.com/google/cel-go/common/types/ref" "google.golang.org/protobuf/reflect/protodesc" "google.golang.org/protobuf/types/descriptorpb" @@ -140,3 +141,40 @@ func NewCELStandardLibraryMessageType(pkgName, msgName string) *Type { }, } } + +func (plugin *CELPlugin) LibraryName() string { + return plugin.Name +} + +func (f *CELFunction) CELArgs() []*cel.Type { + ret := make([]*cel.Type, 0, len(f.Args)) + for _, arg := range f.Args { + ret = append(ret, ToCELType(arg)) + } + return ret +} + +func (f *CELFunction) CELReturn() *cel.Type { + return ToCELType(f.Return) +} + +func (plugin *CELPlugin) CompileOptions() []cel.EnvOption { + var opts []cel.EnvOption + for _, fn := range plugin.Functions { + var ( + overload cel.FunctionOpt + bindFunc = cel.FunctionBinding(func(args ...ref.Val) ref.Val { return nil }) + ) + if fn.Receiver != nil { + overload = cel.MemberOverload(fn.ID, fn.CELArgs(), fn.CELReturn(), bindFunc) + } else { + overload = cel.Overload(fn.ID, fn.CELArgs(), fn.CELReturn(), bindFunc) + } + opts = append(opts, cel.Function(fn.Name, overload)) + } + return opts +} + +func (plugin *CELPlugin) ProgramOptions() []cel.ProgramOption { + return []cel.ProgramOption{} +} diff --git a/resolver/context.go b/resolver/context.go index 6b795431..26a6c03c 100644 --- a/resolver/context.go +++ b/resolver/context.go @@ -1,19 +1,23 @@ package resolver type context struct { - errorBuilder *errorBuilder - allWarnings *allWarnings - fileRef *File - svc *Service - mtd *Method - msg *Message - enum *Enum - owner *VariableDefinitionOwner - defIdx int - depIdx int - argIdx int - errDetailIdx int - variableMap map[string]*VariableDefinition + errorBuilder *errorBuilder + allWarnings *allWarnings + fileRef *File + svc *Service + mtd *Method + msg *Message + enum *Enum + owner *VariableDefinitionOwner + plugin *CELPlugin + defIdx int + depIdx int + argIdx int + errDetailIdx int + pluginTypeIdx int + pluginFunctionIdx int + isPluginMethod bool + variableMap map[string]*VariableDefinition } type allWarnings struct { @@ -30,17 +34,22 @@ func newContext() *context { func (c *context) clone() *context { return &context{ - errorBuilder: c.errorBuilder, - allWarnings: c.allWarnings, - fileRef: c.fileRef, - svc: c.svc, - mtd: c.mtd, - msg: c.msg, - enum: c.enum, - owner: c.owner, - defIdx: c.defIdx, - depIdx: c.depIdx, - argIdx: c.argIdx, + errorBuilder: c.errorBuilder, + allWarnings: c.allWarnings, + fileRef: c.fileRef, + svc: c.svc, + mtd: c.mtd, + msg: c.msg, + enum: c.enum, + owner: c.owner, + plugin: c.plugin, + defIdx: c.defIdx, + depIdx: c.depIdx, + argIdx: c.argIdx, + pluginTypeIdx: c.pluginTypeIdx, + pluginFunctionIdx: c.pluginFunctionIdx, + isPluginMethod: c.isPluginMethod, + errDetailIdx: c.errDetailIdx, variableMap: c.variableMap, } @@ -100,6 +109,30 @@ func (c *context) withDefIndex(idx int) *context { return ctx } +func (c *context) withPlugin(plugin *CELPlugin) *context { + ctx := c.clone() + ctx.plugin = plugin + return ctx +} + +func (c *context) withPluginTypeIndex(idx int) *context { + ctx := c.clone() + ctx.pluginTypeIdx = idx + return ctx +} + +func (c *context) withPluginFunctionIndex(idx int) *context { + ctx := c.clone() + ctx.pluginFunctionIdx = idx + return ctx +} + +func (c *context) withPluginIsMethod(v bool) *context { + ctx := c.clone() + ctx.isPluginMethod = v + return ctx +} + func (c *context) withErrDetailIndex(idx int) *context { ctx := c.clone() ctx.errDetailIdx = idx @@ -123,6 +156,13 @@ func (c *context) file() *File { return c.fileRef } +func (c *context) pluginName() string { + if c.plugin == nil { + return "" + } + return c.plugin.Name +} + func (c *context) fileName() string { if c.fileRef == nil { return "" @@ -174,6 +214,18 @@ func (c *context) argIndex() int { return c.argIdx } +func (c *context) pluginTypeIndex() int { + return c.pluginTypeIdx +} + +func (c *context) pluginFunctionIndex() int { + return c.pluginFunctionIdx +} + +func (c *context) pluginIsMethod() bool { + return c.isPluginMethod +} + func (c *context) errDetailIndex() int { return c.errDetailIdx } diff --git a/resolver/resolver.go b/resolver/resolver.go index c840a262..2aed122a 100644 --- a/resolver/resolver.go +++ b/resolver/resolver.go @@ -26,6 +26,7 @@ type Resolver struct { defToFileMap map[*descriptorpb.FileDescriptorProto]*File protoPackageNameToFileDefs map[string][]*descriptorpb.FileDescriptorProto protoPackageNameToPackage map[string]*Package + celPluginMap map[string]*CELPlugin serviceToRuleMap map[*Service]*federation.ServiceRule methodToRuleMap map[*Method]*federation.MethodRule @@ -49,6 +50,7 @@ func New(files []*descriptorpb.FileDescriptorProto) *Resolver { defToFileMap: make(map[*descriptorpb.FileDescriptorProto]*File), protoPackageNameToFileDefs: make(map[string][]*descriptorpb.FileDescriptorProto), protoPackageNameToPackage: make(map[string]*Package), + celPluginMap: make(map[string]*CELPlugin), serviceToRuleMap: make(map[*Service]*federation.ServiceRule), methodToRuleMap: make(map[*Method]*federation.MethodRule), @@ -214,7 +216,7 @@ func (r *Resolver) validateServiceFromFiles(ctx *context, files []*File) { func (r *Resolver) resultFiles(allFiles []*File) []*File { fileMap := make(map[*File]struct{}) ret := make([]*File, 0, len(allFiles)) - for _, file := range r.hasServiceRuleFiles(allFiles) { + for _, file := range r.hasServiceOrPluginRuleFiles(allFiles) { ret = append(ret, file) fileMap[file] = struct{}{} @@ -229,10 +231,13 @@ func (r *Resolver) resultFiles(allFiles []*File) []*File { return ret } -func (r *Resolver) hasServiceRuleFiles(files []*File) []*File { +func (r *Resolver) hasServiceOrPluginRuleFiles(files []*File) []*File { var ret []*File for _, file := range files { - if file.HasServiceWithRule() { + switch { + case file.HasServiceWithRule(): + ret = append(ret, file) + case len(file.CELPlugins) != 0: ret = append(ret, file) } } @@ -297,6 +302,21 @@ func (r *Resolver) validateMethodResponse(ctx *context, service *Service) { func (r *Resolver) resolveFile(ctx *context, def *descriptorpb.FileDescriptorProto) *File { file := r.defToFileMap[def] ctx = ctx.withFile(file) + pluginRuleDef, err := getExtensionRule[*federation.PluginRule](def.GetOptions(), federation.E_Plugin) + if err != nil { + ctx.addError( + ErrWithLocation( + err.Error(), + source.FileLocation(ctx.fileName()), + ), + ) + } + if pluginRuleDef != nil { + if plugin := r.resolveCELPlugin(ctx, def, pluginRuleDef.Export); plugin != nil { + file.CELPlugins = append(file.CELPlugins, plugin) + } + } + for _, serviceDef := range def.GetService() { service := r.resolveService(ctx, file.Package, serviceDef.GetName()) if service == nil { @@ -317,6 +337,168 @@ func (r *Resolver) resolveFile(ctx *context, def *descriptorpb.FileDescriptorPro return file } +func (r *Resolver) resolveCELPlugin(ctx *context, fileDef *descriptorpb.FileDescriptorProto, def *federation.Export) *CELPlugin { + if def == nil { + return nil + } + pkgName := fileDef.GetPackage() + plugin := &CELPlugin{Name: def.GetName()} + ctx = ctx.withPlugin(plugin) + for idx, fn := range def.GetFunctions() { + pluginFunc := r.resolvePluginGlobalFunction(ctx.withPluginFunctionIndex(idx), pkgName, fn) + if pluginFunc == nil { + continue + } + plugin.Functions = append(plugin.Functions, pluginFunc) + } + for idx, msgType := range def.GetTypes() { + ctx := ctx.withPluginTypeIndex(idx) + msg, err := r.resolveMessageByName(ctx, msgType.GetName()) + if err != nil { + ctx.addError( + ErrWithLocation( + err.Error(), + source.PluginTypeNameLocation(ctx.fileName(), plugin.Name, idx), + ), + ) + continue + } + for idx, fn := range msgType.GetMethods() { + pluginFunc := r.resolvePluginMethod(ctx.withPluginIsMethod(true).withPluginFunctionIndex(idx), msg, fn) + if pluginFunc == nil { + continue + } + plugin.Functions = append(plugin.Functions, pluginFunc) + } + } + r.celPluginMap[def.GetName()] = plugin + return plugin +} + +func (r *Resolver) resolvePluginMethod(ctx *context, msg *Message, fn *federation.CELFunction) *CELFunction { + msgType := NewMessageType(msg, false) + pluginFunc := &CELFunction{ + Name: fn.GetName(), + Receiver: msg, + Args: []*Type{msgType}, + } + args, ret := r.resolvePluginFunctionArgumentsAndReturn(ctx, fn.GetArgs(), fn.GetReturn()) + pluginFunc.Args = append(pluginFunc.Args, args...) + pluginFunc.Return = ret + pluginFunc.ID = r.toPluginFunctionID(fmt.Sprintf("%s_%s", msg.FQDN(), fn.GetName()), append(pluginFunc.Args, pluginFunc.Return)) + return pluginFunc +} + +func (r *Resolver) resolvePluginGlobalFunction(ctx *context, pkgName string, fn *federation.CELFunction) *CELFunction { + pluginFunc := &CELFunction{ + Name: fmt.Sprintf("%s.%s", pkgName, fn.GetName()), + } + args, ret := r.resolvePluginFunctionArgumentsAndReturn(ctx, fn.GetArgs(), fn.GetReturn()) + pluginFunc.Args = append(pluginFunc.Args, args...) + pluginFunc.Return = ret + pluginFunc.ID = r.toPluginFunctionID(fmt.Sprintf("%s_%s", pkgName, fn.GetName()), append(pluginFunc.Args, pluginFunc.Return)) + return pluginFunc +} + +func (r *Resolver) resolvePluginFunctionArgumentsAndReturn(ctx *context, args []*federation.CELFunctionArgument, ret *federation.CELType) ([]*Type, *Type) { + argTypes := r.resolvePluginFunctionArguments(ctx, args) + if ret == nil { + return argTypes, nil + } + retType, err := r.resolvePluginFunctionType(ctx, ret.GetType(), ret.GetRepeated()) + if err != nil { + if ctx.pluginIsMethod() { + ctx.addError( + ErrWithLocation( + err.Error(), + source.PluginMethodReturnTypeLocation( + ctx.fileName(), + ctx.pluginName(), + ctx.pluginTypeIndex(), + ctx.pluginFunctionIndex(), + ), + ), + ) + } else { + ctx.addError( + ErrWithLocation( + err.Error(), + source.PluginFunctionReturnTypeLocation( + ctx.fileName(), + ctx.pluginName(), + ctx.pluginFunctionIndex(), + ), + ), + ) + } + } + return argTypes, retType +} + +func (r *Resolver) resolvePluginFunctionArguments(ctx *context, args []*federation.CELFunctionArgument) []*Type { + var ret []*Type + for argIdx, arg := range args { + typ, err := r.resolvePluginFunctionType(ctx, arg.GetType(), arg.GetRepeated()) + if err != nil { + if ctx.pluginIsMethod() { + ctx.addError( + ErrWithLocation( + err.Error(), + source.PluginMethodArgumentTypeLocation( + ctx.fileName(), + ctx.pluginName(), + ctx.pluginTypeIndex(), + ctx.pluginFunctionIndex(), + argIdx, + ), + ), + ) + } else { + ctx.addError( + ErrWithLocation( + err.Error(), + source.PluginFunctionArgumentTypeLocation( + ctx.fileName(), + ctx.pluginName(), + ctx.pluginFunctionIndex(), + argIdx, + ), + ), + ) + } + continue + } + ret = append(ret, typ) + } + return ret +} + +func (r *Resolver) resolvePluginFunctionType(ctx *context, typeName string, repeated bool) (*Type, error) { + var label descriptorpb.FieldDescriptorProto_Label + if repeated { + label = descriptorpb.FieldDescriptorProto_LABEL_REPEATED + } else { + label = descriptorpb.FieldDescriptorProto_LABEL_REQUIRED + } + kind := types.ToKind(typeName) + if kind == types.Unknown { + // TODO: do not consider enums at first. + kind = types.Message + } + return r.resolveType(ctx, typeName, kind, label) +} + +func (r *Resolver) toPluginFunctionID(prefix string, t []*Type) string { + var typeNames []string + for _, tt := range t { + if tt == nil { + continue + } + typeNames = append(typeNames, tt.FQDN()) + } + return strings.ReplaceAll(strings.Join(append([]string{prefix}, typeNames...), "_"), ".", "_") +} + func (r *Resolver) resolveService(ctx *context, pkg *Package, name string) *Service { fqdn := fmt.Sprintf("%s.%s", pkg.Name, name) cachedService, exists := r.cachedServiceMap[fqdn] @@ -343,10 +525,18 @@ func (r *Resolver) resolveService(ctx *context, pkg *Package, name string) *Serv ) return nil } + plugins := make([]*CELPlugin, 0, len(r.celPluginMap)) + for _, plugin := range r.celPluginMap { + plugins = append(plugins, plugin) + } + sort.Slice(plugins, func(i, j int) bool { + return plugins[i].Name < plugins[j].Name + }) service := &Service{ - File: file, - Name: name, - Methods: make([]*Method, 0, len(serviceDef.GetMethod())), + File: file, + Name: name, + Methods: make([]*Method, 0, len(serviceDef.GetMethod())), + CELPlugins: plugins, } r.serviceToRuleMap[service] = ruleDef ctx = ctx.withService(service) @@ -1484,8 +1674,8 @@ func (r *Resolver) resolveFieldRuleByAutoAlias(ctx *context, msg *Message, field ErrWithLocation( fmt.Sprintf( `The types of %q's %q field (%q) and %q's field (%q) are different. This field cannot be resolved automatically, so you must use the "grpc.federation.field" option to bind it yourself`, - msg.FQDN(), field.Name, types.ToString(field.Type.Kind), - msgAlias.FQDN(), types.ToString(aliasField.Type.Kind), + msg.FQDN(), field.Name, field.Type.Kind.ToString(), + msgAlias.FQDN(), aliasField.Type.Kind.ToString(), ), source.MessageFieldLocation(ctx.fileName(), ctx.messageName(), field.Name), ), @@ -1527,8 +1717,8 @@ func (r *Resolver) resolveFieldAlias(ctx *context, msg *Message, field *Field, f ErrWithLocation( fmt.Sprintf( `The types of %q's %q field (%q) and %q's field (%q) are different. This field cannot be resolved automatically, so you must use the "grpc.federation.field" option to bind it yourself`, - msg.FQDN(), field.Name, types.ToString(field.Type.Kind), - msgAlias.FQDN(), types.ToString(aliasField.Type.Kind), + msg.FQDN(), field.Name, field.Type.Kind.ToString(), + msgAlias.FQDN(), aliasField.Type.Kind.ToString(), ), source.MessageFieldLocation(ctx.fileName(), ctx.messageName(), field.Name), ), @@ -1656,7 +1846,7 @@ func (r *Resolver) resolveFields(ctx *context, fieldsDef []*descriptorpb.FieldDe } func (r *Resolver) resolveField(ctx *context, fieldDef *descriptorpb.FieldDescriptorProto, oneofs []*Oneof) *Field { - typ, err := r.resolveType(ctx, fieldDef.GetTypeName(), fieldDef.GetType(), fieldDef.GetLabel()) + typ, err := r.resolveType(ctx, fieldDef.GetTypeName(), types.Kind(fieldDef.GetType()), fieldDef.GetLabel()) if err != nil { ctx.addError( ErrWithLocation( @@ -2290,7 +2480,7 @@ func (r *Resolver) resolveMessageCELValues(ctx *context, env *cel.Env, msg *Mess if varDef.If.Out.Kind != types.Bool { ctx.addError( ErrWithLocation( - fmt.Sprintf(`return value of "if" must be bool type but got %s type`, varDef.If.Out.Kind), + fmt.Sprintf(`return value of "if" must be bool type but got %s type`, varDef.If.Out.Kind.ToString()), source.VariableDefinitionIfLocation( msg.File.Name, msg.Name, @@ -2361,7 +2551,7 @@ func (r *Resolver) resolveMessageCELValues(ctx *context, env *cel.Env, msg *Mess if oneof.If.Out.Kind != types.Bool { ctx.addError( ErrWithLocation( - fmt.Sprintf(`return value of "if" must be bool type but got %s type`, oneof.If.Out.Kind), + fmt.Sprintf(`return value of "if" must be bool type but got %s type`, oneof.If.Out.Kind.ToString()), source.MessageFieldOneofIfLocation( msg.File.Name, msg.Name, @@ -2803,6 +2993,9 @@ func (r *Resolver) createCELEnv(msg *Message) (*cel.Env, error) { cel.CustomTypeAdapter(r.celRegistry), cel.CustomTypeProvider(r.celRegistry), } + for _, plugin := range r.celPluginMap { + envOpts = append(envOpts, cel.Lib(plugin)) + } if msg.Rule != nil && msg.Rule.MessageArgument != nil { envOpts = append(envOpts, cel.Variable(federation.MessageArgumentVariableName, cel.ObjectType(msg.Rule.MessageArgument.FQDN()))) @@ -2902,7 +3095,7 @@ func (r *Resolver) messageArgumentFileDescriptor(arg *Message) *descriptorpb.Fil if field.Type.Repeated { label = descriptorpb.FieldDescriptorProto_LABEL_REPEATED } - kind := field.Type.Kind + kind := descriptorpb.FieldDescriptorProto_Type(field.Type.Kind) msg.Field = append(msg.Field, &descriptorpb.FieldDescriptorProto{ Name: proto.String(field.Name), Number: proto.Int32(int32(idx) + 1), diff --git a/resolver/types.go b/resolver/types.go index eb99c89e..6dc3591e 100644 --- a/resolver/types.go +++ b/resolver/types.go @@ -15,14 +15,29 @@ type Package struct { Files Files } -type File struct { - Package *Package - GoPackage *GoPackage +type CELPlugin struct { Name string - Desc *descriptorpb.FileDescriptorProto - Services []*Service - Messages []*Message - Enums []*Enum + Desc string + Functions []*CELFunction +} + +type CELFunction struct { + Name string + ID string + Args []*Type + Return *Type + Receiver *Message +} + +type File struct { + Package *Package + GoPackage *GoPackage + Name string + Desc *descriptorpb.FileDescriptorProto + Services []*Service + Messages []*Message + Enums []*Enum + CELPlugins []*CELPlugin } type Files []*File @@ -40,6 +55,7 @@ type Service struct { Rule *ServiceRule Messages []*Message MessageArgs []*Message + CELPlugins []*CELPlugin } type Method struct { @@ -369,7 +385,7 @@ func (t *Type) FQDN() string { if t.Enum != nil { return repeated + t.Enum.FQDN() } - return repeated + types.ToString(t.Kind) + return repeated + t.Kind.ToString() } type MethodCall struct { diff --git a/source/location.go b/source/location.go index 578bf118..fb6ded77 100644 --- a/source/location.go +++ b/source/location.go @@ -3,12 +3,43 @@ package source // Location represents semantic location information for grpc federation option. type Location struct { FileName string + Export *Export GoPackage bool Service *Service Message *Message Enum *Enum } +type Export struct { + Name string + Wasm *Wasm + Types *PluginType + Functions *PluginFunction +} + +type Wasm struct { + URL bool + Sha256 bool +} + +type PluginType struct { + Idx int + Name bool + Methods *PluginFunction +} + +type PluginFunction struct { + Idx int + Name bool + Args *PluginFunctionArgument + ReturnType bool +} + +type PluginFunctionArgument struct { + Idx int + Type bool +} + // Service represents service location. type Service struct { Name string @@ -250,6 +281,88 @@ func GoPackageLocation(fileName string) *Location { } } +// PluginTypeNameLocation creates location for export.types[*].name option. +func PluginTypeNameLocation(fileName, pluginName string, idx int) *Location { + return &Location{ + FileName: fileName, + Export: &Export{ + Name: pluginName, + Types: &PluginType{ + Idx: idx, + Name: true, + }, + }, + } +} + +// PluginMethodArgumentTypeLocation creates location for export.types[*].methods[*].args[*].type option. +func PluginMethodArgumentTypeLocation(fileName, pluginName string, typeIdx, methodIdx, argIdx int) *Location { + return &Location{ + FileName: fileName, + Export: &Export{ + Name: pluginName, + Types: &PluginType{ + Idx: typeIdx, + Methods: &PluginFunction{ + Idx: methodIdx, + Args: &PluginFunctionArgument{ + Idx: argIdx, + Type: true, + }, + }, + }, + }, + } +} + +// PluginFunctionArgumentTypeLocation creates location for export.functions[*].args[*].type option. +func PluginFunctionArgumentTypeLocation(fileName, pluginName string, funcIdx, argIdx int) *Location { + return &Location{ + FileName: fileName, + Export: &Export{ + Name: pluginName, + Functions: &PluginFunction{ + Idx: funcIdx, + Args: &PluginFunctionArgument{ + Idx: argIdx, + Type: true, + }, + }, + }, + } +} + +// PluginMethodReturnTypeLocation creates location for export.types[*].methods[*].return.type option. +func PluginMethodReturnTypeLocation(fileName, pluginName string, typeIdx, methodIdx int) *Location { + return &Location{ + FileName: fileName, + Export: &Export{ + Name: pluginName, + Types: &PluginType{ + Idx: typeIdx, + Methods: &PluginFunction{ + Idx: methodIdx, + ReturnType: true, + }, + }, + }, + } +} + +// PluginFunctionReturnTypeLocation creates location for export.functions[*].return.type option. +func PluginFunctionReturnTypeLocation(fileName, pluginName string, funcIdx int) *Location { + return &Location{ + FileName: fileName, + Export: &Export{ + Name: pluginName, + Functions: &PluginFunction{ + Idx: funcIdx, + ReturnType: true, + }, + }, + } +} + // ServiceLocation creates location for service name. func ServiceLocation(fileName, svcName string) *Location { return &Location{ diff --git a/types/types.go b/types/types.go index 68e87956..ae714a62 100644 --- a/types/types.go +++ b/types/types.go @@ -2,31 +2,32 @@ package types import "google.golang.org/protobuf/types/descriptorpb" -type Kind = descriptorpb.FieldDescriptorProto_Type +type Kind int var ( - Double = descriptorpb.FieldDescriptorProto_TYPE_DOUBLE - Float = descriptorpb.FieldDescriptorProto_TYPE_FLOAT - Int64 = descriptorpb.FieldDescriptorProto_TYPE_INT64 - Uint64 = descriptorpb.FieldDescriptorProto_TYPE_UINT64 - Int32 = descriptorpb.FieldDescriptorProto_TYPE_INT32 - Fixed64 = descriptorpb.FieldDescriptorProto_TYPE_FIXED64 - Fixed32 = descriptorpb.FieldDescriptorProto_TYPE_FIXED32 - Bool = descriptorpb.FieldDescriptorProto_TYPE_BOOL - String = descriptorpb.FieldDescriptorProto_TYPE_STRING - Group = descriptorpb.FieldDescriptorProto_TYPE_GROUP - Message = descriptorpb.FieldDescriptorProto_TYPE_MESSAGE - Bytes = descriptorpb.FieldDescriptorProto_TYPE_BYTES - Uint32 = descriptorpb.FieldDescriptorProto_TYPE_UINT32 - Enum = descriptorpb.FieldDescriptorProto_TYPE_ENUM - Sfixed32 = descriptorpb.FieldDescriptorProto_TYPE_SFIXED32 - Sfixed64 = descriptorpb.FieldDescriptorProto_TYPE_SFIXED64 - Sint32 = descriptorpb.FieldDescriptorProto_TYPE_SINT32 - Sint64 = descriptorpb.FieldDescriptorProto_TYPE_SINT64 + Unknown Kind = -1 + Double = Kind(descriptorpb.FieldDescriptorProto_TYPE_DOUBLE) + Float = Kind(descriptorpb.FieldDescriptorProto_TYPE_FLOAT) + Int64 = Kind(descriptorpb.FieldDescriptorProto_TYPE_INT64) + Uint64 = Kind(descriptorpb.FieldDescriptorProto_TYPE_UINT64) + Int32 = Kind(descriptorpb.FieldDescriptorProto_TYPE_INT32) + Fixed64 = Kind(descriptorpb.FieldDescriptorProto_TYPE_FIXED64) + Fixed32 = Kind(descriptorpb.FieldDescriptorProto_TYPE_FIXED32) + Bool = Kind(descriptorpb.FieldDescriptorProto_TYPE_BOOL) + String = Kind(descriptorpb.FieldDescriptorProto_TYPE_STRING) + Group = Kind(descriptorpb.FieldDescriptorProto_TYPE_GROUP) + Message = Kind(descriptorpb.FieldDescriptorProto_TYPE_MESSAGE) + Bytes = Kind(descriptorpb.FieldDescriptorProto_TYPE_BYTES) + Uint32 = Kind(descriptorpb.FieldDescriptorProto_TYPE_UINT32) + Enum = Kind(descriptorpb.FieldDescriptorProto_TYPE_ENUM) + Sfixed32 = Kind(descriptorpb.FieldDescriptorProto_TYPE_SFIXED32) + Sfixed64 = Kind(descriptorpb.FieldDescriptorProto_TYPE_SFIXED64) + Sint32 = Kind(descriptorpb.FieldDescriptorProto_TYPE_SINT32) + Sint64 = Kind(descriptorpb.FieldDescriptorProto_TYPE_SINT64) ) -func ToString(kind Kind) string { - switch kind { +func (k Kind) ToString() string { + switch k { case Double: return "double" case Float: @@ -66,3 +67,41 @@ func ToString(kind Kind) string { } return "" } + +func ToKind(s string) Kind { + switch s { + case "double": + return Double + case "float": + return Float + case "int64": + return Int64 + case "uint64": + return Uint64 + case "int32": + return Int32 + case "fixed64": + return Fixed64 + case "fixed32": + return Fixed32 + case "bool": + return Bool + case "string": + return String + case "group": + return Group + case "bytes": + return Bytes + case "uint32": + return Uint32 + case "sfixed32": + return Sfixed32 + case "sfixed64": + return Sfixed64 + case "sint32": + return Sint32 + case "sint64": + return Sint64 + } + return Unknown +}