Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for multiple accounts #31

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from
Draft
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
21 changes: 17 additions & 4 deletions lib/kane/client.ex
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,16 @@ defmodule Kane.Client do
def delete(path, options \\ []), do: call(:delete, path, options)

defp call(method, path, options) do
headers = [auth_header()]
{goth_opts, options} = split_opts(options)
headers = [auth_header(goth_opts)]

apply(HTTPoison, method, [url(path), headers, options])
|> handle_response
end

defp call(method, path, data, options) do
headers = [auth_header(), {"content-type", "application/json"}]
{goth_opts, options} = split_opts(options)
headers = [auth_header(goth_opts), {"content-type", "application/json"}]

apply(HTTPoison, method, [url(path), encode!(data), headers, options])
|> handle_response
Expand All @@ -33,8 +35,19 @@ defmodule Kane.Client do
defp endpoint, do: Application.get_env(:kane, :endpoint, "https://pubsub.googleapis.com/v1")
defp token_mod, do: Application.get_env(:kane, :token, Goth.Token)

defp auth_header do
{:ok, token} = token_mod().for_scope(Kane.oauth_scope())
defp split_opts(options), do: Keyword.split(options, [:account, :sub])

defp auth_header(opts) do
{:ok, token} =
opts
|> Keyword.get(:account)
|> case do
nil -> token_mod().for_scope(Kane.oauth_scope(), Keyword.get(opts, :sub))
acct -> token_mod().for_scope({acct, Kane.oauth_scope()}, Keyword.get(opts, :sub))
end

# we need to call this differently depending on
# {:ok, token} = token_mod().for_scope(Kane.oauth_scope())
{"Authorization", "#{token.type} #{token.token}"}
end

Expand Down
25 changes: 17 additions & 8 deletions lib/kane/message.ex
Original file line number Diff line number Diff line change
Expand Up @@ -12,22 +12,24 @@ defmodule Kane.Message do

defstruct id: nil, attributes: %{}, data: nil, ack_id: nil, publish_time: nil

def publish(message, topic, opts \\ [])

@spec publish(binary, binary) :: {:ok, t} | Error.t()
def publish(message, topic) when is_binary(message) and is_binary(topic) do
publish(%__MODULE__{data: message}, %Topic{name: topic})
def publish(message, topic, opts) when is_binary(message) and is_binary(topic) do
publish(%__MODULE__{data: message}, %Topic{name: topic}, opts)
end

@spec publish(t, Topic.t()) :: {:ok, t} | Error.t()
def publish(%__MODULE__{} = message, %Topic{} = topic) do
case publish([message], topic) do
def publish(%__MODULE__{} = message, %Topic{} = topic, opts) do
case publish([message], topic, opts) do
{:ok, [message | _]} -> {:ok, message}
err -> err
end
end

@spec publish([t], Topic.t()) :: {:ok, [t]} | Error.t()
def publish(messages, %Topic{name: topic}) when is_list(messages) do
case Kane.Client.post(path(topic), data(messages)) do
def publish(messages, %Topic{name: topic}, opts) when is_list(messages) do
case Kane.Client.post(path(topic), data(messages), opts) do
{:ok, body, _code} ->
collected =
body
Expand Down Expand Up @@ -102,9 +104,16 @@ defmodule Kane.Message do
end

defp path(%Topic{name: topic}), do: path(topic)
defp path({project, topic}), do: "projects/#{project}/topics/#{Topic.strip!(topic)}:publish"

defp path(topic) do
{:ok, project} = Goth.Config.get(:project_id)
"projects/#{project}/topics/#{Topic.strip!(topic)}:publish"
topic
|> String.match?(~r{/})
|> if do
topic
else
{:ok, project} = Goth.Config.get(:project_id)
path({project, topic})
end
end
end
33 changes: 28 additions & 5 deletions lib/kane/subscription.ex
Original file line number Diff line number Diff line change
Expand Up @@ -111,8 +111,19 @@ defmodule Kane.Subscription do
project
end

