Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 28 additions & 0 deletions cmd/protoc-gen-elixir-grpc/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,33 @@ defmodule Greeter.Server do
end
```

#### Custom Compressors

Specify custom compressor modules for your gRPC server:

```yaml
version: v2
plugins:
- local: protoc-gen-elixir
out: lib
- local: protoc-gen-elixir-grpc
out: lib
opt:
- compressors=GRPC.Compressor.Gzip
```

This generates:

```elixir
defmodule Greeter.Server do
use GRPC.Server,
service: Greeter.Service,
compressors: [GRPC.Compressor.Gzip]

# ... method delegates
end
```

#### Combining Options

You can combine multiple options:
Expand All @@ -123,6 +150,7 @@ plugins:
- http_transcode=true
- handler_module_prefix=MyApp.Handlers
- codecs=GRPC.Codec.Proto,GRPC.Codec.WebText,GRPC.Codec.JSON
- compressors=GRPC.Compressor.Gzip
```

### Basic Service Implementation
Expand Down
27 changes: 22 additions & 5 deletions cmd/protoc-gen-elixir-grpc/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,9 @@ const (
handlerModulePrefixFlag = "handler_module_prefix"
httpTranscodeFlag = "http_transcode"
codecsFlag = "codecs"
compressorsFlag = "compressors"

usage = "\n\nFlags:\n -h, --help\tPrint this help and exit.\n --version\tPrint the version and exit.\n --handler_module_prefix\tCustom Elixir module prefix for handler modules instead of protobuf package.\n --http_transcode\tEnable HTTP transcoding support (adds http_transcode: true to use GRPC.Server).\n --codecs\tComma-separated list of codec modules (e.g., 'GRPC.Codec.Proto,GRPC.Codec.WebText,GRPC.Codec.JSON')."
usage = "\n\nFlags:\n -h, --help\tPrint this help and exit.\n --version\tPrint the version and exit.\n --handler_module_prefix\tCustom Elixir module prefix for handler modules instead of protobuf package.\n --http_transcode\tEnable HTTP transcoding support (adds http_transcode: true to use GRPC.Server).\n --codecs\tComma-separated list of codec modules (e.g., 'GRPC.Codec.Proto,GRPC.Codec.WebText,GRPC.Codec.JSON').\n --compressors\tComma-separated list of compressor modules (e.g., 'GRPC.Compressor.Gzip')."
)

