defmodule GRPC.Service do
@moduledoc """
Define gRPC service used by Stub and Server. You should use `Protobuf` to
to generate code instead of using this module directly.
It imports DSL functions like `rpc/3` and `stream/1` for defining the RPC
functions easily:
defmodule Greeter.Service do
use GRPC.Service, name: "helloworld.Greeter"
rpc :SayHello, HelloRequest, stream(HelloReply)
end
"""
defmacro __using__(opts) do
quote do
import GRPC.Service, only: [rpc: 3, stream: 1]
Module.register_attribute(__MODULE__, :rpc_calls, accumulate: true)
@before_compile GRPC.Service
def __meta__(:name), do: unquote(opts[:name])
end
end
defmacro __before_compile__(env) do
rpc_calls = Module.get_attribute(env.module, :rpc_calls)
quote do
def __rpc_calls__, do: unquote(rpc_calls |> Macro.escape() |> Enum.reverse())
end
end
defmacro rpc(name, request, reply) do
quote do
@rpc_calls {unquote(name), unquote(wrap_stream(request)), unquote(wrap_stream(reply))}
end
end
@doc """
Specify if the request/reply is streaming.
"""
def stream(param) do
quote do: {unquote(param), true}
end
@doc false
def wrap_stream({:stream, _, _} = param) do
quote do: unquote(param)
end
def wrap_stream(param) do
quote do: {unquote(param), false}
end
def grpc_type({_, {_, false}, {_, false}}), do: :unary
def grpc_type({_, {_, true}, {_, false}}), do: :client_stream
def grpc_type({_, {_, false}, {_, true}}), do: :server_stream
def grpc_type({_, {_, true}, {_, true}}), do: :bidi_stream
end