Refactored structure

This commit is contained in:
Jakob Ovrum 2010-03-10 20:03:36 +09:00
parent 4f17455fbe
commit d992dcc9ae
1 changed files with 37 additions and 212 deletions

249
init.lua
View File

@ -1,97 +1,44 @@
--[[
Lua IRC library
Copyright (c) 2010 Jakob Ovrum
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use,
copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.]]
local socket = require "socket"
local error = error
local setmetatable = setmetatable
local rawget = rawget
local ipairs = ipairs
local print = print
local unpack = unpack
local pairs = pairs
local string = string
local tostring = tostring
local table = table
local type = type
local assert = assert
local require = require
module("irc")
local print = print
local function assert(b, err, errlevel)
if not b then
error(err, errlevel or 3)
end
return b
end
debug = false
local clients = {}
module "irc"
local meta = {}
meta.__index = meta
_META = meta
require "irc.util"
require "irc.asyncoperations"
local meta_preconnect = {}
local function postAuth_join(o, channel, key)
if key then
o:send("JOIN %s :%s", channel, key)
else
o:send("JOIN %s", channel)
end
end
function meta_preconnect.__index(o, k)
local v = rawget(meta_preconnect, k)
if not v and meta[k] then
error("field '"..k.."' is not accessible before connecting", 2)
end
return v
local v = rawget(meta_preconnect, k)
if not v and meta[k] then
error("field '"..k.."' is not accessible before connecting", 2)
end
return v
end
function new(user)
local o = {}
o.nick = assert(user.nick, "Field 'nick' is required")
o.username = user.username or "lua"
o.realname = user.realname or "Lua owns"
o.socket = socket.tcp()
o.hooks = {}
o.rooms = {}
o.connected = false
local o = {
nick = assert(user.nick, "Field 'nick' is required");
username = user.username or "lua";
realname = user.realname or "Lua owns";
hooks = {};
}
return setmetatable(o, meta_preconnect)
end
function think()
local think = meta.think
for _,o in ipairs(clients) do
think(o)
end
end
function meta:hook(name, id, f)
f = f or id
self.hooks[name] = self.hooks[name] or {}
@ -116,26 +63,24 @@ function meta:invoke(name, ...)
end
end
function meta:connect(server, port)
function meta_preconnect:connect(server, port, timeout)
port = port or 6667
self.socket:settimeout(30)
local succ, err = self.socket:connect(server, port)
if not succ then return nil, err end
local s = socket.tcp()
self.socket = s
s:settimeout(timeout or 30)
assert(s:connect(server, port))
setmetatable(self, meta)
self:send("USER %s 0 * :%s", self.username, self.realname)
self:send("NICK %s", self.nick)
self._i = #clients + 1
clients[self._i] = self
self.socket:settimeout(0)
self.connected = true
return true
s:settimeout(0)
repeat
self:think()
until self.authed
end
meta_preconnect.connect = meta.connect
function meta:disconnect(message)
local message = message or "Bye!"
@ -147,13 +92,8 @@ function meta:disconnect(message)
end
function meta:shutdown()
self.connected = false
self.socket:shutdown()
self.socket:close()
clients[self._i] = nil
setmetatable(self, nil)
end
@ -165,13 +105,13 @@ local function getline(self, errlevel)
self:shutdown()
error(err, errlevel)
end
return line
end
function meta:think()
while true do
local line = getline(self, 4)
local line = getline(self, 3)
if line then
self:handle(parse(line))
else
@ -180,42 +120,6 @@ function meta:think()
end
end
function parsePrefix(prefix)
local user = {}
if prefix then
user.nick, user.username, user.host = prefix:match("(.*)!(.*)@(.*)")
end
return user
end
function parse(line)
local colonsplit = line:find(":", 2)
local last
if colonsplit then
last = line:sub(colonsplit+1)
line = line:sub(1, colonsplit-2)
end
local prefix
if line:sub(1,1) == ":" then
local space = line:find(" ")
prefix = line:sub(2, space-1)
line = line:sub(space)
end
local params = {}
local it, state, init = line:gmatch("(%S+)")
local cmd = it(state, init)
for sub in it, state, init do
params[#params + 1] = sub
end
if last then params[#params + 1] = last end
return prefix, cmd, params
end
local handlers = {}
handlers["PING"] = function(o, prefix, query)
@ -223,17 +127,7 @@ handlers["PING"] = function(o, prefix, query)
end
handlers["001"] = function(o)
if type(o.config.startup) == "function" then
o.config.startup(o)
end
o.join = postAuth_join
for k,room in ipairs(o.rooms) do
o:join(room.name, room.key)
end
o.rooms = nil
o:invoke("OnConnect")
o.authed = true
end
handlers["PRIVMSG"] = function(o, prefix, channel, message)
@ -255,72 +149,16 @@ end
handlers["ERROR"] = function(o, prefix, message)
o:invoke("OnDisconnect", message, true)
o:shutdown()
error(message)
error(message, 3)
end
function meta:handle(prefix, cmd, params)
local handler = handlers[cmd]
if handler then
return handler(self, prefix, unpack(params))
handler(self, prefix, unpack(params))
end
end
function meta:send(fmt, ...)
self.socket:send(fmt:format(...) .. "\r\n")
end
function meta:sendChat(channel, msg)
toChannel = table.concat{"PRIVMSG ", channel, " :"}
for line in msg:gmatch("[^\r\n]+") do
self.socket:send(table.concat{toChannel, line, "\r\n"})
end
end
--preAuth_join
function meta:join(channel, key)
table.insert(self.rooms, {name = channel, key = key})
end
meta_preconnect.join = meta.join
function meta:part(channel)
self:send("PART %s", channel)
end
color = {
black = 1,
blue = 2,
green = 3,
red = 4,
lightred = 5,
purple = 6,
brown = 7,
yellow = 8,
lightgreen = 9,
navy = 10,
cyan = 11,
lightblue = 12,
violet = 13,
gray = 14,
lightgray = 15,
white = 16
}
local colByte = string.char(3)
setmetatable(color, {__call = function(_, text, colornum)
colornum = type(colornum) == "string" and assert(color[colornum], "Invalid color '"..colornum.."'") or colornum
return table.concat{colByte, tostring(colornum), text, colByte}
end})
local boldByte = string.char(2)
function bold(text)
return boldByte..text..boldByte
end
local underlineByte = string.char(31)
function underline(text)
return underlineByte..text..underlineByte
end
local whoisHandlers = {
["311"] = "userinfo";
["312"] = "node";
@ -354,16 +192,3 @@ function meta:whois(nick)
end
return result
end
function meta:setmode(t)
local target = t.target or self.nick
local mode = ""
local add, rem = t.add, t.remove
if add then
mode = table.concat{mode, "+", add}
elseif rem then
mode = table.concat{mode, "-", rem}
end
self:send("MODE %s %s", target, mode)
end