From 8cddd8e78eff6ee5f89e54813aa2a88ecadc1d15 Mon Sep 17 00:00:00 2001 From: Alek Ratzloff Date: Thu, 9 Jul 2020 14:51:33 -0700 Subject: [PATCH] Move markov to be a supervisor plugin This is probably going to be necessary to avoid race conditions in the ETS storage Signed-off-by: Alek Ratzloff --- lib/contrib/markov/bot.ex | 50 +++++++++++++++++++++++++++++++++ lib/contrib/markov/markov.ex | 54 +++++++++++++----------------------- lib/contrib/wordbot/bot.ex | 3 +- 3 files changed, 71 insertions(+), 36 deletions(-) create mode 100644 lib/contrib/markov/bot.ex diff --git a/lib/contrib/markov/bot.ex b/lib/contrib/markov/bot.ex new file mode 100644 index 0000000..0f603ff --- /dev/null +++ b/lib/contrib/markov/bot.ex @@ -0,0 +1,50 @@ +defmodule Omnibot.Contrib.Markov.Bot do + use Omnibot.Plugin + alias Omnibot.Contrib.Markov.Chain + + @impl true + def on_init(_cfg) do + # Create the markov database + path = String.to_atom(cfg()[:path]) + {:ok, db} = :dets.open_file(path, [:named_table]) + chains = :ets.new(:markov_chains, [:public]) + :dets.to_ets(db, chains) + :dets.close(db) + end + + @impl true + def on_channel_msg(_irc, channel, nick, msg) do + train(channel, nick, msg) + end + + def train(channel, user, msg) do + chain = (user_chain(channel, user) || create_user_chain(channel, user)) + |> Chain.train(msg) + true = update_user_chain(channel, user, chain) + end + + def user_chain(channel, user) do + db = state() + case :ets.lookup(db, {channel, user}) do + [] -> nil + [{{^channel, ^user}, chains}] -> chains + end + end + + def update_user_chain(channel, user, chain) do + db = state() + case user_chain(channel, user) do + nil -> :ets.insert_new(db, {{channel, user}, chain}) + chain -> :ets.insert(db, {{channel, user}, chain}) + end + end + + defp create_user_chain(channel, user) do + true = update_user_chain(channel, user, %Chain{order: cfg()[:order]}) + user_chain(channel, user) + end + + def save_chains() do + + end +end diff --git a/lib/contrib/markov/markov.ex b/lib/contrib/markov/markov.ex index eb5f4dd..ace5407 100644 --- a/lib/contrib/markov/markov.ex +++ b/lib/contrib/markov/markov.ex @@ -1,46 +1,32 @@ defmodule Omnibot.Contrib.Markov do - use Omnibot.Plugin + use Omnibot.Plugin.Base + alias Omnibot.Contrib.Markov + use Supervisor - alias Omnibot.Contrib.Markov.Chain + @default_config path: "markov", order: 2, save_every: 5 * 60 - @default_config path: "markov", order: 2 - - @impl true - def on_init(cfg) do - # Create the markov database - path = String.to_atom(cfg[:path]) - :ets.new(path, [:public]) + def start_link(opts) do + Supervisor.start_link(__MODULE__, opts[:cfg], opts) end @impl true - def on_channel_msg(_irc, channel, nick, msg) do - train(channel, nick, msg) + def init(cfg) do + children = [ + {Markov.Bot, cfg: cfg, name: Omnibot.Contrib.Markov.Bot}, + {Task, fn -> save_loop(cfg) end} + ] + Supervisor.init(children, strategy: :one_for_all) end - def train(channel, user, msg) do - chain = (user_chain(channel, user) || create_user_chain(channel, user)) - |> Chain.train(msg) - true = update_user_chain(channel, user, chain) + defp save_loop(cfg) do + save_every = cfg[:save_every] + Process.sleep(save_every * 1000) + Markov.Bot.save_chains() end - def user_chain(channel, user) do - db = state() - case :ets.lookup(db, {channel, user}) do - [] -> nil - [{{^channel, ^user}, chains}] -> chains - end - end + @impl true + def on_msg(irc, msg), do: Markov.Bot.on_msg(irc, msg) - def update_user_chain(channel, user, chain) do - db = state() - case user_chain(channel, user) do - nil -> :ets.insert_new(db, {{channel, user}, chain}) - chain -> :ets.insert(db, {{channel, user}, chain}) - end - end - - defp create_user_chain(channel, user) do - true = update_user_chain(channel, user, %Chain{order: cfg()[:order]}) - user_chain(channel, user) - end + @impl true + def on_channel_msg(irc, channel, nick, msg), do: Markov.Bot.on_channel_msg(irc, channel, nick, msg) end diff --git a/lib/contrib/wordbot/bot.ex b/lib/contrib/wordbot/bot.ex index e6002bd..ad80b1c 100644 --- a/lib/contrib/wordbot/bot.ex +++ b/lib/contrib/wordbot/bot.ex @@ -1,6 +1,5 @@ defmodule Omnibot.Contrib.Wordbot.Bot do - use Omnibot.Plugin.Base - use Omnibot.Plugin.GenServer + use Omnibot.Plugin alias Omnibot.{Contrib.Wordbot, Irc, State, Util} require Logger