Finish removing Omnibot.State functions
Omnibot.State shouldn't be used anywhere anymore except as a GenServer
being started up in the supervisor.
Also, configuration must be loaded through Config.load/1 rather than
being constructed, because everything expects a tuple of {plugin,
config} now.
Finally, Omnibot.Core must be added to the configuration in order for
basic functionality.
Signed-off-by: Alek Ratzloff <alekratz@gmail.com>
This commit is contained in:
@@ -87,11 +87,12 @@ defmodule Omnibot.Config do
|
|||||||
"""
|
"""
|
||||||
def all_channels(cfg) do
|
def all_channels(cfg) do
|
||||||
Enum.flat_map(cfg.plugins, fn
|
Enum.flat_map(cfg.plugins, fn
|
||||||
{_, [channels: :all]} -> []
|
{_, cfg} -> if cfg[:channels] in [nil, :all],
|
||||||
{_, [channels: channels]} -> channels
|
do: [],
|
||||||
|
else: cfg[:channels]
|
||||||
end)
|
end)
|
||||||
|> MapSet.new()
|
|> MapSet.new()
|
||||||
|> MapSet.to_list()
|
|> MapSet.to_list()
|
||||||
end
|
end
|
||||||
|
|
||||||
@doc """
|
@doc """
|
||||||
@@ -108,9 +109,9 @@ defmodule Omnibot.Config do
|
|||||||
%Omnibot.Irc.Msg.Prefix {:nick => "omnibot", :user => "omnibot", :host => nil}
|
%Omnibot.Irc.Msg.Prefix {:nick => "omnibot", :user => "omnibot", :host => nil}
|
||||||
"""
|
"""
|
||||||
def msg_prefix(cfg) do
|
def msg_prefix(cfg) do
|
||||||
%Msg.Prefix {
|
%Msg.Prefix{
|
||||||
nick: cfg.nick,
|
nick: cfg.nick,
|
||||||
user: cfg.user,
|
user: cfg.user
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -135,10 +136,29 @@ defmodule Omnibot.Config do
|
|||||||
}
|
}
|
||||||
"""
|
"""
|
||||||
def msg(cfg, command, params \\ []) do
|
def msg(cfg, command, params \\ []) do
|
||||||
%Msg {
|
%Msg{
|
||||||
prefix: msg_prefix(cfg),
|
prefix: msg_prefix(cfg),
|
||||||
command: command,
|
command: command,
|
||||||
params: params,
|
params: params
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def channel_plugins(cfg, channel) do
|
||||||
|
cfg.plugins
|
||||||
|
|> Enum.filter(fn {_plug, cf} ->
|
||||||
|
cf[:channels] == :all or channel in Keyword.get(cf, :channels, [])
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
def load(path) do
|
||||||
|
with {_, bindings} <- Code.eval_file(path) do
|
||||||
|
cfg = bindings[:config]
|
||||||
|
plugins = cfg.plugins
|
||||||
|
|> Enum.map(fn
|
||||||
|
plug when is_atom(plug) -> {plug, plug.default_config()}
|
||||||
|
{plug, cfg}-> {plug, cfg ++ plug.default_config()}
|
||||||
|
end)
|
||||||
|
%Omnibot.Config{cfg | plugins: plugins}
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
defmodule Omnibot.Irc do
|
defmodule Omnibot.Irc do
|
||||||
require Logger
|
require Logger
|
||||||
alias Omnibot.Irc.Msg
|
alias Omnibot.Irc.Msg
|
||||||
alias Omnibot.{Config, State}
|
alias Omnibot.Config
|
||||||
use GenServer
|
use GenServer
|
||||||
|
|
||||||
## Client API
|
## Client API
|
||||||
@@ -29,8 +29,13 @@ defmodule Omnibot.Irc do
|
|||||||
|
|
||||||
def cfg(irc), do: GenServer.call(irc, :cfg)
|
def cfg(irc), do: GenServer.call(irc, :cfg)
|
||||||
|
|
||||||
defp route_msg(irc, msg) do
|
defp route_msg(irc, cfg, msg) do
|
||||||
plugins = Msg.channel(msg) |> State.channel_plugins()
|
# TODO :
|
||||||
|
# * Plugins that are loaded are not having their defaults applied, since
|
||||||
|
# the add_loaded_plugin in State would handle that. May be a good idea to
|
||||||
|
# make a Config.load/1 function that will handle loading of a
|
||||||
|
# configuration file instead of doing it in the root Omnibot module
|
||||||
|
plugins = Config.channel_plugins(cfg, Msg.channel(msg))
|
||||||
|
|
||||||
Task.Supervisor.async_stream_nolink(
|
Task.Supervisor.async_stream_nolink(
|
||||||
Omnibot.RouterSupervisor,
|
Omnibot.RouterSupervisor,
|
||||||
@@ -85,12 +90,12 @@ defmodule Omnibot.Irc do
|
|||||||
end
|
end
|
||||||
|
|
||||||
@impl true
|
@impl true
|
||||||
def handle_info({:tcp, _socket, line}, state) do
|
def handle_info({:tcp, _info_socket, line}, state = {_socket, cfg}) do
|
||||||
Logger.debug(String.trim(line))
|
Logger.debug(String.trim(line))
|
||||||
msg = Msg.parse(line)
|
msg = Msg.parse(line)
|
||||||
|
|
||||||
# Send the message to the router
|
# Send the message to the router
|
||||||
route_msg(self(), msg)
|
route_msg(self(), cfg, msg)
|
||||||
|
|
||||||
{:noreply, state}
|
{:noreply, state}
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ defmodule Omnibot.PluginManager do
|
|||||||
|
|
||||||
use Supervisor
|
use Supervisor
|
||||||
require Logger
|
require Logger
|
||||||
alias Omnibot.State
|
|
||||||
|
|
||||||
def start_link(opts \\ []) do
|
def start_link(opts \\ []) do
|
||||||
Supervisor.start_link(__MODULE__, opts[:cfg], opts)
|
Supervisor.start_link(__MODULE__, opts[:cfg], opts)
|
||||||
@@ -13,23 +12,10 @@ defmodule Omnibot.PluginManager do
|
|||||||
def init(cfg) do
|
def init(cfg) do
|
||||||
compile_files(cfg.plugin_paths || [])
|
compile_files(cfg.plugin_paths || [])
|
||||||
|
|
||||||
# These are plugins that need to be loaded for core functionality of the bot
|
|
||||||
core = [
|
|
||||||
Omnibot.Core,
|
|
||||||
]
|
|
||||||
|
|
||||||
# Map the plugins in the configuration to the children
|
# Map the plugins in the configuration to the children
|
||||||
children =
|
children =
|
||||||
for plug <- (core ++ cfg.plugins) do
|
for {plugin, cfg} <- cfg.plugins,
|
||||||
{name, cfg} = case plug do
|
do: {Omnibot.Plugin.Supervisor, plugin: plugin, cfg: cfg}
|
||||||
{name, cfg} -> {name, cfg ++ name.default_config()}
|
|
||||||
name -> {name, name.default_config()}
|
|
||||||
end
|
|
||||||
{Omnibot.Plugin.Supervisor, plugin: name, cfg: cfg}
|
|
||||||
end
|
|
||||||
|
|
||||||
# Add each child to the "loaded plugins" list in the State
|
|
||||||
Enum.each(children, fn {_plugin, opts} -> State.add_loaded_plugin({opts[:plugin], opts[:cfg]}) end)
|
|
||||||
|
|
||||||
Supervisor.init(children, strategy: :one_for_one)
|
Supervisor.init(children, strategy: :one_for_one)
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ defmodule Omnibot.Supervisor do
|
|||||||
|
|
||||||
use Supervisor
|
use Supervisor
|
||||||
require IEx
|
require IEx
|
||||||
|
alias Omnibot.Config
|
||||||
|
|
||||||
def start_link(opts) do
|
def start_link(opts) do
|
||||||
Supervisor.start_link(__MODULE__, :ok, opts)
|
Supervisor.start_link(__MODULE__, :ok, opts)
|
||||||
@@ -10,10 +11,7 @@ defmodule Omnibot.Supervisor do
|
|||||||
|
|
||||||
@impl true
|
@impl true
|
||||||
def init(:ok) do
|
def init(:ok) do
|
||||||
|
cfg = System.get_env("OMNIBOT_CFG", "omnibot.exs") |> Config.load()
|
||||||
{_, bindings} = System.get_env("OMNIBOT_CFG", "omnibot.exs")
|
|
||||||
|> Code.eval_file()
|
|
||||||
cfg = bindings[:config]
|
|
||||||
|
|
||||||
# TODO : move cfg to its own process so reloading it is as simple as killing the process
|
# TODO : move cfg to its own process so reloading it is as simple as killing the process
|
||||||
children = [
|
children = [
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ config = %Config {
|
|||||||
ssl: false,
|
ssl: false,
|
||||||
|
|
||||||
plugins: [
|
plugins: [
|
||||||
|
Omnibot.Core,
|
||||||
{Omnibot.Contrib.OnConnect, commands: [
|
{Omnibot.Contrib.OnConnect, commands: [
|
||||||
["privmsg", "nickserv", "register", "password123", "omnibot@omni.bot"],
|
["privmsg", "nickserv", "register", "password123", "omnibot@omni.bot"],
|
||||||
["privmsg", "nickserv", "identify", "password123"]
|
["privmsg", "nickserv", "identify", "password123"]
|
||||||
|
|||||||
63
test/config_test.exs
Normal file
63
test/config_test.exs
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
defmodule Omnibot.ConfigTest do
|
||||||
|
use ExUnit.Case, async: true
|
||||||
|
doctest Omnibot.Config
|
||||||
|
alias Omnibot.Config
|
||||||
|
|
||||||
|
test "channel_plugins works correctly" do
|
||||||
|
cfg = %Config {
|
||||||
|
server: "test",
|
||||||
|
plugins: [
|
||||||
|
{FooBar, channels: ["#foo", "#bar"]},
|
||||||
|
{Foo, channels: ["#foo"]},
|
||||||
|
{Bar, channels: ["#bar"]},
|
||||||
|
{Baz, channels: ["#baz"]},
|
||||||
|
{All, channels: :all},
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
plugins = Config.channel_plugins(cfg, "#foo")
|
||||||
|
|> Enum.map(fn {plugin, _} -> plugin end)
|
||||||
|
assert length(plugins) == 3
|
||||||
|
assert Enum.member?(plugins, FooBar)
|
||||||
|
assert Enum.member?(plugins, Foo)
|
||||||
|
assert Enum.member?(plugins, All)
|
||||||
|
|
||||||
|
plugins = Config.channel_plugins(cfg, "#bar")
|
||||||
|
|> Enum.map(fn {plugin, _} -> plugin end)
|
||||||
|
assert length(plugins) == 3
|
||||||
|
assert Enum.member?(plugins, FooBar)
|
||||||
|
assert Enum.member?(plugins, Bar)
|
||||||
|
assert Enum.member?(plugins, All)
|
||||||
|
|
||||||
|
plugins = Config.channel_plugins(cfg, "#baz")
|
||||||
|
|> Enum.map(fn {plugin, _} -> plugin end)
|
||||||
|
assert length(plugins) == 2
|
||||||
|
assert Enum.member?(plugins, Baz)
|
||||||
|
assert Enum.member?(plugins, All)
|
||||||
|
|
||||||
|
plugins = Config.channel_plugins(cfg, nil)
|
||||||
|
|> Enum.map(fn {plugin, _} -> plugin end)
|
||||||
|
assert length(plugins) == 1
|
||||||
|
assert Enum.member?(plugins, All)
|
||||||
|
end
|
||||||
|
|
||||||
|
test "all_channels works correctly" do
|
||||||
|
cfg = %Config {
|
||||||
|
server: "testing",
|
||||||
|
plugins: [
|
||||||
|
{FooBar, channels: ["#foo", "#bar"]},
|
||||||
|
{Foo, channels: ["#foo"]},
|
||||||
|
{Bar, channels: ["#bar"]},
|
||||||
|
{Baz, channels: ["#baz"]},
|
||||||
|
{All, channels: :all},
|
||||||
|
],
|
||||||
|
}
|
||||||
|
|
||||||
|
channels = Config.all_channels(cfg)
|
||||||
|
|
||||||
|
assert length(channels) == 3
|
||||||
|
assert Enum.member?(channels, "#foo")
|
||||||
|
assert Enum.member?(channels, "#bar")
|
||||||
|
assert Enum.member?(channels, "#baz")
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -1,65 +0,0 @@
|
|||||||
defmodule StateTest do
|
|
||||||
use ExUnit.Case
|
|
||||||
|
|
||||||
alias Omnibot.State
|
|
||||||
|
|
||||||
setup do
|
|
||||||
state = start_supervised!(State)
|
|
||||||
{:ok, state: state}
|
|
||||||
end
|
|
||||||
|
|
||||||
test "state channel_plugins works correctly", %{state: state} do
|
|
||||||
plugins = [
|
|
||||||
{FooBar, channels: ["#foo", "#bar"]},
|
|
||||||
{Foo, channels: ["#foo"]},
|
|
||||||
{Bar, channels: ["#bar"]},
|
|
||||||
{Baz, channels: ["#baz"]},
|
|
||||||
{All, channels: :all},
|
|
||||||
]
|
|
||||||
|
|
||||||
plugins |> Enum.each(fn plugin -> State.add_loaded_plugin(state, plugin) end)
|
|
||||||
|
|
||||||
plugins = State.channel_plugins(state, "#foo")
|
|
||||||
|> Enum.map(fn {plugin, _} -> plugin end)
|
|
||||||
assert length(plugins) == 3
|
|
||||||
assert Enum.member?(plugins, FooBar)
|
|
||||||
assert Enum.member?(plugins, Foo)
|
|
||||||
assert Enum.member?(plugins, All)
|
|
||||||
|
|
||||||
plugins = State.channel_plugins(state, "#bar")
|
|
||||||
|> Enum.map(fn {plugin, _} -> plugin end)
|
|
||||||
assert length(plugins) == 3
|
|
||||||
assert Enum.member?(plugins, FooBar)
|
|
||||||
assert Enum.member?(plugins, Bar)
|
|
||||||
assert Enum.member?(plugins, All)
|
|
||||||
|
|
||||||
plugins = State.channel_plugins(state, "#baz")
|
|
||||||
|> Enum.map(fn {plugin, _} -> plugin end)
|
|
||||||
assert length(plugins) == 2
|
|
||||||
assert Enum.member?(plugins, Baz)
|
|
||||||
assert Enum.member?(plugins, All)
|
|
||||||
|
|
||||||
plugins = State.channel_plugins(state, nil)
|
|
||||||
|> Enum.map(fn {plugin, _} -> plugin end)
|
|
||||||
assert length(plugins) == 1
|
|
||||||
assert Enum.member?(plugins, All)
|
|
||||||
end
|
|
||||||
|
|
||||||
test "state all_channels works correctly", %{state: state} do
|
|
||||||
plugins = [
|
|
||||||
{FooBar, channels: ["#foo", "#bar"]},
|
|
||||||
{Foo, channels: ["#foo"]},
|
|
||||||
{Bar, channels: ["#bar"]},
|
|
||||||
{Baz, channels: ["#baz"]},
|
|
||||||
{All, channels: :all},
|
|
||||||
]
|
|
||||||
|
|
||||||
plugins |> Enum.each(fn plugin -> State.add_loaded_plugin(state, plugin) end)
|
|
||||||
channels = State.all_channels(state)
|
|
||||||
|
|
||||||
assert length(channels) == 3
|
|
||||||
assert Enum.member?(channels, "#foo")
|
|
||||||
assert Enum.member?(channels, "#bar")
|
|
||||||
assert Enum.member?(channels, "#baz")
|
|
||||||
end
|
|
||||||
end
|
|
||||||
Reference in New Issue
Block a user