diff options
author | href <href@random.sh> | 2021-01-11 15:53:02 +0100 |
---|---|---|
committer | href <href@random.sh> | 2021-01-11 15:53:02 +0100 |
commit | 0f3f0e035b43eabd3f739c41964446962cf54208 (patch) | |
tree | 9279c54e100c92375c9d980e2031e0a153245025 /lib/irc/store.ex | |
parent | Some fixes (diff) |
Cont. wipmaster
Diffstat (limited to 'lib/irc/store.ex')
-rw-r--r-- | lib/irc/store.ex | 131 |
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 |