Compare commits

..

No commits in common. "master" and "ngircd-link" have entirely different histories.

22 changed files with 100 additions and 610 deletions

View File

@ -2,10 +2,4 @@ FROM xena/lua:5.3
WORKDIR /ketracel WORKDIR /ketracel
COPY . . COPY . .
ENV PATH $PATH:/root/.luarocks/bin ENV PATH $PATH:/root/.luarocks/bin
RUN apk --no-cache add ngircd \ RUN ./scripts/build_docker.sh
&& 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

View File

@ -2,4 +2,4 @@
export LUA_PATH='/root/.luarocks/share/lua/5.3/?.lua;/root/.luarocks/share/lua/5.3/?/init.lua' 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' export LUA_CPATH='/root/.luarocks/lib/lua/5.3/?.so'
lua5.3 -l ketracel.main lua5.3 -l ketracel

View File

@ -16,19 +16,11 @@ dependencies = {
"lua ~> 5.3", "lua ~> 5.3",
"irc-engine", "irc-engine",
"luasocket", "luasocket",
"ln",
"uuid",
} }
build = { build = {
type = "builtin", type = "builtin",
modules = { modules = {
["ketracel.bots.commands"] = "src/ketracel/bots/commands.lua", ["ketracel"] = "src/ketracel.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", ["irce.modules.oper"] = "src/irce/modules/oper.lua",
}, },
install = { install = {

View File

@ -1,17 +0,0 @@
#!/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

View File

@ -2,4 +2,4 @@
tup tup
cd src cd src
godotenv -f ../.env lua5.3 -l set_paths ./ketracel/main.lua godotenv -f ../.env lua5.3 -l set_paths ketracel.lua

View File

@ -1,4 +0,0 @@
#!/bin/sh
moonc `find -type f | grep -v spec | grep 'moon$'`
busted -o TAP

View File

@ -1,46 +0,0 @@
[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

View File

@ -1,27 +0,0 @@
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

View File

@ -1,87 +0,0 @@
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"

View File

@ -1,20 +0,0 @@
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)

40
src/bots/ketracel.moon Normal file
View File

@ -0,0 +1,40 @@
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
}

View File

@ -1,43 +0,0 @@
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

View File

@ -2,8 +2,6 @@ irce = require "irce"
util = require "irce.util" util = require "irce.util"
stringx = require "pl.stringx" stringx = require "pl.stringx"
moon = require "moon" moon = require "moon"
ln = require "ln"
modeconv = require "irce.modules.ngircd.modes"
{ {
init: (state) => init: (state) =>
@ -13,10 +11,10 @@ modeconv = require "irce.modules.ngircd.modes"
senders: senders:
["REGISTER"]: (state, password, software, version, sname, real, nicklen) => ["REGISTER"]: (state, password, software, version, sname, real, nicklen) =>
assert @PASS password, software, version assert self\PASS password, software, version
assert @SERVER sname, real assert self\SERVER sname, real
assert @NICKLEN nicklen assert self\NICKLEN nicklen
assert @EMOTD! assert self\EMOTD!
string.format ":%s PING :%s", sname, sname string.format ":%s PING :%s", sname, sname
["PASS"]: (state, password, software, version) => ["PASS"]: (state, password, software, version) =>
@ -45,124 +43,35 @@ modeconv = require "irce.modules.ngircd.modes"
["NICK"]: (state, nick, user, host, modes, real) => ["NICK"]: (state, nick, user, host, modes, real) =>
state.clients[string.lower nick] = state.clients[string.lower nick] =
:nick, :user, :host, modes: string.sub(modes, 2), :real, metadata: {} :nick, :user, :host, :modes, :real, metadata: {}
string.format ":%s NICK %s 1 %s %s 1 %s :%s", state.sname, nick, user, host, modes, real string.format ":%s NICK %s 1 %s %s 1 %s :%s", state.sname, nick, user, host, modes, real
["CHANINFO"]: (state, channame) => ["NJOIN"]: (state, channame, who) =>
if state.channels[channame] == nil string.format ":%s NJOIN %s :%s", state.sname, channame, who
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) => ["METADATA"]: (state, nick, key, val) =>
state.clients[string.lower nick].metadata[key] = val state.clients[string.lower nick].metadata[key] = val
string.format ":%s METADATA %s %s :%s", state.sname, nick, key, val string.format ":%s METADATA %s %s :%s", state.sname, nick, key, val
["VHOST"]: (state, nick, vhost) => ["VHOST"]: (state, nick, vhost) =>
@METADATA nick, "cloakhost", vhost self\METADATA nick, "cloakhost", vhost
string.format ":%s MODE %s +x", state.sname, nick string.format ":%s MODE %s +x", state.sname, nick
["PRIVMSG"]: (state, nick, target, message) => ["PRIVMSG"]: (state, nick, target, message) =>
string.format ":%s PRIVMSG %s :%s", 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: handlers:
["461"]: (state, sender, params) =>
@handle "DIE", string.format("%s: %s", sender[1], params[1])
["ERROR"]: (state, sender, params) => ["ERROR"]: (state, sender, params) =>
error string.format "%s: %s", sender[1], params[1] error string.format "%s: %s", sender[1], params[1]
["PING"]: (state, sender, params) => ["PING"]: (state, sender, params) =>
@send "PONG", params[1] self\send "PONG", params[1]
sender, params[1] sender, params[1]
["PONG"]: (state, sender, params) => ["PONG"]: (state, sender, params) =>
sender, params[1] 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) => ["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] nick = params[1]
user = params[3] user = params[3]
host = params[4] host = params[4]
@ -173,7 +82,7 @@ modeconv = require "irce.modules.ngircd.modes"
state.clients[string.lower nick] = state.clients[string.lower nick] =
:nick, :user, :host, :modes, :real, :metadata :nick, :user, :host, :modes, :real, :metadata
sender, state.clients[string.lower nick] sender, state.clients[nick]
["METADATA"]: (state, sender, params) => ["METADATA"]: (state, sender, params) =>
nick = params[1] nick = params[1]
@ -187,13 +96,6 @@ modeconv = require "irce.modules.ngircd.modes"
chan = params[1] chan = params[1]
whose = stringx.split tostring(params[2]), "," 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 for k, v in pairs whose
pfxlen = string.find v, "%a+" pfxlen = string.find v, "%a+"
nick = string.lower string.sub v, pfxlen nick = string.lower string.sub v, pfxlen
@ -201,7 +103,7 @@ modeconv = require "irce.modules.ngircd.modes"
pfxarr = {} pfxarr = {}
for i = 1, #prefix for i = 1, #prefix
pfxarr[i] = modeconv.convert string.sub prefix, i, i pfxarr[i] = string.sub prefix, i, i
state.channels[chan].members[nick] = pfxarr state.channels[chan].members[nick] = pfxarr
@ -225,24 +127,19 @@ modeconv = require "irce.modules.ngircd.modes"
state.channels[name] = state.channels[name] =
:name, :mode, :topic, :key, :limit, members: {} :name, :mode, :topic, :key, :limit, members: {}
state.channels[name]
["PRIVMSG"]: (state, sender, params) => ["PRIVMSG"]: (state, sender, params) =>
if params[2] == "?state"
moon.p state
return sender, params
if sender[1] == "Cadey" and stringx.startswith params[2], "?eval" if sender[1] == "Cadey" and stringx.startswith params[2], "?eval"
code = string.sub(params[2], 7) code = string.sub(params[2], 7)
print string.format "%s %s %s - evaling", params[1], sender[1], code print string.format "%s %s %s - evaling", params[1], sender[1], code
fun, err = load(code, sender[1].."-"..params[1], "t", { fun, err = load(code, sender[1].."-"..params[1], "t", {
state: state, :string, irc: @, :_VERSION state: state, :string,
}) })
if err ~= nil if err ~= nil
error err error err
result = fun! result = fun!
if result ~= nil if result ~= nil
@PRIVMSG state.sname, params[1], tostring result self\PRIVMSG state.sname, params[1], tostring result
sender, params sender, params

View File

@ -1,22 +0,0 @@
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
}

43
src/ketracel.moon Normal file
View File

@ -0,0 +1,43 @@
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!

View File

@ -1,3 +0,0 @@
include_rules
.gitignore

View File

@ -1,38 +0,0 @@
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

View File

@ -1,48 +0,0 @@
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
}

View File

@ -1,15 +0,0 @@
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!

View File

@ -1,59 +0,0 @@
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
}

View File

@ -1,47 +0,0 @@
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
}