1 -- Prosody IM |
|
2 -- Copyright (C) 2014 Daurnimator |
|
3 -- |
|
4 -- This project is MIT/X11 licensed. Please see the |
|
5 -- COPYING file in the source package for more information. |
|
6 -- |
|
7 -- This module allows you to use cqueues with a net.server mainloop |
|
8 -- |
|
9 |
|
10 local server = require "net.server"; |
|
11 local cqueues = require "cqueues"; |
|
12 |
|
13 -- Create a single top level cqueue |
|
14 local cq; |
|
15 |
|
16 if server.cq then -- server provides cqueues object |
|
17 cq = server.cq; |
|
18 elseif server.get_backend() == "select" and server._addtimer then -- server_select |
|
19 cq = cqueues.new(); |
|
20 local function step() |
|
21 assert(cq:loop(0)); |
|
22 end |
|
23 |
|
24 -- Use wrapclient (as wrapconnection isn't exported) to get server_select to watch cq fd |
|
25 local handler = server.wrapclient({ |
|
26 getfd = function() return cq:pollfd(); end; |
|
27 settimeout = function() end; -- Method just needs to exist |
|
28 close = function() end; -- Need close method for 'closeall' |
|
29 }, nil, nil, {}); |
|
30 |
|
31 -- Only need to listen for readable; cqueues handles everything under the hood |
|
32 -- readbuffer is called when `select` notes an fd as readable |
|
33 handler.readbuffer = step; |
|
34 |
|
35 -- Use server_select low lever timer facility, |
|
36 -- this callback gets called *every* time there is a timeout in the main loop |
|
37 server._addtimer(function(current_time) |
|
38 -- This may end up in extra step()'s, but cqueues handles it for us. |
|
39 step(); |
|
40 return cq:timeout(); |
|
41 end); |
|
42 elseif server.event and server.base then -- server_event |
|
43 cq = cqueues.new(); |
|
44 -- Only need to listen for readable; cqueues handles everything under the hood |
|
45 local EV_READ = server.event.EV_READ; |
|
46 server.base:addevent(cq:pollfd(), EV_READ, function(e) |
|
47 assert(cq:loop(0)); |
|
48 -- Convert a cq timeout to an acceptable timeout for luaevent |
|
49 local t = cq:timeout(); |
|
50 if t == 0 then -- if you give luaevent 0, it won't call this callback again |
|
51 t = 0.000001; -- 1 microsecond is the smallest that works (goes into a `struct timeval`) |
|
52 elseif t == nil then -- you always need to give a timeout, pick something big if we don't have one |
|
53 t = 0x7FFFFFFF; -- largest 32bit int |
|
54 end |
|
55 return EV_READ, t; |
|
56 end, |
|
57 -- Schedule the callback to fire on first tick to ensure any cq:wrap calls that happen during start-up are serviced. |
|
58 0.000001); |
|
59 else |
|
60 error "NYI" |
|
61 end |
|
62 |
|
63 return { |
|
64 cq = cq; |
|
65 } |
|