luaevent/luaevent.lua

Mon, 11 Jun 2007 01:08:59 +0000

author
Thomas Harning Jr <harningt@gmail.com>
date
Mon, 11 Jun 2007 01:08:59 +0000
changeset 2
01b3a96ae760
parent 1
31c782cfe7fe
child 3
5999243fab1d
permissions
-rw-r--r--

* Completed mostly working version
* Moved to a mode where addevent calls a callback rather than
it being instantiated within.
* If the callback returns -1, then no event is ever setup
* Otherwise the integer value is used to setup the event
* This allows for using coroutine.wrap rather than a cooked-up wrapper
* Tests work, although there are a few remaining issues:
* Need to figure a good way of preserving the event object,
not sure if current method is good enough, since the socket
is the only anchor, and it is only held inside the coro..
circular reference, something that Lua 'handles' well.
* Doing more than the maximum sockets the process is allows
causes strangeness to occur in libevent.. somehow
it is getting around to epoll_add which is causing valgrind
to barf.

--[[
	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

local hookedObjectMt = false

-- Weak keys.. the keys are the client sockets
local clientTable = setmetatable({}, {'__mode', 'k'})

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
			coroutine.yield(EV_WRITE)
		end
		if s or err ~= "timeout" then return s, err, sent 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
		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
		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
	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 serverCoroutine(sock, callback)
	repeat
		local event = coroutine.yield(EV_READ)
		-- Get new socket
		local client = sock:accept()
		if client then
			--cl[#cl + 1] = client
			client:settimeout(0)
			local coFunc = coroutine.wrap(clientCoroutine)
			clientTable[client] = luaevent.core.addevent(client, coFunc, client, callback)
		end
	until false
end

local oldAddEvent = luaevent.core.addevent
luaevent.core.addevent = function(...)
	local item = oldAddEvent(...)
	print("SETUP ITEM FOR: ", debug.getmetatable(item).getfd(item))
	if not hookedObjectMt then
		hookedObjectMt = true
		local mt = debug.getmetatable(item)
		local oldGC = mt.__gc
		mt.__gc = function(...)
			print("RELEASING ITEM FOR: ", mt.getfd(...))
			return oldGC(...)
		end
	end
	return item
end

function addserver(sock, callback)
	local coFunc = coroutine.wrap(serverCoroutine)
	clientTable[sock] = luaevent.core.addevent(sock, coFunc, sock, callback)
end
function addthread(sock, func, ...)
	local coFunc = coroutine.wrap(func)
	clientTable[sock] = luaevent.core.addevent(sock, coFunc, ...)
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,
}}
function wrap(sock)
	return setmetatable({socket = sock}, _skt_mt)
end
loop = luaevent.core.loop

mercurial