diff options
Diffstat (limited to 'luaevent.lua')
-rw-r--r-- | luaevent.lua | 157 |
1 files changed, 157 insertions, 0 deletions
diff --git a/luaevent.lua b/luaevent.lua new file mode 100644 index 0000000..ec9bc15 --- /dev/null +++ b/luaevent.lua @@ -0,0 +1,157 @@ +--[[ + LuaEvent - Copyright (C) 2007 Thomas Harning <harningt@gmail.com> + Licensed as LGPL - See doc/COPYING for details. +]] +module("luaevent", package.seeall) +require("luaevent.core") + +local EV_READ = luaevent.core.EV_READ +local EV_WRITE = luaevent.core.EV_WRITE +local fair = false -- Not recommended for most cases... +local base = luaevent.core.new() +local sockMap = setmetatable({}, {'__mode', 'kv'}) +local function addevent(sock, ...) + local item = base:addevent(sock, ...) + if not item then print("FAILED TO SETUP ITEM") return item end + local fd = sock:getfd() + sockMap[item] = fd + print("SETUP ITEM FOR: ", fd) + if not hookedObjectMt then + hookedObjectMt = true + --[[ + local mt = debug.getmetatable(item) + local oldGC = mt.__gc + mt.__gc = function(...) + print("RELEASING ITEM FOR: ", sockMap[(...)]) + return oldGC(...) + end]] + end + return item +end +-- Weak keys.. the keys are the client sockets +local clientTable = setmetatable({}, {'__mode', 'kv'}) + +local function getWrapper() + local running = coroutine.running() + return function(...) + if coroutine.running() == running then return end + return select(2, coroutine.resume(running, ...)) + end +end + +function send(sock, data, start, stop) + local s, err + local from = start or 1 + local sent = 0 + repeat + from = from + sent + s, err, sent = sock:send(data, from, stop) + -- Add extra coro swap for fairness + -- CURRENTLY DISABLED FOR TESTING...... + if fair and math.random(100) > 90 then + if not clientTable[sock] then clientTable[sock] = addevent(sock, EV_WRITE, getWrapper()) end + coroutine.yield(EV_WRITE) + end + if s or err ~= "timeout" then return s, err, sent end + if not clientTable[sock] then clientTable[sock] = addevent(sock, EV_WRITE, getWrapper()) end + coroutine.yield(EV_WRITE) + until false +end +function receive(sock, pattern, part) + local s, err + pattern = pattern or '*l' + repeat + s, err, part = sock:receive(pattern, part) + if s or err ~= "timeout" then return s, err, part end + if not clientTable[sock] then clientTable[sock] = addevent(sock, EV_READ, getWrapper()) end + coroutine.yield(EV_READ) + until false +end +-- same as above but with special treatment when reading chunks, +-- unblocks on any data received. +function receivePartial(client, pattern) + local s, err, part + pattern = pattern or "*l" + repeat + s, err, part = client:receive(pattern) + if s or ( (type(pattern)=="number") and part~="" and part ~=nil ) or + err ~= "timeout" then return s, err, part end + if not clientTable[sock] then clientTable[sock] = addevent(sock, EV_READ, getWrapper()) end + coroutine.yield(EV_READ) + until false +end +function connect(sock, ...) + sock:settimeout(0) + local ret, err = sock:connect(...) + if ret or err ~= "timeout" then return ret, err end + if not clientTable[sock] then clientTable[sock] = addevent(sock, EV_WRITE, getWrapper()) end + coroutine.yield(EV_WRITE) + ret, err = sock:connect(...) + if err == "already connected" then + return 1 + end + return ret, err +end +-- Deprecated.. +function flush(sock) +end +local function clientCoroutine(sock, handler) + -- Figure out what to do ...... + return handler(sock) +end +local function handleClient(co, client, handler) + local ok, res, event = coroutine.resume(co, client, handler) +end +local function serverCoroutine(sock, callback) + local listenItem = addevent(sock, EV_READ, getWrapper()) + repeat + local event = coroutine.yield(EV_READ) + -- Get new socket + local client = sock:accept() + if client then + client:settimeout(0) + local co = coroutine.create(clientCoroutine) + handleClient(co, client, callback) + end + until false +end +function addserver(sock, callback) + local coro = coroutine.create(serverCoroutine) + assert(coroutine.resume(coro, sock, callback)) +end +function addthread(func, ...) + return coroutine.resume(coroutine.create(func), ...) +end +local _skt_mt = {__index = { + connect = function(self, ...) + return connect(self.socket, ...) + end, + send = function (self, data) + return send(self.socket, data) + end, + + receive = function (self, pattern) + if (self.timeout==0) then + return receivePartial(self.socket, pattern) + end + return receive(self.socket, pattern) + end, + + flush = function (self) + return flush(self.socket) + end, + + settimeout = function (self,time) + self.timeout=time + return + end, + + close = function(self) + clientTable[self.socket]:close() + self.socket:close() + end +}} +function wrap(sock) + return setmetatable({socket = sock}, _skt_mt) +end +loop = function(...) base:loop(...) end
\ No newline at end of file |