Mercurial > prosody-modules
changeset 2455:dc30ca5ce315
mod_csi_pump: Lossless CSI mode
author | Kim Alvefur <zash@zash.se> |
---|---|
date | Sun, 22 Jan 2017 00:41:11 +0100 |
parents | 51cf82d36a8a |
children | f3fc2b672df3 |
files | mod_csi_pump/README.markdown mod_csi_pump/mod_csi_pump.lua |
diffstat | 2 files changed, 105 insertions(+), 0 deletions(-) [+] |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mod_csi_pump/README.markdown Sun Jan 22 00:41:11 2017 +0100 @@ -0,0 +1,9 @@ +--- +description: Lossless CSI module +--- + +Stanzas are queued in a buffer until either an "important" stanza is +encountered or the buffer becomes full. Then all queued stanzas are sent +at the same time. This way, nothing is lost or reordered while still +allowing for power usage savings by not requiring mobile clients to +bring up their radio for unimportant stanzas.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mod_csi_pump/mod_csi_pump.lua Sun Jan 22 00:41:11 2017 +0100 @@ -0,0 +1,96 @@ +-- Copyright (C) 2016 Kim Alvefur +-- + +module:depends"csi" +module:depends"track_muc_joins" +local jid = require "util.jid"; +local new_queue = require "util.queue".new; + +local function new_pump(output, ...) + -- luacheck: ignore 212/self + local q = new_queue(...); + local flush = true; + function q:pause() + flush = false; + end + function q:resume() + flush = true; + return q:flush(); + end + local push = q.push; + function q:push(item) + local ok = push(self, item); + if not ok then + q:flush(); + output(item, self); + elseif flush then + return q:flush(); + end + return true; + end + function q:flush() + local item = self:pop(); + while item do + output(item, self); + item = self:pop(); + end + return true; + end + return q; +end + +-- TODO delay stamps +-- local dt = require "util.datetime"; + +local function is_important(stanza, session) + local st_name = stanza.name; + if not st_name then return false; end + local st_type = stanza.attr.type; + if st_name == "presence" then + -- TODO check for MUC status codes? + return false; + elseif st_name == "message" then + if st_type == "headline" then + return false; + end + local body = stanza:get_child_text("body"); + if not body then return false; end + if st_type == "groupchat" then + if body:find(session.username, 1, true) then return true; end + local rooms = session.rooms_joined; + if not rooms then return false; end + local room_nick = rooms[jid.bare(stanza.attr.from)]; + if room_nick and body:find(room_nick, 1, true) then return true; end + return false; + end + return body; + end + return true; +end + +module:hook("csi-client-inactive", function (event) + local session = event.origin; + if session.pump then + session.pump:pause(); + else + session._orig_send = session.send; + local pump = new_pump(session.send, 100); + pump:pause(); + session.pump = pump; + function session.send(stanza) + pump:push(stanza); + if is_important(stanza, session) then + pump:flush(); + end + return true; + end + end +end); + +module:hook("csi-client-active", function (event) + local session = event.origin; + if session.pump then + session.pump:resume(); + end +end); +