aboutsummaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorMelonai <einebeere@gmail.com>2021-05-13 02:15:50 +0200
committerMelonai <einebeere@gmail.com>2021-05-13 02:15:50 +0200
commit14617077c7e348a3caa9f03224e7558beb680068 (patch)
tree6760a57f49b9ae2336ec5792033995a0f15c6f2d /lib
parentfd9caa877db79a1436ee2bc7cd73c1c5792e5205 (diff)
downloadrook-14617077c7e348a3caa9f03224e7558beb680068.tar.zst
rook-14617077c7e348a3caa9f03224e7558beb680068.zip
Manage shares through seperate unique process
Diffstat (limited to 'lib')
-rw-r--r--lib/rook/application.ex2
-rw-r--r--lib/rook/monitors/share_monitor.ex34
-rw-r--r--lib/rook/share.ex80
-rw-r--r--lib/rook/utils/token.ex7
-rw-r--r--lib/rook_web/channels/share_channel.ex21
-rw-r--r--lib/rook_web/channels/user_socket.ex2
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