|
| 1 | +defmodule Sidecar.GRPC.Generators.GRPCWithCustomOptions do |
| 2 | + # ref: https://github.com/elixir-protobuf/protobuf/blob/main/lib/protobuf/protoc/generator/grpc.ex |
| 3 | + @moduledoc """ |
| 4 | + Plugin to Generate gRPC code from protbuf service definitions, this plugin outputs any extension options |
| 5 | + on service methods as a param to [`GRPC.Service.rpc/4`](https://github.com/drowzy/grpc/blob/grpc_transcoding/lib/grpc/service.ex#L56) |
| 6 | + """ |
| 7 | + |
| 8 | + @behaviour ProtobufGenerate.Plugin |
| 9 | + |
| 10 | + alias Protobuf.Protoc.Generator.Util |
| 11 | + |
| 12 | + @impl true |
| 13 | + def template do |
| 14 | + """ |
| 15 | + defmodule <%= @module %>.Service do |
| 16 | + use GRPC.Service, name: <%= inspect(@service_name) %>, protoc_gen_elixir_version: "<%= @version %>" |
| 17 | +
|
| 18 | + <%= if @descriptor_fun_body do %> |
| 19 | + def descriptor do |
| 20 | + # credo:disable-for-next-line |
| 21 | + <%= @descriptor_fun_body %> |
| 22 | + end |
| 23 | + <% end %> |
| 24 | +
|
| 25 | + <%= for {method_name, input, output, options} <- @methods do %> |
| 26 | + rpc :<%= method_name %>, <%= input %>, <%= output %>, <%= options %> |
| 27 | + <% end %> |
| 28 | + end |
| 29 | +
|
| 30 | + defmodule <%= @module %>.Stub do |
| 31 | + use GRPC.Stub, service: <%= @module %>.Service |
| 32 | + end |
| 33 | + """ |
| 34 | + end |
| 35 | + |
| 36 | + @impl true |
| 37 | + def generate(ctx, %Google.Protobuf.FileDescriptorProto{service: svcs} = desc) do |
| 38 | + for svc <- svcs do |
| 39 | + mod_name = Util.mod_name(ctx, [Macro.camelize(svc.name)]) |
| 40 | + name = Util.prepend_package_prefix(ctx.package, svc.name) |
| 41 | + |
| 42 | + descriptor_fun_body = |
| 43 | + if ctx.gen_descriptors? do |
| 44 | + Util.descriptor_fun_body(desc) |
| 45 | + else |
| 46 | + nil |
| 47 | + end |
| 48 | + |
| 49 | + methods = |
| 50 | + for m <- svc.method do |
| 51 | + input = service_arg(Util.type_from_type_name(ctx, m.input_type), m.client_streaming) |
| 52 | + output = service_arg(Util.type_from_type_name(ctx, m.output_type), m.server_streaming) |
| 53 | + |
| 54 | + options = |
| 55 | + m.options |
| 56 | + |> opts() |
| 57 | + |> inspect(limit: :infinity) |
| 58 | + |
| 59 | + {m.name, input, output, options} |
| 60 | + end |
| 61 | + |
| 62 | + {mod_name, |
| 63 | + [ |
| 64 | + module: mod_name, |
| 65 | + service_name: name, |
| 66 | + methods: methods, |
| 67 | + descriptor_fun_body: descriptor_fun_body, |
| 68 | + version: Util.version() |
| 69 | + ]} |
| 70 | + end |
| 71 | + end |
| 72 | + |
| 73 | + defp service_arg(type, _streaming? = true), do: "stream(#{type})" |
| 74 | + defp service_arg(type, _streaming?), do: type |
| 75 | + |
| 76 | + defp opts(%Google.Protobuf.MethodOptions{__pb_extensions__: extensions}) |
| 77 | + when extensions == %{} do |
| 78 | + %{} |
| 79 | + end |
| 80 | + |
| 81 | + defp opts(%Google.Protobuf.MethodOptions{__pb_extensions__: extensions}) do |
| 82 | + for {{type, field}, value} <- extensions, into: %{} do |
| 83 | + {field, %{type: type, value: value}} |
| 84 | + end |
| 85 | + end |
| 86 | +end |
0 commit comments