defmodule Google.Pubsub.GRPC do @moduledoc """ Google.Pubsub.GRPC is a thin wrapper around gRPC-based Google Pubsub Service. It uses [grpc package](https://hex.pm/packages/grpc) for grpc communication, and doesn't attempt to add much more to the code generated by `protoc` (mostly adding support for the pubsub emulator, token authorization, as well as some examples). ## Installation Add the following to your `mix.exs`: ```elixir def deps do [ {:goth, "~> 1.2.0"}, {:cowlib, "~> 2.9.0", override: true}, {:google_protos, "~> 0.1.0"}, {:grpc, github: "elixir-grpc/grpc", override: true}, {:google_pubsub_grpc, "~> 0.1.0"} ] end ``` """ require Logger @emulator_host_env "PUBSUB_EMULATOR_HOST" @googleapis_endpoint "pubsub.googleapis.com:443" @oath_scope "https://www.googleapis.com/auth/pubsub" @doc """ Obtains a connection (channel) with gRPC server. Authorization tokens are by default generated by Goth, but can be overriden, if so desired. ## Examples Google.Pubsub.GRPC.channel() Google.Pubsub.GRPC.channel(interceptors: [GRPC.Logger.Client]) Google.Pubsub.GRPC.channel(interceptors: [GRPC.Logger.Client, level: :info]) Google.Pubsub.GRPC.channel(accepted_compressors: [GRPC.Compressor.Gzip]) Google.Pubsub.GRPC.channel(headers: ["authorization": "my custom token"]) """ @spec channel(opts :: Keyword.t()) :: {:ok, %GRPC.Channel{}} | {:error, %GRPC.RPCError{}} def channel(opts \\ []) do opts = Keyword.merge(connect_defaults(), opts) case GRPC.Stub.connect(endpoint(), opts) do {:ok, channel} -> {:ok, channel} err -> Logger.error("Failed to connect to endpoint #{endpoint()}") err end end def full_project_id do "projects/#{project_id()}" end def full_topic_name(name) do "projects/#{project_id()}/topics/#{name}" end def full_subscription_name(name) do "projects/#{project_id()}/subscriptions/#{name}" end def stripped_name(full_name) do String.replace(full_name, ~r(^.*/), "") end defp using_pubsub_emulator? do !is_nil(System.get_env(@emulator_host_env)) end defp endpoint do case using_pubsub_emulator?() do true -> System.get_env(@emulator_host_env) false -> @googleapis_endpoint end end defp connect_defaults do case using_pubsub_emulator?() do true -> [headers: [authorization: "Dummy token"]] false -> {:ok, token} = Goth.Token.for_scope(@oath_scope) [headers: [authorization: "#{token.type} #{token.token}"], cred: %{ssl: []}] end end defp project_id do # Goth will raise on start-up if can't determine the project, so this should always work Goth.Config.get(:project_id) |> elem(1) end end