219 lines
6.6 KiB
Elixir
219 lines
6.6 KiB
Elixir
defmodule Omnibot.Config do
|
|
@moduledoc """
|
|
The full configuration for an instance of Omnibot.
|
|
|
|
This configuration structure contains both the IRC server connection information, along with all
|
|
plugins and their configuration.
|
|
|
|
## Configuration keys
|
|
|
|
- server: the IRC server to connect to. **(required)**
|
|
- nick: the IRC nickname to use for the bot. **(optional, default "omnibot")**
|
|
- user: the IRC username to use for the bot. **(optional, default "omnibot")**
|
|
- real: the IRC realname to use for the bot. **(optional, default "omnibot")**
|
|
- port: the port to connect to the server on. **(optional, default 6667)**
|
|
- ssl: whether to use SSL or not. Note that IRC usually uses port 6697 for
|
|
SSL. **(optional, default false)**
|
|
- channels: a list of channels that the bot should always join. **(optional, default [])**
|
|
- plugins: a list of plugins to load and their configuration. **(optional, default [])**
|
|
- plugin_paths: a list of locations to look for additional plugins. **(optional, default [])**
|
|
|
|
## Plugins configuration
|
|
|
|
Inside the `plugins` key listed above, a list of plugins is expected. Plugins are either a single
|
|
atom, or a tuple of the plugin and a keyword list of configuration.
|
|
|
|
### Plugin channels
|
|
|
|
All plugins have a `channels` configuration value, determining which channels this plugin is
|
|
active in. This value may also be set to the atom value `:all`, which indicates that it is active
|
|
on all channels.
|
|
|
|
At least one plugin in the configuration list must contain a list of channels, so that the bot
|
|
knows which channels to join.
|
|
|
|
## Example configuration
|
|
|
|
iex> %Omnibot.Config {
|
|
...> nick: "omnibot_testing",
|
|
...> server: "irc.bonerjamz.us",
|
|
...> port: 6667,
|
|
...> ssl: false,
|
|
...> channels: ["#idleville"],
|
|
...> plugins: [
|
|
...> {Omnibot.Contrib.OnConnect, commands: [
|
|
...> ["privmsg", "nickserv", "register", "password123", "omnibot@omni.bot"],
|
|
...> ["privmsg", "nickserv", "identify", "password123"]
|
|
...> ]},
|
|
...> Omnibot.Contrib.Linkbot,
|
|
...> Omnibot.Contrib.Fortune,
|
|
...> {Omnibot.Contrib.Wordbot, ignore: ["username"]},
|
|
...> ],
|
|
...> plugin_paths: [{"plugins", recurse: true}]
|
|
...> }
|
|
|
|
"""
|
|
|
|
alias Omnibot.Irc.Msg
|
|
|
|
@enforce_keys [:server]
|
|
defstruct [
|
|
:server,
|
|
nick: "omnibot",
|
|
user: "omnibot",
|
|
real: "omnibot",
|
|
port: 6667,
|
|
ssl: false,
|
|
channels: [],
|
|
plugins: [],
|
|
plugin_paths: []
|
|
]
|
|
|
|
@doc """
|
|
Gets all channels that the bot should join via its plugins.
|
|
|
|
## Parameters
|
|
|
|
- cfg: the configuration value to operate on.
|
|
|
|
## Examples
|
|
|
|
iex> cfg = %Omnibot.Config {
|
|
...> server: "irc.example.com",
|
|
...> channels: ["#general"],
|
|
...> plugins: [
|
|
...> {ExamplePlugin, channels: ["#omnibot", "#example"]},
|
|
...> {OtherPlugin, channels: ["#example"]}
|
|
...> ]
|
|
...> }
|
|
iex> Omnibot.Config.all_channels(cfg)
|
|
["#example", "#general", "#omnibot"]
|
|
"""
|
|
def all_channels(cfg = %Omnibot.Config{}) do
|
|
(do_all_channels(cfg.plugins) ++ cfg.channels)
|
|
|> MapSet.new()
|
|
|> MapSet.to_list()
|
|
end
|
|
|
|
defp do_all_channels([]) do
|
|
[]
|
|
end
|
|
|
|
defp do_all_channels([plugin | plugins]) when is_atom(plugin) do
|
|
do_all_channels([{plugin, plugin.default_config()} | plugins])
|
|
end
|
|
|
|
defp do_all_channels([{_plugin, cfg} | plugins]) do
|
|
channels = Keyword.get(cfg, :channels, [])
|
|
head = if channels in [nil, :all],
|
|
do: [],
|
|
else: channels
|
|
head ++ do_all_channels(plugins)
|
|
end
|
|
|
|
@doc """
|
|
Creates an `Omnibot.Irc.Msg.Prefix` from this configuration to be sent to a server.
|
|
|
|
## Parameters
|
|
|
|
- cfg: the configuration value to operate on.
|
|
|
|
## Examples
|
|
|
|
iex> cfg = %Omnibot.Config { server: "irc.example.com" }
|
|
iex> Omnibot.Config.msg_prefix(cfg)
|
|
%Omnibot.Irc.Msg.Prefix {:nick => "omnibot", :user => "omnibot", :host => nil}
|
|
"""
|
|
def msg_prefix(cfg = %Omnibot.Config{}) do
|
|
%Msg.Prefix{
|
|
nick: cfg.nick,
|
|
user: cfg.user
|
|
}
|
|
end
|
|
|
|
@doc """
|
|
Make a new message with the given command and parameters using the given
|
|
configuration to build the prefix.
|
|
|
|
## Parameters
|
|
|
|
- cfg: the configuration value to operate on.
|
|
- command: the IRC command to send
|
|
- params: a list of parameters to pass to the IRC command.
|
|
|
|
## Examples
|
|
|
|
iex> cfg = %Omnibot.Config { server: "irc.example.com" }
|
|
iex> Omnibot.Config.msg(cfg, "PRIVMSG", ["#testing", "this is a test message"])
|
|
%Omnibot.Irc.Msg{
|
|
prefix: %Omnibot.Irc.Msg.Prefix {:nick => "omnibot", :user => "omnibot", :host => nil},
|
|
command: "PRIVMSG",
|
|
params: ["#testing", "this is a test message"],
|
|
}
|
|
"""
|
|
def msg(cfg = %Omnibot.Config{}, command, params \\ []) do
|
|
%Msg{
|
|
prefix: msg_prefix(cfg),
|
|
command: command,
|
|
params: params
|
|
}
|
|
end
|
|
|
|
@doc """
|
|
Gets all plugins that expect a message from the given config and channel.
|
|
|
|
## Parameters
|
|
|
|
- cfg: the configuration that holds all plugins to search
|
|
- channel: the channel to filter listening plugins on
|
|
|
|
## Example
|
|
|
|
iex> cfg = %Omnibot.Config {
|
|
...> server: "irc.example.com",
|
|
...> channels: ["#general"],
|
|
...> plugins: [
|
|
...> {ExamplePlugin, channels: ["#omnibot", "#example"]},
|
|
...> {OtherPlugin, channels: ["#example"]},
|
|
...> {ThirdPlugin, channels: :all},
|
|
...> ]
|
|
...> }
|
|
iex> Omnibot.Config.channel_plugins(cfg, "#general")
|
|
[{ThirdPlugin, channels: :all}]
|
|
iex> Omnibot.Config.channel_plugins(cfg, "#omnibot")
|
|
[{ExamplePlugin, channels: ["#omnibot", "#example"]}, {ThirdPlugin, channels: :all}]
|
|
"""
|
|
def channel_plugins(cfg = %Omnibot.Config{}, channel) do
|
|
do_channel_plugins(cfg.plugins, channel)
|
|
end
|
|
|
|
defp do_channel_plugins([], _channel), do: []
|
|
|
|
defp do_channel_plugins([plugin | plugins], channel) when is_atom(plugin) do
|
|
do_channel_plugins([{plugin, plugin.default_config()} | plugins], channel)
|
|
end
|
|
|
|
defp do_channel_plugins([{plugin, cfg} | plugins], channel) do
|
|
plugin_channels = Keyword.get(cfg, :channels, [])
|
|
head = if plugin_channels == :all || channel in plugin_channels,
|
|
do: [{plugin, cfg}],
|
|
else: []
|
|
head ++ do_channel_plugins(plugins, channel)
|
|
end
|
|
|
|
@doc """
|
|
Loads a configuration from a given path and an optional config binding.
|
|
"""
|
|
def load(path, binding_name \\ :config) do
|
|
with {_, bindings} <- Code.eval_file(path) do
|
|
cfg = bindings[binding_name]
|
|
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
|