aboutsummaryrefslogtreecommitdiffstats
path: root/luaevent.lua
diff options
context:
space:
mode:
Diffstat (limited to 'luaevent.lua')
-rw-r--r--luaevent.lua157
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