Add Markov.ChainServer for Markov plugin
* Markov chains each have their own process keeping it updated and synchronized. The markov plugin has been upgraded to account for this. Signed-off-by: Alek Ratzloff <alekratz@gmail.com>
This commit is contained in:
86
lib/contrib/markov/chain_server.ex
Normal file
86
lib/contrib/markov/chain_server.ex
Normal file
@@ -0,0 +1,86 @@
|
||||
defmodule Omnibot.Contrib.Markov.ChainServer do
|
||||
use GenServer
|
||||
alias Omnibot.Contrib.Markov
|
||||
require Logger
|
||||
|
||||
## Client API
|
||||
|
||||
def start_link(opts) do
|
||||
{cfg, opts} = Keyword.pop(opts, :cfg)
|
||||
{channel, opts} = Keyword.pop(opts, :channel)
|
||||
{user, opts} = Keyword.pop(opts, :user)
|
||||
|
||||
chain = case load(channel, user) do
|
||||
{:ok, chain} -> chain
|
||||
{:error, _} -> %Markov.Chain{order: cfg[:order]}
|
||||
end
|
||||
GenServer.start_link(__MODULE__, {chain, channel, user}, opts)
|
||||
end
|
||||
|
||||
@compile :inline
|
||||
def user_path(channel, user), do: Path.join(channel_dir(channel), "#{user}.chain")
|
||||
|
||||
@compile :inline
|
||||
def channel_dir(channel), do: Path.join(Markov.save_dir(), channel)
|
||||
|
||||
def load(channel, user) do
|
||||
with {:ok, contents} <- user_path(channel, user) |> File.read(),
|
||||
do: {:ok, :erlang.binary_to_term(contents)}
|
||||
end
|
||||
|
||||
def save(server) do
|
||||
GenServer.call(server, :save)
|
||||
end
|
||||
|
||||
def train(server, msg) do
|
||||
GenServer.call(server, {:train, msg})
|
||||
end
|
||||
|
||||
def chain(server) do
|
||||
GenServer.call(server, :chain)
|
||||
end
|
||||
|
||||
def channel(server) do
|
||||
GenServer.call(server, :channel)
|
||||
end
|
||||
|
||||
def user(server) do
|
||||
GenServer.call(server, :user)
|
||||
end
|
||||
|
||||
## Server callbacks
|
||||
|
||||
@impl true
|
||||
def init({chain, channel, user}) do
|
||||
{:ok, {chain, channel, user}}
|
||||
end
|
||||
|
||||
@impl true
|
||||
def handle_call(:save, _from, state = {chain, channel, user}) do
|
||||
File.mkdir_p!(channel_dir(channel))
|
||||
path = user_path(channel, user)
|
||||
Logger.debug("Saving chain for #{user} on #{channel} to #{path}")
|
||||
File.write!(path, :erlang.term_to_binary(chain))
|
||||
{:reply, :ok, state}
|
||||
end
|
||||
|
||||
@impl true
|
||||
def handle_call({:train, msg}, _from, {chain, channel, user}) do
|
||||
{:reply, :ok, {Markov.Chain.train(chain, msg), channel, user}}
|
||||
end
|
||||
|
||||
@impl true
|
||||
def handle_call(:chain, _from, state = {chain, _channel, _user}) do
|
||||
{:reply, chain, state}
|
||||
end
|
||||
|
||||
@impl true
|
||||
def handle_call(:channel, _from, state = {_chain, channel, _user}) do
|
||||
{:reply, channel, state}
|
||||
end
|
||||
|
||||
@impl true
|
||||
def handle_call(:user, _from, state = {_chain, _channel, user}) do
|
||||
{:reply, user, state}
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user