func parsePluginParameters(paramStr string, flagSet *flag.FlagSet) error {
Expand Down Expand Up @@ -178,6 +179,11 @@ func main() {
"",
"Comma-separated list of codec modules (e.g., 'GRPC.Codec.Proto,GRPC.Codec.WebText,GRPC.Codec.JSON').",
)
compressors := flagSet.String(
compressorsFlag,
"",
"Comma-separated list of compressor modules (e.g., 'GRPC.Compressor.Gzip').",
)

input, err := io.ReadAll(os.Stdin)
if err != nil {
Expand Down Expand Up @@ -214,6 +220,7 @@ func main() {
}

codecsList := parseCodecs(*codecs)
compressorsList := parseCodecs(*compressors)

for _, fileName := range req.FileToGenerate {
var protoFile *descriptorpb.FileDescriptorProto
Expand All @@ -231,7 +238,7 @@ func main() {
continue
}

generateElixirFile(resp, protoFile, *packagePrefix, *handlerModulePrefix, *httpTranscode, codecsList)
generateElixirFile(resp, protoFile, *packagePrefix, *handlerModulePrefix, *httpTranscode, codecsList, compressorsList)
}

output, err := proto.Marshal(resp)
Expand All @@ -246,7 +253,7 @@ func main() {
}
}

func generateElixirFile(resp *pluginpb.CodeGeneratorResponse, file *descriptorpb.FileDescriptorProto, packagePrefix, handlerModulePrefix string, httpTranscode bool, codecs []string) {
func generateElixirFile(resp *pluginpb.CodeGeneratorResponse, file *descriptorpb.FileDescriptorProto, packagePrefix, handlerModulePrefix string, httpTranscode bool, codecs []string, compressors []string) {
if len(file.Service) == 0 {
return
}
Expand All @@ -260,7 +267,7 @@ func generateElixirFile(resp *pluginpb.CodeGeneratorResponse, file *descriptorpb
content.WriteString("\n")

for _, service := range file.Service {
generateServiceModule(&content, file, service, handlerModulePrefix, httpTranscode, codecs)
generateServiceModule(&content, file, service, handlerModulePrefix, httpTranscode, codecs, compressors)
content.WriteString("\n")
}

Expand All @@ -270,7 +277,7 @@ func generateElixirFile(resp *pluginpb.CodeGeneratorResponse, file *descriptorpb
})
}

func generateServiceModule(content *strings.Builder, file *descriptorpb.FileDescriptorProto, service *descriptorpb.ServiceDescriptorProto, handlerModulePrefix string, httpTranscode bool, codecs []string) {
func generateServiceModule(content *strings.Builder, file *descriptorpb.FileDescriptorProto, service *descriptorpb.ServiceDescriptorProto, handlerModulePrefix string, httpTranscode bool, codecs []string, compressors []string) {
serverModuleName := generateServerModuleName(file, service)
serviceModuleName := generateServiceModuleName(file, service)

Expand All @@ -290,6 +297,16 @@ func generateServiceModule(content *strings.Builder, file *descriptorpb.FileDesc
}
content.WriteString("]")
}
if len(compressors) > 0 {
content.WriteString(",\n compressors: [")
for i, compressor := range compressors {
if i > 0 {
content.WriteString(", ")
}
content.WriteString(compressor)
}
content.WriteString("]")
}
content.WriteString("\n\n")

for _, method := range service.Method {
Expand Down
58 changes: 56 additions & 2 deletions cmd/protoc-gen-elixir-grpc/main_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -490,6 +490,59 @@ end
assert.Equal(t, expected, content)
})

t.Run("with compressors option", func(t *testing.T) {
fileDesc := &descriptorpb.FileDescriptorProto{
Name: ptr("data/v1/data.proto"),
Package: ptr("data.v1"),
MessageType: []*descriptorpb.DescriptorProto{
{Name: ptr("DataRequest")},
{Name: ptr("DataResponse")},
},
Service: []*descriptorpb.ServiceDescriptorProto{
{
Name: ptr("DataService"),
Method: []*descriptorpb.MethodDescriptorProto{
{
Name: ptr("GetData"),
InputType: ptr(".data.v1.DataRequest"),
OutputType: ptr(".data.v1.DataResponse"),
},
},
},
},
}

req := &pluginpb.CodeGeneratorRequest{
FileToGenerate: []string{"data/v1/data.proto"},
ProtoFile: []*descriptorpb.FileDescriptorProto{fileDesc},
SourceFileDescriptors: []*descriptorpb.FileDescriptorProto{fileDesc},
CompilerVersion: compilerVersion,
Parameter: ptr("compressors=GRPC.Compressor.Gzip"),
}

rsp := testGenerate(t, req)
assert.Nil(t, rsp.Error)
assert.Equal(t, 1, len(rsp.File))

file := rsp.File[0]
assert.Equal(t, "data/v1/data.server.pb.ex", file.GetName())

content := file.GetContent()
expected := `# Code generated by protoc-gen-elixir-grpc. DO NOT EDIT.
#
# Source: data/v1/data.proto

defmodule Data.V1.DataService.Server do
use GRPC.Server,
service: Data.V1.DataService.Service,
compressors: [GRPC.Compressor.Gzip]

defdelegate get_data(request, stream), to: Data.V1.DataService.Server.GetDataHandler, as: :handle_message
end
`
assert.Equal(t, expected, content)
})

t.Run("with all options combined", func(t *testing.T) {
fileDesc := &descriptorpb.FileDescriptorProto{
Name: ptr("store/v1/store.proto"),
Expand Down Expand Up @@ -517,7 +570,7 @@ end
ProtoFile: []*descriptorpb.FileDescriptorProto{fileDesc},
SourceFileDescriptors: []*descriptorpb.FileDescriptorProto{fileDesc},
CompilerVersion: compilerVersion,
Parameter: ptr("http_transcode=true,handler_module_prefix=MyApp.Business,codecs=GRPC.Codec.Proto,GRPC.Codec.JSON"),
Parameter: ptr("http_transcode=true,handler_module_prefix=MyApp.Business,codecs=GRPC.Codec.Proto,GRPC.Codec.JSON,compressors=GRPC.Compressor.Gzip"),
}

rsp := testGenerate(t, req)
Expand All @@ -536,7 +589,8 @@ defmodule Store.V1.StoreService.Server do
use GRPC.Server,
service: Store.V1.StoreService.Service,
http_transcode: true,
codecs: [GRPC.Codec.Proto, GRPC.Codec.JSON]
codecs: [GRPC.Codec.Proto, GRPC.Codec.JSON],
compressors: [GRPC.Compressor.Gzip]

defdelegate create_store(request, stream), to: MyApp.Business.Store.V1.StoreService.Server.CreateStoreHandler, as: :handle_message
end
Expand Down