Add docs
- Add more-detailed usage doc - Add a smaller hello world example - Include a user systemd file - Fix config check to include second-level nested tablestrunk 1.1
parent
75d3f149f2
commit
4edbf32ef9
|
@ -1,3 +1,4 @@
|
||||||
*.servers.lua
|
*.servers.lua
|
||||||
examples/itte*.lua
|
examples/*/itte*.lua
|
||||||
!sample.servers.lua
|
!hellobot.servers.lua
|
||||||
|
!ramenkan.sample.servers.lua
|
||||||
|
|
27
README.md
27
README.md
|
@ -7,33 +7,16 @@ Currently supported:
|
||||||
|
|
||||||
- Authentication via SASL (plain) or Nickserv
|
- Authentication via SASL (plain) or Nickserv
|
||||||
- Joining multiple servers
|
- Joining multiple servers
|
||||||
|
- Ad-hoc connecting to servers and joining channels
|
||||||
- Config reload
|
- Config reload
|
||||||
|
|
||||||
|
|
||||||
## Requirements
|
## Installation
|
||||||
|
|
||||||
- [Lua 5.x](https://www.lua.org/)
|
Please see the [docs](docs/README.md).
|
||||||
- [luasocket](https://w3.impa.br/~diego/software/luasocket/)
|
|
||||||
- [luasec](https://github.com/brunoos/luasec)
|
|
||||||
|
|
||||||
|
|
||||||
## Usage
|
|
||||||
|
|
||||||
See the bot files in the `examples/` directory for usage notes.
|
|
||||||
|
|
||||||
|
|
||||||
## Example: ramenkan
|
|
||||||
|
|
||||||
- Install Lua and other dependencies, e.g. for Alpine:
|
|
||||||
`apk add lua-socket lua-sec`
|
|
||||||
|
|
||||||
- Copy the `itte*.lua` files to the `examples/` directory. Copy the
|
|
||||||
`examples/sample.servers.lua` as `ramenkan.servers.lua` and change the server
|
|
||||||
settings as applicable.
|
|
||||||
|
|
||||||
- Run: `nohup lua /path/to/examples/ramenkan.lua >/dev/null 2>&1 &`
|
|
||||||
|
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
BSD-3.0
|
[BSD-3.0](https://opensource.org/licenses/BSD-3-Clause)
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,149 @@
|
||||||
|
# Itte Documentation
|
||||||
|
|
||||||
|
|
||||||
|
## Requirements
|
||||||
|
|
||||||
|
- [Lua 5.x](https://www.lua.org/)
|
||||||
|
- [luasocket](https://w3.impa.br/~diego/software/luasocket/)
|
||||||
|
- [luasec](https://github.com/brunoos/luasec)
|
||||||
|
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
- Install Lua and other dependencies. Example:
|
||||||
|
|
||||||
|
- Debian/Ubuntu-based distributions: `apt-get install lua-socket lua-sec`
|
||||||
|
|
||||||
|
- Alpine Linux: `apk add lua-socket lua-sec`
|
||||||
|
|
||||||
|
- Copy the `itte*.lua` files to the project directory.
|
||||||
|
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
- Create two config files, or copy the sample files from `examples/` to the
|
||||||
|
same directory level as the `itte*.lua` files. Replace instances of
|
||||||
|
`[prefix]` hereafter with the name of your choice without spaces or special
|
||||||
|
characters, e.g. the project name.
|
||||||
|
|
||||||
|
- `[prefix].servers.lua`: list servers and global admins here.
|
||||||
|
|
||||||
|
- `[prefix].config.lua`: add bot settings and handlers here.
|
||||||
|
|
||||||
|
- There are two variables in `*.servers.lua`:
|
||||||
|
|
||||||
|
- `itte_servers` (required): add a server to `itte_server` following the
|
||||||
|
example configurations.
|
||||||
|
|
||||||
|
- `itte_admins` (optional): this is a table of global admins who can access
|
||||||
|
bot-wide handlers like connecting servers. If left undefined, global
|
||||||
|
admin-only handlers will not be run. In some cases this may be desirable to
|
||||||
|
reduce incidents of bot tampering.
|
||||||
|
|
||||||
|
- There are two optional variables in `*.config.lua`:
|
||||||
|
|
||||||
|
- `itte_config`: customise bot settings, such as the default response and
|
||||||
|
error messages shown to users.
|
||||||
|
|
||||||
|
- `itte_handlers`: most bots listen for some pre-defined code words (often
|
||||||
|
known as "commands") and respond by calling a handler, or function to
|
||||||
|
handle the request accordingly.
|
||||||
|
|
||||||
|
The module will refer to the keywords as codes to distinguish them
|
||||||
|
from IRC commands sent to the server like `JOIN` or `PART`. Name the
|
||||||
|
handler after the code word that will be used to trigger the function and
|
||||||
|
add it to `itte_handlers` so it can be automatically picked up by the
|
||||||
|
module. For example, if the code users will type is `!hello` (where `!` is
|
||||||
|
a prefix to mark it as a bot code), name the function
|
||||||
|
`itte_handlers.hello()`. Handler names cannot start with numbers or special
|
||||||
|
characters.
|
||||||
|
|
||||||
|
- Initialise the module in a project file named `[prefix].lua` and add the
|
||||||
|
following to the file:
|
||||||
|
|
||||||
|
```
|
||||||
|
-- Import the module
|
||||||
|
local itte = require("itte")
|
||||||
|
|
||||||
|
-- Set the prefix for the module to find the config files
|
||||||
|
-- The prefix is the name preceding `.servers.lua` and `.config.lua`
|
||||||
|
itte.confs.prefix = "[prefix]"
|
||||||
|
|
||||||
|
-- Call the run function
|
||||||
|
itte.run()
|
||||||
|
```
|
||||||
|
|
||||||
|
- Start the bot: `lua ./[prefix].lua`
|
||||||
|
|
||||||
|
|
||||||
|
## Built-in service codes
|
||||||
|
|
||||||
|
The module includes a number of built-in codes that bots can respond to. The
|
||||||
|
full list can be viewed on IRC by issuing the code `!help` in a private
|
||||||
|
message with a bot or in a channel where the bot is present. Admin users will
|
||||||
|
also see admin-only codes to manage a bot.
|
||||||
|
|
||||||
|
Global admin-only codes:
|
||||||
|
|
||||||
|
- `connect [server] [user] [password]`: connect to server listed in the server
|
||||||
|
config, where `[server]` is the name given in the servers table (or use
|
||||||
|
`servers` to get the names).
|
||||||
|
|
||||||
|
- `quit [server] [user] [password]`: disconnect from a server. The bot process
|
||||||
|
will automatically exit if it is not connected to any server.
|
||||||
|
|
||||||
|
- `reload [user] [password]`: reload the bot config.
|
||||||
|
|
||||||
|
- `servers [user] [password]`: list known/active servers from the config.
|
||||||
|
|
||||||
|
Server admin-only codes:
|
||||||
|
|
||||||
|
- `channels [password]`: list known channels from the server config.
|
||||||
|
|
||||||
|
- `join [channel] [password]`: join channel(s), e.g. `!join #bots #programming
|
||||||
|
password`.
|
||||||
|
|
||||||
|
- `part [channel] [passowrd]`: leave channel(s), e.g. `!part #bots password`.
|
||||||
|
|
||||||
|
Codes accessible by all users:
|
||||||
|
|
||||||
|
- `help`: list available service codes.
|
||||||
|
|
||||||
|
- `ping`: send a pong message.
|
||||||
|
|
||||||
|
|
||||||
|
## Running a bot as a background process
|
||||||
|
|
||||||
|
There are multiple ways to have a bot run in the background.
|
||||||
|
|
||||||
|
### nohup
|
||||||
|
|
||||||
|
Using the `nohup` command is quick and simple, though it does not support
|
||||||
|
restarting if the bot exits due to a network issue.
|
||||||
|
|
||||||
|
To run the bot and discard any output by redirecting it to `/dev/null`:
|
||||||
|
`nohup lua /path/to/[prefix].lua >/dev/null 2>&1 &`
|
||||||
|
|
||||||
|
### Init scripts, e.g. systemd
|
||||||
|
|
||||||
|
Startup scripts enable services to start automatically and relaunch in the
|
||||||
|
event of an unexpected exit (unless expressly stopped through an init system
|
||||||
|
command). The instructions below describe setting up and running a [systemd]
|
||||||
|
service for a bot under a non-privileged user.
|
||||||
|
|
||||||
|
- Create a systemd directory for the user running the bot if it does not
|
||||||
|
already exist: `mkdir -p /home/[user]/.config/systemd/user`
|
||||||
|
|
||||||
|
- Copy the sample `*.service` to the user systemd directory and rename the file
|
||||||
|
to `[prefix].service`. Edit the service description, `WorkingDirectory` and
|
||||||
|
`ExecStart` values as needed. Use full paths for the `WorkingDirectory` and
|
||||||
|
location of the Lua executable, or the service file will not work.
|
||||||
|
|
||||||
|
- Start and enable the service:
|
||||||
|
|
||||||
|
```
|
||||||
|
systemctl --user start [prefix]
|
||||||
|
systemctl --user enable [prefix]
|
||||||
|
```
|
||||||
|
|
||||||
|
[systemd]: https://www.freedesktop.org/software/systemd/man/systemd.service.html
|
|
@ -0,0 +1,81 @@
|
||||||
|
-- ---------------------------------------------------------------------------
|
||||||
|
-- Custom variables
|
||||||
|
-- ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
local hello_words = {
|
||||||
|
"ahoy!", "EHLO", "hai", "hello!", "henlo", "hey!", "hi!", "ACK (TCP)",
|
||||||
|
"aloha! (Hawaiian)", "ciao! (Italian)", "hallo (Dutch)", "hej (Swedish)",
|
||||||
|
"hola (Spanish)", "salut! (French)", "saluton (Esperanto)", "tag! (German)",
|
||||||
|
"toki! (Toki Pona)", "هلا (pron: hala)", "مااس (Arabic, pron: salaam)",
|
||||||
|
"สวัสดี (Thai, pron: sawatdee)", "你好 (Chinese, pron: ni hao)",
|
||||||
|
"こんにちわ (Japanese, pron: konnichiwa)", "안녕 (Korean, pron: annyeong)",
|
||||||
|
"नमस्ते (Hindi, pron: namaste)", "ᐊᐃ (Ai)", "Привет (Russian, pron: preevyet)",
|
||||||
|
"שָׁלוֹם (Hebrew, pron: shalom)", "kia ora (Māori)"
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
-- ---------------------------------------------------------------------------
|
||||||
|
-- Config
|
||||||
|
-- ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
-- [[
|
||||||
|
-- `itte_config`
|
||||||
|
-- Add custom settings and override the default config settings here (see
|
||||||
|
-- `itte.lua` for the full list). Settings need to be appended to this variable
|
||||||
|
-- to be collected by the reload function.
|
||||||
|
-- ]]
|
||||||
|
itte_config = {
|
||||||
|
debug = true,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
-- ---------------------------------------------------------------------------
|
||||||
|
-- Handlers
|
||||||
|
-- ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
-- Load the main module.
|
||||||
|
local irc = require("itte")
|
||||||
|
-- Load the util module to use some helper functions.
|
||||||
|
local util = require("itteutil")
|
||||||
|
|
||||||
|
|
||||||
|
--[[
|
||||||
|
-- `itte_handlers`
|
||||||
|
-- Define any custom handlers in a new table, then assign the table to it.
|
||||||
|
-- Handlers can also be added to it directly e.g. `itte_handlers.hello()`.
|
||||||
|
-- Handler names should correspond to the service code name, e.g. a function
|
||||||
|
-- `itte_handlers.hello()` will be called within chat as
|
||||||
|
-- `[command_prefix]hello`, as in `!hello`.
|
||||||
|
--
|
||||||
|
-- Here an object called `h` is created for convenience, and functions will be
|
||||||
|
-- added to it.
|
||||||
|
--]]
|
||||||
|
local h = {}
|
||||||
|
|
||||||
|
|
||||||
|
-- Reply with a random greeting.
|
||||||
|
-- The handler takes two parameters, `cxt` and `msg`.
|
||||||
|
--
|
||||||
|
-- The first is a context table that includes server details and a reference to
|
||||||
|
-- the socket connection. The other is a message table, which is the IRC user
|
||||||
|
-- message broken down into parts such as the sender, recipient, reply_to, and
|
||||||
|
-- the code trigger used.
|
||||||
|
--
|
||||||
|
-- The context and message tables are required for the `message()` function to
|
||||||
|
-- know which server and user to direct a response.
|
||||||
|
--
|
||||||
|
-- The `message()` function takes the server connection from the context table,
|
||||||
|
-- a table of users or channels to reply to, and the text string, then formats
|
||||||
|
-- the string into an IRC command and sends it to the server.
|
||||||
|
--
|
||||||
|
-- `util.pick()` is a helper function that takes a table of items and picks one
|
||||||
|
-- randomly by default if the number of items is unspecified. It will return
|
||||||
|
-- the items in a table, so `[1]` will get the one (and in this case, only)
|
||||||
|
-- value in the table.
|
||||||
|
function h.hello(cxt, msg)
|
||||||
|
irc.message(cxt, { msg.reply_to }, util.pick(hello_words)[1])
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
-- Hook up the handlers.
|
||||||
|
itte_handlers = h
|
|
@ -1,5 +1,5 @@
|
||||||
-- Initialise module.
|
-- Initialise module.
|
||||||
local ramenkan = require("itte")
|
local hellobot = require("itte")
|
||||||
|
|
||||||
-- [[
|
-- [[
|
||||||
-- Set the config file paths.
|
-- Set the config file paths.
|
||||||
|
@ -20,7 +20,7 @@ local ramenkan = require("itte")
|
||||||
-- Either set confs.prefix, *or* a combination of confs.config and
|
-- Either set confs.prefix, *or* a combination of confs.config and
|
||||||
-- confs.server, but not both.
|
-- confs.server, but not both.
|
||||||
-- ]]
|
-- ]]
|
||||||
ramenkan.confs.prefix = "ramenkan"
|
hellobot.confs.prefix = "hellobot"
|
||||||
|
|
||||||
-- Call the run function.
|
-- Call the run function.
|
||||||
ramenkan.run()
|
hellobot.run()
|
|
@ -9,7 +9,7 @@
|
||||||
--
|
--
|
||||||
-- This variable is optional, but certain handlers like server disconnection
|
-- This variable is optional, but certain handlers like server disconnection
|
||||||
-- will not work if it is unset.
|
-- will not work if it is unset.
|
||||||
itte_admins = { globaladmin = "password", }
|
itte_admins = { demo = "password", }
|
||||||
|
|
||||||
|
|
||||||
-- `itte_servers`
|
-- `itte_servers`
|
||||||
|
@ -22,13 +22,13 @@ itte_servers = {
|
||||||
server_name = {
|
server_name = {
|
||||||
host = "irc.example.tld",
|
host = "irc.example.tld",
|
||||||
port = 6667,
|
port = 6667,
|
||||||
channels = { "#channel-name" },
|
channels = { "#channel1", "#channel2" },
|
||||||
cap = { "sasl" },
|
cap = nil,
|
||||||
nick = "botnick",
|
nick = "botnick",
|
||||||
auth_type = nil,
|
auth_type = nil,
|
||||||
auth_user = "botuser",
|
auth_user = "botuser",
|
||||||
auth_pass = "password",
|
auth_pass = nil,
|
||||||
code_prefix = "!",
|
code_prefix = "!",
|
||||||
admins = { adminuser = "password", },
|
admins = { demouser = "password", },
|
||||||
},
|
},
|
||||||
}
|
}
|
|
@ -0,0 +1,11 @@
|
||||||
|
[Unit]
|
||||||
|
Description=hellobot — an IRC bot
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
WorkingDirectory=/path/to/hellobot
|
||||||
|
ExecStart=/usr/bin/lua ./hellobot.lua
|
||||||
|
Restart=always
|
||||||
|
RestartSec=300
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=default.target
|
|
@ -2,10 +2,6 @@
|
||||||
-- Ramen data
|
-- Ramen data
|
||||||
-- ---------------------------------------------------------------------------
|
-- ---------------------------------------------------------------------------
|
||||||
|
|
||||||
-- [[
|
|
||||||
-- This is sample data and could be split into another file.
|
|
||||||
-- ]]
|
|
||||||
|
|
||||||
local ramen = {}
|
local ramen = {}
|
||||||
|
|
||||||
ramen.noodle_broth_types = {
|
ramen.noodle_broth_types = {
|
||||||
|
@ -259,7 +255,6 @@ ramen.links = {
|
||||||
-- Ramen functions
|
-- Ramen functions
|
||||||
-- ---------------------------------------------------------------------------
|
-- ---------------------------------------------------------------------------
|
||||||
|
|
||||||
-- Load the util module early to use some helper functions.
|
|
||||||
local util = require("itteutil")
|
local util = require("itteutil")
|
||||||
|
|
||||||
|
|
||||||
|
@ -373,12 +368,6 @@ end
|
||||||
-- Config
|
-- Config
|
||||||
-- ---------------------------------------------------------------------------
|
-- ---------------------------------------------------------------------------
|
||||||
|
|
||||||
-- [[
|
|
||||||
-- `itte_config`
|
|
||||||
-- Add custom settings and override the default config settings here.
|
|
||||||
-- Settings need to be appened to this variable to be collected by the reload
|
|
||||||
-- function.
|
|
||||||
-- ]]
|
|
||||||
itte_config = {
|
itte_config = {
|
||||||
debug = true,
|
debug = true,
|
||||||
messages = {
|
messages = {
|
||||||
|
@ -428,18 +417,7 @@ itte_config.messages.water = {
|
||||||
-- Handlers
|
-- Handlers
|
||||||
-- ---------------------------------------------------------------------------
|
-- ---------------------------------------------------------------------------
|
||||||
|
|
||||||
-- Load the module.
|
|
||||||
local irc = require("itte")
|
local irc = require("itte")
|
||||||
|
|
||||||
|
|
||||||
--[[
|
|
||||||
-- `itte_handlers`
|
|
||||||
-- Define any custom handlers in a new table, then assign the table to it.
|
|
||||||
-- Handlers can also be added to it directly e.g. `itte_handlers.hello()`.
|
|
||||||
-- Handler names should correspond to the service code name, e.g. a function
|
|
||||||
-- `itte_handlers.hello()` will be called within chat as
|
|
||||||
-- `[command_prefix]hello`, as in `!hello`.
|
|
||||||
--]]
|
|
||||||
local h = {}
|
local h = {}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
local ramenkan = require("itte")
|
||||||
|
|
||||||
|
ramenkan.confs.prefix = "ramenkan"
|
||||||
|
|
||||||
|
ramenkan.run()
|
|
@ -0,0 +1,34 @@
|
||||||
|
itte_admins = { USER = "PASSWORD" }
|
||||||
|
|
||||||
|
itte_servers = {
|
||||||
|
town = {
|
||||||
|
host = "localhost",
|
||||||
|
port = 6697,
|
||||||
|
channels = { "#ramenkan", "#bots" },
|
||||||
|
nick = "ramenkan",
|
||||||
|
auth_user = "USER",
|
||||||
|
code_prefix = "!",
|
||||||
|
admins = { USER = "PASSWORD" },
|
||||||
|
},
|
||||||
|
casa = {
|
||||||
|
host = "m455.casa",
|
||||||
|
port = 6697,
|
||||||
|
channels = { "#kitchen", "#siliconpals" },
|
||||||
|
cap = { "sasl", "draft/chathistory" },
|
||||||
|
nick = "ramenkan",
|
||||||
|
auth_type = "sasl",
|
||||||
|
auth_user = "USER",
|
||||||
|
auth_pass = "PASSWORD",
|
||||||
|
code_prefix = "!",
|
||||||
|
admins = { USER = "PASSWORD" },
|
||||||
|
},
|
||||||
|
tildechat = {
|
||||||
|
host = "irc.tilde.chat",
|
||||||
|
port = 6697,
|
||||||
|
channels = { "#bots" },
|
||||||
|
nick = "ramenkan",
|
||||||
|
auth_user = "USER",
|
||||||
|
code_prefix = "!",
|
||||||
|
admins = { USER = "PASSWORD" },
|
||||||
|
},
|
||||||
|
}
|
|
@ -0,0 +1,11 @@
|
||||||
|
[Unit]
|
||||||
|
Description=ramenkan — a ramen-themed IRC bot
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
WorkingDirectory=%h/bin/itte/examples/ramenkan
|
||||||
|
ExecStart=/usr/bin/lua ./ramenkan.lua
|
||||||
|
Restart=always
|
||||||
|
RestartSec=300
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=default.target
|
13
itte.lua
13
itte.lua
|
@ -126,7 +126,18 @@ function itte.get_config(reload)
|
||||||
-- Update config with value overrides from itte_config
|
-- Update config with value overrides from itte_config
|
||||||
if itte_config ~= nil then
|
if itte_config ~= nil then
|
||||||
for k, v in pairs(itte_config) do
|
for k, v in pairs(itte_config) do
|
||||||
itte.config[k] = v
|
-- Second-level nested tables
|
||||||
|
if type(v) == "table" then
|
||||||
|
for kk, vv in pairs(v) do
|
||||||
|
if (type(vv) == "table") or (type(vv) == "function") then
|
||||||
|
itte.config[k] = v
|
||||||
|
else
|
||||||
|
itte.config[k][kk] = vv
|
||||||
|
end
|
||||||
|
end
|
||||||
|
else
|
||||||
|
itte.config[k] = v
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
if itte_handlers ~= nil then itte.handlers = itte_handlers end
|
if itte_handlers ~= nil then itte.handlers = itte_handlers end
|
||||||
|
|
Loading…
Reference in New Issue