Compare commits
11 Commits
ngircd-lin
...
master
Author | SHA1 | Date |
---|---|---|
Cadey Ratio | d7b47df5c4 | |
Cadey Ratio | 1f74e4e3d2 | |
Cadey Ratio | fa56644a7e | |
Cadey Ratio | ac061dff7d | |
Cadey Ratio | aa777a6ab6 | |
Cadey Ratio | b00c7c10d7 | |
Cadey Ratio | 6f9a472818 | |
Cadey Ratio | 559df11d41 | |
Cadey Ratio | fdfb591c13 | |
Cadey Ratio | f953cad787 | |
Cadey Ratio | bb14de2846 |
|
@ -2,4 +2,10 @@ FROM xena/lua:5.3
|
|||
WORKDIR /ketracel
|
||||
COPY . .
|
||||
ENV PATH $PATH:/root/.luarocks/bin
|
||||
RUN ./scripts/build_docker.sh
|
||||
RUN apk --no-cache add ngircd \
|
||||
&& luarocks-5.3 install --local moonscript \
|
||||
&& luarocks-5.3 install --local busted \
|
||||
&& luarocks-5.3 install --local --only-deps ./ketracel*.rockspec \
|
||||
&& ./scripts/test.sh \
|
||||
&& ./scripts/build_docker.sh \
|
||||
&& apk del ngircd
|
||||
|
|
|
@ -2,4 +2,4 @@
|
|||
|
||||
export LUA_PATH='/root/.luarocks/share/lua/5.3/?.lua;/root/.luarocks/share/lua/5.3/?/init.lua'
|
||||
export LUA_CPATH='/root/.luarocks/lib/lua/5.3/?.so'
|
||||
lua5.3 -l ketracel
|
||||
lua5.3 -l ketracel.main
|
||||
|
|
|
@ -16,11 +16,19 @@ dependencies = {
|
|||
"lua ~> 5.3",
|
||||
"irc-engine",
|
||||
"luasocket",
|
||||
"ln",
|
||||
"uuid",
|
||||
}
|
||||
build = {
|
||||
type = "builtin",
|
||||
modules = {
|
||||
["ketracel"] = "src/ketracel.lua",
|
||||
["ketracel.bots.commands"] = "src/ketracel/bots/commands.lua",
|
||||
["ketracel.bots.ketracel"] = "src/ketracel/bots/ketracel.lua",
|
||||
["ketracel.main"] = "src/ketracel/main.lua",
|
||||
["ketracel.server"] = "src/ketracel/server.lua",
|
||||
["irce.modules.ngircd"] = "src/irce/modules/ngircd/init.lua",
|
||||
["irce.modules.ngircd.channel"] = "src/irce/modules/ngircd/channel.lua",
|
||||
["irce.modules.ngircd.modes"] = "src/irce/modules/ngircd/modes.lua",
|
||||
["irce.modules.oper"] = "src/irce/modules/oper.lua",
|
||||
},
|
||||
install = {
|
||||
|
|
|
@ -0,0 +1,17 @@
|
|||
#!/bin/sh
|
||||
|
||||
moonc-5.3 `find -type f | grep -v spec | grep 'moon$'`
|
||||
ngircd -f `pwd`/spec/ngircd.conf
|
||||
|
||||
function trap_ctrlc () {
|
||||
killall ngircd
|
||||
exit 0
|
||||
}
|
||||
|
||||
trap "trap_ctrlc" 2
|
||||
|
||||
cd src
|
||||
export KETRACEL_DEBUG=yes
|
||||
export KETRACEL_SPASS=hunter2
|
||||
lua5.3 -l set_paths ketracel/main.lua
|
||||
trap_ctrlc
|
|
@ -2,4 +2,4 @@
|
|||
|
||||
tup
|
||||
cd src
|
||||
godotenv -f ../.env lua5.3 -l set_paths ketracel.lua
|
||||
godotenv -f ../.env lua5.3 -l set_paths ./ketracel/main.lua
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
#!/bin/sh
|
||||
|
||||
moonc `find -type f | grep -v spec | grep 'moon$'`
|
||||
busted -o TAP
|
|
@ -0,0 +1,46 @@
|
|||
[Global]
|
||||
Name = test.localhost
|
||||
Info = oh god
|
||||
Listen = 0.0.0.0
|
||||
MotdPhrase = testing
|
||||
Network = ShadowNET
|
||||
Ports = 6667
|
||||
ServerGID = 65534
|
||||
ServerUID = 65534
|
||||
|
||||
[Limits]
|
||||
MaxJoins = 50
|
||||
MaxNickLength = 31
|
||||
MaxListSize = 100
|
||||
PingTimeout = 120
|
||||
PongTimeout = 20
|
||||
|
||||
[Options]
|
||||
AllowedChannelTypes = #&+
|
||||
AllowRemoteOper = yes
|
||||
CloakUserToNick = yes
|
||||
DNS = no
|
||||
Ident = no
|
||||
MorePrivacy = no
|
||||
NoticeBeforeRegistration = yes
|
||||
OperCanUseMode = yes
|
||||
OperChanPAutoOp = yes
|
||||
PAM = no
|
||||
PAMIsOptional = yes
|
||||
RequireAuthPing = yes
|
||||
|
||||
[Channel]
|
||||
Name = #lobby
|
||||
Topic = Welcome to the new ShadowNET!
|
||||
Modes = tn
|
||||
|
||||
[Operator]
|
||||
Name = Cadey
|
||||
Password = hunter2
|
||||
|
||||
[Server]
|
||||
Name = ketracel.akua
|
||||
Passive = yes
|
||||
MyPassword = hunter2
|
||||
PeerPassword = hunter2
|
||||
ServiceMask = Ketracel,*Serv
|
|
@ -0,0 +1,27 @@
|
|||
Channel = require "irce.modules.ngircd.channel"
|
||||
|
||||
describe "Channel", ->
|
||||
it "requires a channel name", ->
|
||||
assert.has.errors -> Channel {}
|
||||
|
||||
it "lets you create a channel", ->
|
||||
assert.truthy Channel name: "#butts"
|
||||
|
||||
it "lets you set modes", ->
|
||||
with Channel name: "#butts"
|
||||
\add_mode "p"
|
||||
assert .modes[1] == "p"
|
||||
\del_mode "p"
|
||||
assert #.modes == 0
|
||||
|
||||
it "requires channel membership to give hats", ->
|
||||
with Channel name: "#butts"
|
||||
assert.has.errors -> \add_hat "cadey", "@"
|
||||
assert.has.errors -> \del_hat "cadey", "@"
|
||||
|
||||
it "lets you give people hats", ->
|
||||
with Channel name: "#butts", members: {cadey: {}}
|
||||
\add_hat "cadey", "@"
|
||||
assert .members.cadey[1] == "o"
|
||||
\del_hat "cadey", "@"
|
||||
assert #.members.cadey == 0
|
|
@ -0,0 +1,87 @@
|
|||
irce = require "irce"
|
||||
socket = require "socket"
|
||||
test = require "ketracel.test"
|
||||
Server = require("ketracel.server").Server
|
||||
uuid = require "uuid"
|
||||
ln = require "ln"
|
||||
|
||||
describe "ngircd protocol support", ->
|
||||
local server
|
||||
local client
|
||||
|
||||
setup ->
|
||||
file = io.popen "ngircd -n -f ./spec/ngircd.conf", "r"
|
||||
server = Server
|
||||
server: "127.0.0.1"
|
||||
sname: "ketracel.akua"
|
||||
spass: "hunter2"
|
||||
sreal: "Ketracel"
|
||||
nicklen: "31"
|
||||
debug: os.getenv "DEBUG"
|
||||
client = test.Client "test_user"
|
||||
|
||||
teardown ->
|
||||
with io.popen "killall ngircd", "r"
|
||||
\close!
|
||||
|
||||
it "actually is running ngircd", ->
|
||||
with io.popen "pstree"
|
||||
data = \read "*all"
|
||||
assert.truthy string.find data, "ngircd"
|
||||
|
||||
it "sees end of burst", ->
|
||||
server\wait_for "376"
|
||||
|
||||
it "can use the Client class", ->
|
||||
client\wait_for "005"
|
||||
|
||||
it "sees the client", ->
|
||||
server\wait_for "NICK", (source, user) ->
|
||||
user.nick == "test_user"
|
||||
|
||||
local channame
|
||||
|
||||
it "sees the client join a new channel", ->
|
||||
channame = uuid()
|
||||
client.irc\JOIN "#" .. channame
|
||||
server\wait_for "JOIN", (who, chan) ->
|
||||
chan.name == "#" .. channame
|
||||
client\wait_for "JOIN", (sender, channel) ->
|
||||
channel\sub(2) == channame
|
||||
|
||||
it "sees the client part the channel", ->
|
||||
client.irc\PART "#" .. channame
|
||||
server\wait_for "PART", (who, chan) ->
|
||||
chan.name == "#" .. channame
|
||||
|
||||
it "sees nickchanges", ->
|
||||
client.irc\send_raw "NICK newnick"
|
||||
server\wait_for "NICKCHG", (sender, clinfo) ->
|
||||
clinfo.nick == "newnick"
|
||||
|
||||
it "sees quits", ->
|
||||
cli = test.Client "quitter"
|
||||
cli\wait_for "005"
|
||||
cli.irc\QUIT "bye"
|
||||
server\wait_for "QUIT", (sender, msg) ->
|
||||
sender == "quitter"
|
||||
|
||||
it "sees a privmsg", ->
|
||||
client.irc\JOIN "#ketracel"
|
||||
client.irc\PRIVMSG "#ketracel", "hi"
|
||||
server\wait_for "PRIVMSG", (sender, params) ->
|
||||
params[1] == "#ketracel" and params[2] == "hi"
|
||||
|
||||
describe "ketracel bot", ->
|
||||
it "has a working VHOST command", ->
|
||||
client.irc\PRIVMSG "Ketracel", "VHOST my.cool.vhost"
|
||||
server\wait_for "PRIVMSG", (sender, params) ->
|
||||
params[1] == "Ketracel" and params[2] == "VHOST my.cool.vhost"
|
||||
client\wait_for "396"
|
||||
client\wait_for "NOTICE", (sender, origin, message, pm) ->
|
||||
message\find "my.cool.vhost"
|
||||
|
||||
it "replies to unknown commands", ->
|
||||
client.irc\PRIVMSG "KETRACEL", uuid()
|
||||
server\wait_for "PRIVMSG"
|
||||
client\wait_for "NOTICE"
|
|
@ -0,0 +1,20 @@
|
|||
modes = require "irce.modules.ngircd.modes"
|
||||
|
||||
describe "mode conversion", ->
|
||||
it "has modes2prefix", ->
|
||||
assert.truthy modes.mode2prefix
|
||||
|
||||
it "has prefix2modes", ->
|
||||
assert.truthy modes.prefix2mode
|
||||
|
||||
it "has convert", ->
|
||||
assert.truthy modes.convert
|
||||
|
||||
describe "convert", ->
|
||||
for k, v in pairs modes.mode2prefix
|
||||
msg = string.format "%s: %s", k, v
|
||||
it msg, ->
|
||||
assert.equal(modes.convert(k), v)
|
||||
msg = string.format "%s: %s", v, k
|
||||
it msg, ->
|
||||
assert.equal(modes.convert(v), k)
|
|
@ -1,40 +0,0 @@
|
|||
irce = require "irce"
|
||||
moon = require "moon"
|
||||
stringx = require "pl.stringx"
|
||||
|
||||
{
|
||||
hooks:
|
||||
["376"]: (state) =>
|
||||
self\NICK "Ketracel", "white", "the.dominion", "+io", "Ketracel White"
|
||||
self\NJOIN "#ketracel", "@Ketracel"
|
||||
|
||||
--["NJOIN"]: (state, chan) =>
|
||||
-- self\NJOIN chan, "Ketracel"
|
||||
|
||||
["PRIVMSG"]: (state, sender, params) =>
|
||||
cmdchar = params[2]\sub 1, 1
|
||||
destsigil = params[1]\sub 1, 1
|
||||
|
||||
if params[1]\lower! == "ketracel"
|
||||
sp = stringx.split params[2]
|
||||
cmd = sp[1]
|
||||
table.remove sp, 1
|
||||
self\handle("Ketracel command", sender[1], params[1], cmd, sp)
|
||||
|
||||
if cmdchar == "?" and destsigil == "#"
|
||||
sp = stringx.split params[2]
|
||||
cmd = string.sub sp[1], 2
|
||||
table.remove sp, 1
|
||||
self\handle("Ketracel command", sender[1], params[1], cmd, sp)
|
||||
|
||||
["Ketracel command"]: (state, sender, target, cmd, args) =>
|
||||
switch string.upper cmd
|
||||
when "VHOST"
|
||||
if #args > 0
|
||||
self\VHOST sender, args[1]
|
||||
self\PRIVMSG "Ketracel", sender, "your vhost is now " ..args[1]
|
||||
else
|
||||
self\PRIVMSG "Ketracel", sender, "usage: VHOST <your.vhost>"
|
||||
else
|
||||
self\PRIVMSG "Ketracel", sender, "i don't know " .. cmd
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
modeconv = require "irce.modules.ngircd.modes"
|
||||
|
||||
class Channel
|
||||
new: (data) =>
|
||||
assert data.name
|
||||
data.members = {} unless data.members
|
||||
data.modes = {} unless data.modes
|
||||
data.topic = "" unless data.topic
|
||||
for k, v in pairs data
|
||||
self[k] = v
|
||||
|
||||
add_hat: (who, mode) =>
|
||||
hat = modeconv.convert mode
|
||||
usermodes = assert @members[who\lower!]
|
||||
for _, chhat in pairs usermodes
|
||||
return if chhat == hat
|
||||
|
||||
usermodes[#usermodes+1] = hat
|
||||
|
||||
del_hat: (who, mode) =>
|
||||
hat = modeconv.convert mode
|
||||
usermodes = assert @members[who\lower!]
|
||||
|
||||
for i, v in pairs usermodes
|
||||
if v == hat
|
||||
table.remove usermodes, i
|
||||
return
|
||||
|
||||
add_mode: (mode) =>
|
||||
for _, chmd in pairs @modes
|
||||
return if chmd == mode
|
||||
|
||||
@modes[#@modes+1] = mode
|
||||
|
||||
del_mode: (mode) =>
|
||||
for i, v in pairs @modes
|
||||
if v == mode
|
||||
table.remove @modes, i
|
||||
return
|
||||
|
||||
string.format "desync detected: mode %s isn't set on %s", mode, @name
|
||||
|
||||
Channel
|
|
@ -2,6 +2,8 @@ irce = require "irce"
|
|||
util = require "irce.util"
|
||||
stringx = require "pl.stringx"
|
||||
moon = require "moon"
|
||||
ln = require "ln"
|
||||
modeconv = require "irce.modules.ngircd.modes"
|
||||
|
||||
{
|
||||
init: (state) =>
|
||||
|
@ -11,10 +13,10 @@ moon = require "moon"
|
|||
|
||||
senders:
|
||||
["REGISTER"]: (state, password, software, version, sname, real, nicklen) =>
|
||||
assert self\PASS password, software, version
|
||||
assert self\SERVER sname, real
|
||||
assert self\NICKLEN nicklen
|
||||
assert self\EMOTD!
|
||||
assert @PASS password, software, version
|
||||
assert @SERVER sname, real
|
||||
assert @NICKLEN nicklen
|
||||
assert @EMOTD!
|
||||
string.format ":%s PING :%s", sname, sname
|
||||
|
||||
["PASS"]: (state, password, software, version) =>
|
||||
|
@ -43,35 +45,124 @@ moon = require "moon"
|
|||
|
||||
["NICK"]: (state, nick, user, host, modes, real) =>
|
||||
state.clients[string.lower nick] =
|
||||
:nick, :user, :host, :modes, :real, metadata: {}
|
||||
:nick, :user, :host, modes: string.sub(modes, 2), :real, metadata: {}
|
||||
string.format ":%s NICK %s 1 %s %s 1 %s :%s", state.sname, nick, user, host, modes, real
|
||||
|
||||
["NJOIN"]: (state, channame, who) =>
|
||||
string.format ":%s NJOIN %s :%s", state.sname, channame, who
|
||||
["CHANINFO"]: (state, channame) =>
|
||||
if state.channels[channame] == nil
|
||||
state.channels[channame] =
|
||||
name: channame
|
||||
mode: "tn"
|
||||
topic: ""
|
||||
members: {}
|
||||
|
||||
string.format ":%s CHANINFO %s +tn", state.sname, channame
|
||||
|
||||
["NJOIN"]: (state, channame, who, prefix) =>
|
||||
if state.channels[channame] == nil
|
||||
state.channels[channame] =
|
||||
name: channame,
|
||||
mode: ""
|
||||
topic: ""
|
||||
members: {}
|
||||
|
||||
pfxarr = {}
|
||||
if prefix
|
||||
for i = 1, #prefix
|
||||
pfxarr[i] = string.sub prefix, i, i
|
||||
state.channels[channame].members[string.lower who] = pfxarr
|
||||
string.format ":%s NJOIN %s :%s%s", state.sname, channame, prefix or "", who
|
||||
|
||||
["METADATA"]: (state, nick, key, val) =>
|
||||
state.clients[string.lower nick].metadata[key] = val
|
||||
string.format ":%s METADATA %s %s :%s", state.sname, nick, key, val
|
||||
|
||||
["VHOST"]: (state, nick, vhost) =>
|
||||
self\METADATA nick, "cloakhost", vhost
|
||||
@METADATA nick, "cloakhost", vhost
|
||||
string.format ":%s MODE %s +x", state.sname, nick
|
||||
|
||||
["PRIVMSG"]: (state, nick, target, message) =>
|
||||
string.format ":%s PRIVMSG %s :%s", nick, target, message
|
||||
|
||||
["NOTICE"]: (state, nick, target, message) =>
|
||||
string.format ":%s NOTICE %s :%s", nick, target, message
|
||||
|
||||
["PART"]: (state, nick, chan, why) =>
|
||||
state.channels[chan].members[nick] = nil
|
||||
if #state.channels[chan].members == 0
|
||||
state.channels[chan] = nil
|
||||
|
||||
string.format ":%s PART %s :%s", nick, chan, why
|
||||
|
||||
handlers:
|
||||
["461"]: (state, sender, params) =>
|
||||
@handle "DIE", string.format("%s: %s", sender[1], params[1])
|
||||
|
||||
["ERROR"]: (state, sender, params) =>
|
||||
error string.format "%s: %s", sender[1], params[1]
|
||||
|
||||
["PING"]: (state, sender, params) =>
|
||||
self\send "PONG", params[1]
|
||||
@send "PONG", params[1]
|
||||
sender, params[1]
|
||||
|
||||
["PONG"]: (state, sender, params) =>
|
||||
sender, params[1]
|
||||
|
||||
["JOIN"]: (state, sender, params) =>
|
||||
chan = params[1]
|
||||
mode = {}
|
||||
bell = string.find chan, "\x07"
|
||||
if bell
|
||||
sp = {string.sub(chan, 1, bell - 1), string.sub(chan, bell + 1)}
|
||||
chan = sp[1]
|
||||
mode = {modeconv.convert sp[2]}
|
||||
nick = string.lower sender[1]
|
||||
|
||||
if not state.channels[chan]
|
||||
state.channels[chan] = {name: chan, mode: "", members: {}, topic: ""}
|
||||
state.channels[chan].members[nick] = mode
|
||||
|
||||
sender[1], state.channels[chan]
|
||||
|
||||
["PART"]: (state, sender, params) =>
|
||||
chan = params[1]
|
||||
nick = string.lower sender[1]
|
||||
cinfo = state.channels[chan]
|
||||
state.channels[chan].members[nick] = nil
|
||||
if #state.channels[chan].members == 0
|
||||
state.channels[chan] = nil
|
||||
|
||||
sender[1], cinfo
|
||||
|
||||
["QUIT"]: (state, sender, params) =>
|
||||
nick = string.lower sender[1]
|
||||
state.clients[nick] = nil
|
||||
|
||||
for k, v in pairs state.channels
|
||||
v.members[nick] = nil
|
||||
|
||||
sender[1], params[1]
|
||||
|
||||
["NICK"]: (state, sender, params) =>
|
||||
if #params == 1
|
||||
oldnick = sender[1]
|
||||
oldnicksmall = string.lower oldnick
|
||||
newnick = params[1]
|
||||
cli = state.clients[oldnicksmall]
|
||||
cli.nick = newnick
|
||||
state.clients[string.lower oldnicksmall] = nil
|
||||
nick = string.lower newnick
|
||||
state.clients[string.lower newnick] = cli
|
||||
|
||||
for k, v in pairs state.channels
|
||||
for kk, vv in pairs v.members
|
||||
if kk == oldnicksmall
|
||||
v.members[nick] = v.members[oldnicksmall]
|
||||
v.members[oldnicksmall] = nil
|
||||
|
||||
@handle "NICKCHG", sender, state.clients[nick]
|
||||
return
|
||||
|
||||
nick = params[1]
|
||||
user = params[3]
|
||||
host = params[4]
|
||||
|
@ -82,7 +173,7 @@ moon = require "moon"
|
|||
state.clients[string.lower nick] =
|
||||
:nick, :user, :host, :modes, :real, :metadata
|
||||
|
||||
sender, state.clients[nick]
|
||||
sender, state.clients[string.lower nick]
|
||||
|
||||
["METADATA"]: (state, sender, params) =>
|
||||
nick = params[1]
|
||||
|
@ -96,6 +187,13 @@ moon = require "moon"
|
|||
chan = params[1]
|
||||
whose = stringx.split tostring(params[2]), ","
|
||||
|
||||
if state.channels[chan] == nil
|
||||
state.channels[chan] =
|
||||
name: chan
|
||||
mode: ""
|
||||
topic: ""
|
||||
members: {}
|
||||
|
||||
for k, v in pairs whose
|
||||
pfxlen = string.find v, "%a+"
|
||||
nick = string.lower string.sub v, pfxlen
|
||||
|
@ -103,7 +201,7 @@ moon = require "moon"
|
|||
pfxarr = {}
|
||||
|
||||
for i = 1, #prefix
|
||||
pfxarr[i] = string.sub prefix, i, i
|
||||
pfxarr[i] = modeconv.convert string.sub prefix, i, i
|
||||
|
||||
state.channels[chan].members[nick] = pfxarr
|
||||
|
||||
|
@ -127,19 +225,24 @@ moon = require "moon"
|
|||
|
||||
state.channels[name] =
|
||||
:name, :mode, :topic, :key, :limit, members: {}
|
||||
state.channels[name]
|
||||
|
||||
["PRIVMSG"]: (state, sender, params) =>
|
||||
if params[2] == "?state"
|
||||
moon.p state
|
||||
return sender, params
|
||||
|
||||
if sender[1] == "Cadey" and stringx.startswith params[2], "?eval"
|
||||
code = string.sub(params[2], 7)
|
||||
print string.format "%s %s %s - evaling", params[1], sender[1], code
|
||||
fun, err = load(code, sender[1].."-"..params[1], "t", {
|
||||
state: state, :string,
|
||||
state: state, :string, irc: @, :_VERSION
|
||||
})
|
||||
if err ~= nil
|
||||
error err
|
||||
result = fun!
|
||||
if result ~= nil
|
||||
self\PRIVMSG state.sname, params[1], tostring result
|
||||
@PRIVMSG state.sname, params[1], tostring result
|
||||
|
||||
sender, params
|
||||
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
mode2prefix =
|
||||
q: "~"
|
||||
a: "&"
|
||||
o: "@"
|
||||
h: "%"
|
||||
v: "+"
|
||||
|
||||
prefix2mode =
|
||||
["~"]: "q"
|
||||
["&"]: "a"
|
||||
["@"]: "o"
|
||||
["%"]: "h"
|
||||
["+"]: "v"
|
||||
|
||||
convert = (mode_or_prefix) ->
|
||||
mode2prefix[mode_or_prefix] or prefix2mode[mode_or_prefix]
|
||||
|
||||
{
|
||||
:mode2prefix
|
||||
:prefix2mode
|
||||
:convert
|
||||
}
|
|
@ -1,43 +0,0 @@
|
|||
irce = require "irce"
|
||||
socket = require "socket"
|
||||
|
||||
config =
|
||||
server: os.getenv("IRC_HOST") or "127.0.0.1"
|
||||
sname: os.getenv("KETRACEL_SNAME") or "ketracel.akua"
|
||||
spass: os.getenv("KETRACEL_SPASS") or error("need KETRACEL_SPASS")
|
||||
sreal: os.getenv("KETRACEL_SREAL") or "The favorite of the Jem'Hadar"
|
||||
debug: os.getenv("KETRACEL_DEBUG")
|
||||
nicklen: os.getenv("KETRACEL_NICKLEN") or "31"
|
||||
|
||||
irc = irce.new!
|
||||
running = true
|
||||
|
||||
-- load IRC modules
|
||||
assert irc\load_module require "irce.modules.ngircd"
|
||||
assert irc\load_module require "bots.ketracel"
|
||||
|
||||
client = socket.tcp!
|
||||
client\settimeout 1
|
||||
|
||||
irc\set_send_func (message) =>
|
||||
client\send message
|
||||
|
||||
if config.debug
|
||||
irc\set_callback irce.RAW, (send, message) =>
|
||||
print string.format "%s %s", (send and ">" or "<"), message
|
||||
|
||||
print "Ketracel loaded using " .. irce._VERSION .. " running on " .. _VERSION
|
||||
|
||||
-- connect to irc server
|
||||
assert client\connect config.server, 6667
|
||||
|
||||
assert irc\REGISTER config.spass, "ketracel", "0.0.1", config.sname, config.sreal, config.nicklen
|
||||
|
||||
if config.oper
|
||||
irc\OPER config.nick, config.oper
|
||||
print "IRC operator status requested for " .. config.nick
|
||||
|
||||
while running
|
||||
irc\process client\receive!
|
||||
|
||||
client\close!
|
|
@ -0,0 +1,3 @@
|
|||
include_rules
|
||||
.gitignore
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
ln = require "ln"
|
||||
stringx = require "pl.stringx"
|
||||
|
||||
class CommandRouter
|
||||
new: (bot, cmdchar = "?") =>
|
||||
@bot = bot
|
||||
@cmdchar = cmdchar
|
||||
@commands = {}
|
||||
|
||||
register: (verb, action) =>
|
||||
self.commands[verb] = action
|
||||
|
||||
run: (sender, target, verb, args) =>
|
||||
verb = string.upper verb
|
||||
cmd = self.commands[verb]
|
||||
if cmd == nil
|
||||
@bot.irc\NOTICE @bot.name, sender, "unknown command verb " .. verb
|
||||
return
|
||||
|
||||
cmd sender, target, verb, args
|
||||
|
||||
privmsg: (sender, params) =>
|
||||
cmdchar = params[2]\sub 1, 1
|
||||
destsigil = params[1]\sub 1, 1
|
||||
|
||||
if params[1]\lower! == @bot.name\lower!
|
||||
sp = stringx.split params[2]
|
||||
cmd = sp[1]
|
||||
table.remove sp, 1
|
||||
@run sender[1], params[1], cmd, sp
|
||||
|
||||
if cmdchar == @cmdchar and destsigil == "#"
|
||||
sp = stringx.split params[2]
|
||||
cmd = string.sub sp[1], (#@cmdchar + 1)
|
||||
table.remove sp, 1
|
||||
@run sender[1], params[1], cmd, sp
|
||||
|
||||
CommandRouter
|
|
@ -0,0 +1,48 @@
|
|||
irce = require "irce"
|
||||
ln = require "ln"
|
||||
moon = require "moon"
|
||||
stringx = require "pl.stringx"
|
||||
CommandRouter = require "ketracel.bots.commands"
|
||||
|
||||
class Ketracel
|
||||
new: (irc) =>
|
||||
@name = "Ketracel"
|
||||
@irc = irc
|
||||
router = CommandRouter self
|
||||
router\register "DIE", (sender, target, verb, args) -> @die sender, target, verb, args
|
||||
router\register "VHOST", (...) -> @set_vhost ...
|
||||
router\register "STATE", ->
|
||||
router\register "EVAL", ->
|
||||
@router = router
|
||||
|
||||
burst: =>
|
||||
@irc\NICK @name, "white", "the.dominion", "+io", "Ketracel White"
|
||||
|
||||
njoin: (chan) =>
|
||||
@irc\NJOIN chan, "Ketracel"
|
||||
|
||||
die: (sender, target, verb, args) =>
|
||||
@irc\handle "DIE", string.format("%s asked me to die in %s", sender, target)
|
||||
|
||||
set_vhost: (sender, target, verb, args) =>
|
||||
if #args > 0
|
||||
ln.log :sender, vhost: args[1], action: "setting vhost"
|
||||
@irc\VHOST sender, args[1]
|
||||
@irc\NOTICE "Ketracel", sender, "your vhost is now " ..args[1]
|
||||
else
|
||||
@irc\NOTICE "Ketracel", sender, "usage: VHOST <your.vhost>"
|
||||
|
||||
{
|
||||
init: (state) =>
|
||||
state.bot = Ketracel self
|
||||
|
||||
hooks:
|
||||
["376"]: (state) =>
|
||||
state.bot\burst!
|
||||
|
||||
["NJOIN"]: (state, chan) =>
|
||||
state.bot\njoin chan
|
||||
|
||||
["PRIVMSG"]: (state, sender, params) =>
|
||||
state.bot.router\privmsg sender, params
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
irce = require "irce"
|
||||
ln = require "ln"
|
||||
socket = require "socket"
|
||||
server = require "ketracel.server"
|
||||
|
||||
config =
|
||||
server: os.getenv("IRC_HOST") or "127.0.0.1"
|
||||
sname: os.getenv("KETRACEL_SNAME") or "ketracel.akua"
|
||||
spass: os.getenv("KETRACEL_SPASS") or error("need KETRACEL_SPASS")
|
||||
sreal: os.getenv("KETRACEL_SREAL") or "The favorite of the Jem'Hadar"
|
||||
debug: os.getenv("KETRACEL_DEBUG")
|
||||
nicklen: os.getenv("KETRACEL_NICKLEN") or "31"
|
||||
|
||||
with server.Server config
|
||||
\run!
|
|
@ -0,0 +1,59 @@
|
|||
irce = require "irce"
|
||||
ln = require "ln"
|
||||
socket = require "socket"
|
||||
|
||||
class Server
|
||||
new: (config) =>
|
||||
@config = config
|
||||
sock = socket.tcp!
|
||||
irc = irce.new!
|
||||
|
||||
irc\load_module require "irce.modules.ngircd"
|
||||
irc\load_module require "ketracel.bots.ketracel"
|
||||
|
||||
irc\set_send_func (message) =>
|
||||
sock\send message
|
||||
|
||||
if config.debug
|
||||
ln.log {"msg": "debug enabled"}, config
|
||||
irc\set_callback irce.RAW, (send, message) =>
|
||||
sigil = send and ">" or "<"
|
||||
print string.format "%s %s", (send and ">" or "<"), message
|
||||
|
||||
ln.log msg: "Ketracel loaded", irce: irce._VERSION, lua: _VERSION
|
||||
|
||||
assert sock\connect config.server, 6667
|
||||
assert irc\REGISTER config.spass, "ketracel", "0.0.1", config.sname, config.sreal, config.nicklen
|
||||
|
||||
@irc = irc
|
||||
@socket = sock
|
||||
|
||||
wait_for: (event, checker) =>
|
||||
running = true
|
||||
|
||||
@irc\set_callback event, (...) =>
|
||||
if checker and not checker(...)
|
||||
return
|
||||
print "! got event " .. event if os.getenv "DEBUG"
|
||||
running = false
|
||||
|
||||
while running
|
||||
@irc\process @socket\receive!
|
||||
|
||||
@irc\clear_callback event
|
||||
|
||||
run: =>
|
||||
running = true
|
||||
|
||||
@irc\set_callback "DIE", (why) =>
|
||||
ln.err why, {msg: "told to die"}
|
||||
running = false
|
||||
|
||||
while running
|
||||
@irc\process @socket\receive!
|
||||
|
||||
@socket\close!
|
||||
|
||||
{
|
||||
:Server
|
||||
}
|
|
@ -0,0 +1,47 @@
|
|||
irce = require "irce"
|
||||
socket = require "socket"
|
||||
|
||||
get_client_modules = (irc) ->
|
||||
irc\load_module require "irce.modules.base"
|
||||
irc\load_module require "irce.modules.message"
|
||||
irc\load_module require "irce.modules.channel"
|
||||
|
||||
class Client
|
||||
new: (nick) =>
|
||||
@nick = nick
|
||||
sock = socket.tcp!
|
||||
irc = irce.new!
|
||||
get_client_modules irc
|
||||
irc\set_send_func (message) =>
|
||||
print string.format "[client %s] > %s", nick, message if os.getenv "DEBUG"
|
||||
sock\send message
|
||||
|
||||
sock\connect "127.0.0.1", 6667
|
||||
irc\NICK nick
|
||||
irc\USER nick, nick
|
||||
|
||||
@socket = sock
|
||||
@irc = irc
|
||||
|
||||
wait_for: (event, checker) =>
|
||||
running = true
|
||||
nick = @nick
|
||||
@irc\set_callback event, (...) =>
|
||||
if checker and not checker ...
|
||||
return
|
||||
print string.format "[client %s] ! got event %s", nick, event if os.getenv "DEBUG"
|
||||
running = false
|
||||
while running
|
||||
msg = assert @socket\receive!
|
||||
print string.format "[client %s] < %s", nick, msg if os.getenv "DEBUG"
|
||||
@irc\process msg
|
||||
|
||||
@irc\clear_callback event
|
||||
|
||||
quit: =>
|
||||
@irc\QUIT "bye"
|
||||
@socket\close!
|
||||
|
||||
{
|
||||
:Client
|
||||
}
|
Loading…
Reference in New Issue