73 lines
2.0 KiB
Lua
73 lines
2.0 KiB
Lua
--- Copas specific client handling module.
|
|
-- Typically this module is not used directly, but through `mqtt.loop` when
|
|
-- auto-detecting the environment.
|
|
-- @module mqtt.loop.copas
|
|
|
|
local copas = require "copas"
|
|
local log = require "mqtt.log"
|
|
|
|
local client_registry = {}
|
|
|
|
local _M = {}
|
|
|
|
|
|
--- Add MQTT client to the Copas scheduler.
|
|
-- Each received packet will be handled by a new thread, such that the thread
|
|
-- listening on the socket can return immediately.
|
|
-- The client will automatically be removed after it exits. It will set up a
|
|
-- thread to call `Client:check_keep_alive`.
|
|
-- @param cl mqtt-client to add to the Copas scheduler
|
|
-- @return `true` on success or `false` and error message on failure
|
|
function _M.add(cl)
|
|
if client_registry[cl] then
|
|
log:warn("MQTT client '%s' was already added to Copas", cl.opts.id)
|
|
return false, "MQTT client was already added to Copas"
|
|
end
|
|
client_registry[cl] = true
|
|
|
|
do -- make mqtt device async for incoming packets
|
|
local handle_received_packet = cl.handle_received_packet
|
|
local count = 0
|
|
-- replace packet handler; create a new thread for each packet received
|
|
cl.handle_received_packet = function(mqttdevice, packet)
|
|
count = count + 1
|
|
copas.addnamedthread(handle_received_packet, cl.opts.id..":receive_"..count, mqttdevice, packet)
|
|
return true
|
|
end
|
|
end
|
|
|
|
-- add keep-alive timer
|
|
local timer = copas.addnamedthread(function()
|
|
while client_registry[cl] do
|
|
local next_check = cl:check_keep_alive()
|
|
if next_check > 0 then
|
|
copas.pause(next_check)
|
|
end
|
|
end
|
|
end, cl.opts.id .. ":keep_alive")
|
|
|
|
-- add client to connect and listen
|
|
copas.addnamedthread(function()
|
|
while client_registry[cl] do
|
|
local timeout = cl:step()
|
|
if not timeout then
|
|
client_registry[cl] = nil -- exiting
|
|
log:debug("MQTT client '%s' exited, removed from Copas", cl.opts.id)
|
|
copas.wakeup(timer)
|
|
else
|
|
if timeout > 0 then
|
|
copas.pause(timeout)
|
|
end
|
|
end
|
|
end
|
|
end, cl.opts.id .. ":listener")
|
|
|
|
return true
|
|
end
|
|
|
|
return setmetatable(_M, {
|
|
__call = function(self, ...)
|
|
return self.add(...)
|
|
end,
|
|
})
|