about summary refs log tree commit diff
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