lua/luaevent.lua

1
--[[
2
	LuaEvent - Copyright (C) 2007 Thomas Harning <harningt@gmail.com>
3
	Licensed as LGPL - See doc/COPYING for details.
4
]]
5
module("luaevent", package.seeall)
6
require("luaevent.core")
7
 
8
_NAME = "luaevent";
9
_VERSION = "0.3.2";
10
 
11
local EV_READ = luaevent.core.EV_READ
12
local EV_WRITE = luaevent.core.EV_WRITE
13
local base = luaevent.core.new()
14
 
15
local function addevent(...)
16
	return base:addevent(...)
17
end
18
 
19
local function getWrapper()
20
	local running = coroutine.running()
21
	return function(...)
22
		return select(2, coroutine.resume(running, ...))
23
	end
24
end
25
-- Weak keys.. the keys are the client sockets
26
local clientTable = setmetatable({}, {'__mode', 'kv'})
27
local function socketWait(sock, event)
28
	if not clientTable[sock] then clientTable[sock] = addevent(sock, event, getWrapper()) end
29
	coroutine.yield(event)
30
end
31
 
32
 
33
function send(sock, data, start, stop)
34
	local s, err
35
	local from = start or 1
36
	local sent = 0
37
	repeat
38
		from = from + sent
39
		s, err, sent = sock:send(data, from, stop)
40
		if s or err ~= "timeout" then return s, err, sent end
41
		socketWait(sock, EV_WRITE)
42
	until false
43
end
44
function receive(sock, pattern, part)
45
	local s, err
46
	pattern = pattern or '*l'
47
	repeat
48
		s, err, part = sock:receive(pattern, part)
49
		if s or err ~= "timeout" then return s, err, part end
50
		socketWait(sock, EV_READ)
51
	until false
52
end
53
-- same as above but with special treatment when reading chunks,
54
-- unblocks on any data received.
55
function receivePartial(client, pattern)
56
	local s, err, part
57
	pattern = pattern or "*l"
58
	repeat
59
	s, err, part = client:receive(pattern)
60
	if s or ( (type(pattern)=="number") and part~="" and part ~=nil ) or 
61
		err ~= "timeout" then return s, err, part end
62
		socketWait(sock, EV_READ)
63
	until false
64
end
65
function connect(sock, ...)
66
	sock:settimeout(0)
67
	local ret, err = sock:connect(...)
68
	if ret or err ~= "timeout" then return ret, err end
69
	socketWait(sock, EV_WRITE)
70
	ret, err = sock:connect(...)
71
	if err == "already connected" then
72
		return 1
73
	end
74
	return ret, err
75
end
76
-- Deprecated..
77
function flush(sock)
78
end
79
local function clientCoroutine(sock, handler)
80
	-- Figure out what to do ......
81
	return handler(sock)
82
end
83
local function handleClient(co, client, handler)
84
	local ok, res, event = coroutine.resume(co, client, handler)
85
end
86
local function serverCoroutine(sock, callback)
87
	local listenItem = addevent(sock, EV_READ, getWrapper())
88
	repeat
89
		local event = coroutine.yield(EV_READ)
90
		-- Get new socket
91
		local client = sock:accept()
92
		if client then
93
			client:settimeout(0)
94
			local co = coroutine.create(clientCoroutine)
95
			handleClient(co, client, callback)
96
		end
97
	until false
98
end
99
function addserver(sock, callback)
100
	local coro = coroutine.create(serverCoroutine)
101
	assert(coroutine.resume(coro, sock, callback))
102
end
103
function addthread(func, ...)
104
	return coroutine.resume(coroutine.create(func), ...)
105
end
106
local _skt_mt = {__index = {
107
	connect = function(self, ...)
108
		return connect(self.socket, ...)
109
	end,
110
	send = function (self, data)
111
		return send(self.socket, data)
112
	end,
113
	
114
	receive = function (self, pattern)
115
		if (self.timeout==0) then
116
  			return receivePartial(self.socket, pattern)
117
  		end
118
		return receive(self.socket, pattern)
119
	end,
120
	
121
	flush = function (self)
122
		return flush(self.socket)
123
	end,
124
	
125
	settimeout = function (self,time)
126
		self.timeout=time
127
		return
128
	end,
129
	
130
	close = function(self)
131
		clientTable[self.socket]:close()
132
		self.socket:close()
133
	end
134
}}
135
function wrap(sock)
136
	return setmetatable({socket = sock}, _skt_mt)
137
end
138
loop = function(...) base:loop(...) end