Merge branch 'feature/zeroTimeoutHandling' into develop
[luaevent.git] / lua / luaevent.lua
blobfa3952a1ccc8847c69d5f6bec84ebc72bcc17bef
1 --[[
2 LuaEvent
3 Copyright (C) 2007,2012,2013 Thomas Harning <harningt@gmail.com>
5 Permission is hereby granted, free of charge, to any person obtaining a copy
6 of this software and associated documentation files (the "Software"), to deal
7 in the Software without restriction, including without limitation the rights
8 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 copies of the Software, and to permit persons to whom the Software is
10 furnished to do so, subject to the following conditions:
12 The above copyright notice and this permission notice shall be included in
13 all copies or substantial portions of the Software.
15 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 THE SOFTWARE.
23 local _M = {}
24 local core = require("luaevent.core")
26 _M.core = core
27 _M._NAME = "luaevent"
28 _M._VERSION = "0.4.4"
30 local EV_READ = core.EV_READ
31 local EV_WRITE = core.EV_WRITE
32 local base = core.new()
34 local function addevent(...)
35 return base:addevent(...)
36 end
38 local function getWrapper()
39 local running = coroutine.running()
40 return function(...)
41 return select(2, coroutine.resume(running, ...))
42 end
43 end
44 -- Weak keys.. the keys are the client sockets
45 local clientTable = setmetatable({}, {'__mode', 'kv'})
46 local function socketWait(sock, event)
47 if not clientTable[sock] then clientTable[sock] = addevent(sock, event, getWrapper()) end
48 coroutine.yield(event)
49 end
52 function _M.send(sock, data, start, stop)
53 local s, err
54 local from = start or 1
55 local sent = 0
56 repeat
57 from = from + sent
58 s, err, sent = sock:send(data, from, stop)
59 if s or err ~= "timeout" then return s, err, sent end
60 socketWait(sock, EV_WRITE)
61 until false
62 end
63 function _M.receive(sock, pattern, part)
64 local s, err
65 pattern = pattern or '*l'
66 repeat
67 s, err, part = sock:receive(pattern, part)
68 if s or err ~= "timeout" then return s, err, part end
69 socketWait(sock, EV_READ)
70 until false
71 end
72 -- same as above but with special treatment when reading chunks,
73 -- unblocks on any data received.
74 function _M.receivePartial(client, pattern)
75 local s, err, part
76 pattern = pattern or "*l"
77 repeat
78 s, err, part = client:receive(pattern)
79 if s or ( (type(pattern)=="number") and part~="" and part ~=nil ) or err ~= "timeout" then
80 return s, err, part
81 end
82 socketWait(client, EV_READ)
83 until false
84 end
85 function _M.connect(sock, ...)
86 sock:settimeout(0)
87 local ret, err = sock:connect(...)
88 if ret or err ~= "timeout" then return ret, err end
89 socketWait(sock, EV_WRITE)
90 ret, err = sock:connect(...)
91 if err == "already connected" then
92 return 1
93 end
94 return ret, err
95 end
96 -- Deprecated..
97 function _M.flush(sock)
98 end
99 local function clientCoroutine(sock, handler)
100 -- Figure out what to do ......
101 return handler(sock)
103 local function handleClient(co, client, handler)
104 local ok, res, event = coroutine.resume(co, client, handler)
106 local function serverCoroutine(sock, callback)
107 local listenItem = addevent(sock, EV_READ, getWrapper())
108 repeat
109 local event = coroutine.yield(EV_READ)
110 -- Get new socket
111 local client = sock:accept()
112 if client then
113 client:settimeout(0)
114 local co = coroutine.create(clientCoroutine)
115 handleClient(co, client, callback)
117 until false
119 function _M.addserver(sock, callback)
120 local coro = coroutine.create(serverCoroutine)
121 assert(coroutine.resume(coro, sock, callback))
123 function _M.addthread(func, ...)
124 return coroutine.resume(coroutine.create(func), ...)
126 local _skt_mt = {__index = {
127 connect = function(self, ...)
128 return _M.connect(self.socket, ...)
129 end,
130 send = function (self, data)
131 return _M.send(self.socket, data)
132 end,
134 receive = function (self, pattern)
135 if (self.timeout==0) then
136 return _M.receivePartial(self.socket, pattern)
138 return _M.receive(self.socket, pattern)
139 end,
141 flush = function (self)
142 return _M.flush(self.socket)
143 end,
145 settimeout = function (self,time)
146 self.timeout=time
147 return
148 end,
150 close = function(self)
151 clientTable[self.socket]:close()
152 self.socket:close()
155 function _M.wrap(sock)
156 return setmetatable({socket = sock}, _skt_mt)
158 _M.loop = function(...) base:loop(...) end
160 return _M