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