summaryrefslogtreecommitdiff
path: root/lib/irc/store.ex
diff options
context:
space:
mode:
authorhref <href@random.sh>2021-01-11 15:53:02 +0100
committerhref <href@random.sh>2021-01-11 15:53:02 +0100
commit0f3f0e035b43eabd3f739c41964446962cf54208 (patch)
tree9279c54e100c92375c9d980e2031e0a153245025 /lib/irc/store.ex
parentSome fixes (diff)
Cont. wipmaster
Diffstat (limited to 'lib/irc/store.ex')
-rw-r--r--lib/irc/store.ex131
1 files changed, 131 insertions, 0 deletions
diff --git a/lib/irc/store.ex b/lib/irc/store.ex
new file mode 100644
index 0000000..5aaef6c
--- /dev/null
+++ b/lib/irc/store.ex
@@ -0,0 +1,131 @@
+defmodule Irc.Store do
+ @moduledoc """
+ Mnesia-based store for `Irc.Client`.
+
+ Tables:
+ * User (transient, in memory): tracks known connected users.
+ * Channel (transient, in memory): tracks known channels.
+
+ ## Setup
+
+ Needs to be ran only once at setup:
+
+ ```elixir
+ # First step: create schemas.
+ Memento.stop()
+ Memento.Schema.create([node()])
+ Memento.start()
+
+ # Second step: create tables
+ Irc.Store.setup()
+ ```
+
+
+ """
+
+ @doc false
+ # Childrens for Irc.Application supervisor tree
+ def childs do
+ [{Irc.Store.OwnerSweeper, []}]
+ end
+
+ @doc "Creates tables in Mnesia. Should only be run once."
+ def setup do
+ Memento.Table.create!(Irc.Store.User)
+ end
+
+ defmodule OwnerSweeper do
+ @moduledoc """
+ Ensures the Store only keeps alive data by monitoring owners and deleting entries when their owner dies.
+ """
+ use GenServer
+ require Logger
+
+ @doc "Register calling process to the `OwnerSweeper` process."
+ def register() do
+ GenServer.call(__MODULE__, {:monitor, self()})
+ end
+
+ @doc "Unregister calling process from the sweeper and delete all its entries."
+ def unregister() do
+ GenServer.call(__MODULE__, {:unregister, self()})
+ end
+
+ @doc false
+ def start_link(_) do
+ GenServer.start_link(__MODULE__, [], name: __MODULE__)
+ end
+
+ @impl true
+ @doc false
+ def init(_) do
+ {:ok, Map.new}
+ end
+
+ @impl true
+ @doc false
+ def handle_call({:register, pid}, _, monitors) do
+ if Map.get(monitors, pid) do
+ {:reply, :ok, monitors}
+ else
+ Logger.debug("Irc.Store.OwnerSweeper: added to sweep list #{inspect(pid)}")
+ monitor = Process.monitor(pid)
+ {:reply, :ok, Map.put(monitors, pid, monitor)}
+ end
+ end
+
+ @impl true
+ @doc false
+ def handle_call({:unregister, pid}, _, monitors) do
+ if ref = Map.get(monitors, pid) do
+ Process.demonitor(ref, [:flush])
+ clear_entries(pid)
+ {:reply, :ok, Map.drop(monitors, pid)}
+ else
+ {:reply, :not_registered, monitors}
+ end
+ end
+
+ @impl true
+ @doc false
+ def handle_info({:DOWN, monitor, :process, pid, _reason}, monitors) do
+ Logger.debug("Irc.Store.OwnerSweeper: removing entries of #{inspect(pid)}")
+ if monitor == Map.get(monitors, pid) do
+ # TODO: Delete all `User` entries where owner == pid
+ clear_entries(pid)
+ {:noreply, Map.drop(monitors, pid)}
+ else
+ {:noreply, monitors}
+ end
+ end
+
+ defp clear_entries(pid) do
+ # TODO: Find some way to use built in mnesia select_delete
+ for table <- [Irc.Store.User] do
+ Memento.transaction fn ->
+ for entry <- Memento.Query.select(table, {:==, :owner, pid}) do
+ Memento.delete(table, entry.id)
+ end
+ end
+ end
+ end
+
+ end
+
+
+ defmodule User do
+ #attributes = Irc.User.__attrs__
+ #|> Enum.map(fn
+ # ({k, _}) -> k
+ # k -> k
+ #end)
+
+ #IO.inspect(attributes)
+
+ #use Memento.Table,
+ # attributes: attributes,
+ # index: [:owner, :host, :nick, :account]
+
+ end
+
+end