Compare commits
1 Commits
86c7eaf04c
...
4edbf32ef9
Author | SHA1 | Date |
---|---|---|
mio | 4edbf32ef9 |
|
@ -1,3 +1,4 @@
|
|||
*.servers.lua
|
||||
examples/itte*.lua
|
||||
!sample.servers.lua
|
||||
examples/*/itte*.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
|
||||
- Joining multiple servers
|
||||
- Ad-hoc connecting to servers and joining channels
|
||||
- Config reload
|
||||
|
||||
|
||||
## Requirements
|
||||
## Installation
|
||||
|
||||
- [Lua 5.x](https://www.lua.org/)
|
||||
- [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 &`
|
||||
Please see the [docs](docs/README.md).
|
||||
|
||||
|
||||
## 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.
|
||||
local ramenkan = require("itte")
|
||||
local hellobot = require("itte")
|
||||
|
||||
-- [[
|
||||
-- Set the config file paths.
|
||||
|
@ -20,7 +20,7 @@ local ramenkan = require("itte")
|
|||
-- Either set confs.prefix, *or* a combination of confs.config and
|
||||
-- confs.server, but not both.
|
||||
-- ]]
|
||||
ramenkan.confs.prefix = "ramenkan"
|
||||
hellobot.confs.prefix = "hellobot"
|
||||
|
||||
-- Call the run function.
|
||||
ramenkan.run()
|
||||
hellobot.run()
|
|
@ -9,7 +9,7 @@
|
|||
--
|
||||
-- This variable is optional, but certain handlers like server disconnection
|
||||
-- will not work if it is unset.
|
||||
itte_admins = { globaladmin = "password", }
|
||||
itte_admins = { demo = "password", }
|
||||
|
||||
|
||||
-- `itte_servers`
|
||||
|
@ -22,13 +22,13 @@ itte_servers = {
|
|||
server_name = {
|
||||
host = "irc.example.tld",
|
||||
port = 6667,
|
||||
channels = { "#channel-name" },
|
||||
cap = { "sasl" },
|
||||
channels = { "#channel1", "#channel2" },
|
||||
cap = nil,
|
||||
nick = "botnick",
|
||||
auth_type = nil,
|
||||
auth_user = "botuser",
|
||||
auth_pass = "password",
|
||||
auth_pass = nil,
|
||||
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
|
||||
-- ---------------------------------------------------------------------------
|
||||
|
||||
-- [[
|
||||
-- This is sample data and could be split into another file.
|
||||
-- ]]
|
||||
|
||||
local ramen = {}
|
||||
|
||||
ramen.noodle_broth_types = {
|
||||
|
@ -259,7 +255,6 @@ ramen.links = {
|
|||
-- Ramen functions
|
||||
-- ---------------------------------------------------------------------------
|
||||
|
||||
-- Load the util module early to use some helper functions.
|
||||
local util = require("itteutil")
|
||||
|
||||
|
||||
|
@ -373,12 +368,6 @@ end
|
|||
-- 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 = {
|
||||
debug = true,
|
||||
messages = {
|
||||
|
@ -428,18 +417,7 @@ itte_config.messages.water = {
|
|||
-- Handlers
|
||||
-- ---------------------------------------------------------------------------
|
||||
|
||||
-- Load the module.
|
||||
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 = {}
|
||||
|
||||
|
|
@ -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
|
||||
if itte_config ~= nil then
|
||||
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
|
||||
if itte_handlers ~= nil then itte.handlers = itte_handlers end
|
||||
|
|
Loading…
Reference in New Issue