defp find_path, do: "projects/#{project()}/subscriptions"
defp find_path(subscription), do: "#{find_path()}/#{strip!(subscription)}"
# defp find_path, do: "projects/#{project()}/subscriptions"

defp find_path({project, sub}), do: "projects/#{project}/subscriptions/#{sub}"

defp find_path(subscription) do
subscription
|> String.contains?("/")
|> if do
subscription
else
find_path({project(), subscription})
end
end

def path(%__MODULE__{name: name}, kind), do: path(name, kind)

Expand All @@ -126,12 +137,24 @@ defmodule Kane.Subscription do

def full_name(%__MODULE__{name: name}), do: full_name(name)

def full_name({project, name}), do: "projects/#{project}/subscriptions/#{name}"

def full_name(name) do
{:ok, project} = Goth.Config.get(:project_id)
"projects/#{project}/subscriptions/#{name}"
name
|> String.contains?("/")
|> if do
name
else
{:ok, project} = Goth.Config.get(:project_id)
full_name({project, name})
end
end

def strip!(name), do: String.replace(name, ~r(^#{find_path()}/?), "")
def strip!(name) do
name
|> String.split("/", trim: true)
|> List.last()
end

defp from_json(json) do
data = Jason.decode!(json)
Expand Down
27 changes: 23 additions & 4 deletions lib/kane/topic.ex
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,13 @@ defmodule Kane.Topic do
alias Kane.Client.Response.Error

@type t :: %__MODULE__{name: binary}
defstruct [:name]
defstruct [:name, :project]

@doc """
Find a topic by name. The name can be either a short name (`my-topic`)
or the fully-qualified name (`projects/my-project/topics/my-topic`)
or the fully-qualified name (`projects/my-project/topics/my-topic`).
If the short name is passed in, Kane will use `Goth` to get the default
project from you application's config (via `Goth.Config.get(:project_id)`).
"""
@spec find(String.t()) :: {:ok, t} | Error.t()
def find(name) do
Expand Down Expand Up @@ -80,7 +82,12 @@ defmodule Kane.Topic do
"my-topic"
"""
@spec strip!(String.t()) :: String.t()
def strip!(name), do: String.replace(name, ~r(^#{path()}/?), "")

def strip!(name) do
name
|> String.split("/", trim: true)
|> List.last()
end

@doc """
Adds the project and topic prefix (if necessary) to create a fully-qualified topic name
Expand All @@ -94,11 +101,23 @@ defmodule Kane.Topic do

defp with_name(name), do: %__MODULE__{name: strip!(name)}

# this should be specific to a topic, and, in fact,
# maybe we should require it to be included on the Topic itself
defp project do
{:ok, id} = Goth.Config.get(:project_id)
id
end

defp path, do: "projects/#{project()}/topics"
defp path(topic), do: "#{path()}/#{strip!(topic)}"
defp path({proj, topic}), do: "projects/#{proj}/topics/#{strip!(topic)}"

defp path(topic) do
topic
|> String.contains?("/")
|> if do
topic
else
path({project(), topic})
end
end
end
5 changes: 5 additions & 0 deletions test/kane/topic_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,11 @@ defmodule Kane.TopicTest do
test "getting full name", %{project: project} do
name = "my-topic"
assert "projects/#{project}/topics/#{name}" == %Topic{name: name} |> Topic.full_name()

assert "projects/whatever/topics/full" ==
%Topic{name: {"whatever", "full"}} |> Topic.full_name()

assert "projects/whatever/topics/mine" == Topic.full_name("projects/whatever/topics/mine")
end

test "successfully creating a topic", %{bypass: bypass} do
Expand Down
2 changes: 1 addition & 1 deletion test/test_helper.exs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ ExUnit.start()
Application.ensure_all_started(:bypass)

defmodule Kane.TestToken do
def for_scope(scope) do
def for_scope(scope, _sub \\ nil) do
{:ok,
%Goth.Token{
scope: scope,
Expand Down