diff options
| author | Melonai <einebeere@gmail.com> | 2021-05-13 02:15:50 +0200 |
|---|---|---|
| committer | Melonai <einebeere@gmail.com> | 2021-05-13 02:15:50 +0200 |
| commit | 14617077c7e348a3caa9f03224e7558beb680068 (patch) | |
| tree | 6760a57f49b9ae2336ec5792033995a0f15c6f2d /lib | |
| parent | fd9caa877db79a1436ee2bc7cd73c1c5792e5205 (diff) | |
| download | rook-14617077c7e348a3caa9f03224e7558beb680068.tar.zst rook-14617077c7e348a3caa9f03224e7558beb680068.zip | |
Manage shares through seperate unique process
Diffstat (limited to 'lib')
| -rw-r--r-- | lib/rook/application.ex | 2 | ||||
| -rw-r--r-- | lib/rook/monitors/share_monitor.ex | 34 | ||||
| -rw-r--r-- | lib/rook/share.ex | 80 | ||||
| -rw-r--r-- | lib/rook/utils/token.ex | 7 | ||||
| -rw-r--r-- | lib/rook_web/channels/share_channel.ex | 21 | ||||
| -rw-r--r-- | lib/rook_web/channels/user_socket.ex | 2 |
6 files changed, 105 insertions, 41 deletions
diff --git a/lib/rook/application.ex b/lib/rook/application.ex index c54e6d2..27879e3 100644 --- a/lib/rook/application.ex +++ b/lib/rook/application.ex @@ -15,7 +15,7 @@ defmodule Rook.Application do RookWeb.Endpoint, # Start a worker by calling: Rook.Worker.start_link(arg) # {Rook.Worker, arg} - Rook.ShareMonitor + {Registry, keys: :unique, name: Registry.Share} ] # See https://hexdocs.pm/elixir/Supervisor.html diff --git a/lib/rook/monitors/share_monitor.ex b/lib/rook/monitors/share_monitor.ex deleted file mode 100644 index 0dd1730..0000000 --- a/lib/rook/monitors/share_monitor.ex +++ /dev/null @@ -1,34 +0,0 @@ -defmodule Rook.ShareMonitor do - use GenServer - - def track(pid, token) do - GenServer.call(__MODULE__, {:track, pid, token}) - end - - def start_link(_) do - GenServer.start_link(__MODULE__, [], name: __MODULE__) - end - - def init(_) do - Process.flag(:trap_exit, true) - {:ok, {%{}, %{}}} - end - - def handle_call({:track, pid, token}, _from, {pids, channels}) do - Process.link(pid) - - {:reply, :ok, {Map.put(pids, pid, token), Map.put(channels, token, {pid, []})}} - end - - def handle_info({:EXIT, pid, _reason}, {pids, channels}) do - case Map.fetch(pids, pid) do - :error -> - {:noreply, {pids, channels}} - - {:ok, token} -> - {_, requests} = Map.fetch!(channels, token) - RookWeb.ShareChannel.handle_close(requests) - {:noreply, {Map.delete(pids, pid), Map.delete(channels, token)}} - end - end -end diff --git a/lib/rook/share.ex b/lib/rook/share.ex new file mode 100644 index 0000000..17e680a --- /dev/null +++ b/lib/rook/share.ex @@ -0,0 +1,80 @@ +defmodule Rook.Share do + use GenServer + + defmodule State do + @type t :: %__MODULE__{ + token: String.t(), + channel_pid: pid(), + requests: [String.t()] + } + + defstruct [:token, :channel_pid, requests: []] + end + + ## Client + + def init([token, channel_pid]) do + Process.flag(:trap_exit, true) + Process.link(channel_pid) + {:ok, %State{token: token, channel_pid: channel_pid}} + end + + def start(token) do + GenServer.start(__MODULE__, [token, self()], name: via(token)) + end + + def new_request(share_token, request_token) do + cast(share_token, {:new_request, request_token}) + end + + def cancel_request(share_token, request_token) do + cast(share_token, {:request_cancelled, request_token}) + end + + def close(_requests) do + # TODO: Notify requestors + :ok + end + + def get(token) do + case Registry.lookup(Registry.Share, token) do + [{pid, _}] -> pid + _ -> nil + end + end + + def exists?(token) do + get(token) != nil + end + + ## Server + + def handle_cast({:new_request, request_token}, state) do + # TODO: Check whether request exists. + %State{token: token, requests: requests} = state + notify(token, "new_request", %{request: request_token}) + {:noreply, %{state | requests: [request_token | requests]}} + end + + def handle_cast({:request_cancelled, request_token}, state) do + %State{token: token, requests: requests} = state + notify(token, "request_cancelled", %{request: request_token}) + {:noreply, %{state | requests: List.delete(requests, request_token)}} + end + + def handle_info({:EXIT, pid, reason}, state) do + if state.channel_pid == pid do + Rook.Share.close(state.requests) + end + + {:stop, reason, state} + end + + ## Helpers + + defp via(name), do: {:via, Registry, {Registry.Share, name}} + defp cast(token, params), do: GenServer.cast(via(token), params) + + defp notify(token, event, params), + do: RookWeb.Endpoint.broadcast!("share:" <> token, event, params) +end diff --git a/lib/rook/utils/token.ex b/lib/rook/utils/token.ex index 344789b..036d5dc 100644 --- a/lib/rook/utils/token.ex +++ b/lib/rook/utils/token.ex @@ -1,7 +1,12 @@ -defmodule Rook.Utils.Token do +defmodule Rook.Token do @alphabet "abcdefghijklmnopqrstuvw0123456789" + def token() do Nanoid.generate(21, @alphabet) end + + def match?(token, socket) do + token == socket.assigns[:token] + end end diff --git a/lib/rook_web/channels/share_channel.ex b/lib/rook_web/channels/share_channel.ex index 7454986..2d99d87 100644 --- a/lib/rook_web/channels/share_channel.ex +++ b/lib/rook_web/channels/share_channel.ex @@ -1,16 +1,29 @@ defmodule RookWeb.ShareChannel do use Phoenix.Channel + intercept ["new_request"] + def join("share:" <> token, _params, socket) do - if token == socket.assigns[:token] do - :ok = Rook.ShareMonitor.track(self(), token) + if Rook.Token.match?(token, socket) do + Rook.Share.start(token) {:ok, socket} else {:error, %{reason: "Wrong token."}} end end - def handle_close(_requests) do - # Notify all requests that share is gone. + def handle_in("accept_request", %{"request" => _request_token}, socket) do + # TODO: Send request accept message. + {:noreply, socket} + end + + def handle_in("accept_request", _params, _socket) do + {:error, %{reason: "No request given to accept."}} + end + + def handle_out("new_request", msg, socket) do + # TODO: Send ACK + push(socket, "new_request", msg) + {:noreply, socket} end end diff --git a/lib/rook_web/channels/user_socket.ex b/lib/rook_web/channels/user_socket.ex index a036c4a..ae82b6b 100644 --- a/lib/rook_web/channels/user_socket.ex +++ b/lib/rook_web/channels/user_socket.ex @@ -18,7 +18,7 @@ defmodule RookWeb.UserSocket do # performing token verification on connect. @impl true def connect(_params, socket, _connect_info) do - token = Rook.Utils.Token.token() + token = Rook.Token.token() {:ok, assign(socket, :token, token)} end |
