Thu, 23 Mar 2023 15:13:14 +0000
client: Tell Verse that stanzas are "handled"
This should prevent automatic error bounces for iqs, for example.
local async = require "scansion.async"; local new_error = require "scansion.error".new_error; local verse = require "verse".init("client"); local parse_xml = require "scansion.xml".parse; local default_stanza_timeout = 3; local stanzacmp = require "scansion.stanzacmp"; local helpers = require "scansion.helpers"; return { _validate = function (client) assert(client.jid, "No JID specified"); client.stream = verse.new(verse.new_logger(client.name)); client.stream.connect_host = client.connect_host client.stream.connect_port = client.connect_port function client.log(fmt, ...) return client.stream:info(fmt, ...); end -- This one prints all received data client.stream:hook("incoming-raw", function (s) client.log("Data in: %s", s); end, 1000); client.stream:hook("outgoing-raw", function (s) client.log("Data out: %s", s); end, 1000); -- And incoming, parsed, stanzas client.stream:hook("stanza", function (s) client.log("Stanza: %s", s) end); -- Handle unexpected disconnects client.stream:hook("disconnected", function (s) if not (client.disconnect_expected or client.script.finished) or (s.reason and s.reason ~= "stream closed" and s.reason ~= "closed") then client.log("Unexpected disconnect!"); error("Unexpected disconnect"..(s.reason and " ("..tostring(s.reason)..")" or "")); end end); end; _finish = function (client) if client.stream.connected then client.disconnect_expected = true; client.stream:close(); end end; connects = function (client) local wait, done = async.waiter(); client.stream:hook("ready", function () client.stream.conn:pause() client.log"ready" done() client.log("ready done") end); client.stream:connect_client(client.jid, client.password); wait(); client.full_jid = client.stream.jid; client.host = client.stream.host; end; sends = function (client, data) local stanza = helpers.fill_vars(client.script, assert(parse_xml((table.concat(data):gsub("\t", " "))))); local wait, done = async.waiter(); local function handle_drained() client.stream:unhook("drained", handle_drained); done(); end client.stream:hook("drained", handle_drained); client.stream:send(stanza); wait(); end; receives = function (client, data) local wait, done = async.waiter(); local expected_stanza = false; local have_received_stanza = false; data = table.concat(data):gsub("\t", " "):gsub("^%s+", ""):gsub("%s+$", ""); if data ~= "nothing" then expected_stanza = helpers.fill_vars(client.script, assert(parse_xml(data))); end local function stanza_handler(received_stanza) have_received_stanza = true; if not expected_stanza then error(new_error("unexpected-stanza", { text = "Received unexpected stanza"; stanza = tostring(received_stanza); })); elseif not expected_stanza or not stanzacmp.stanzas_match(expected_stanza, received_stanza, client.script.captures) then if not expected_stanza then client.log("Received a stanza when none were expected: %s", received_stanza); else client.log("Expected: %s", expected_stanza); client.log("Received: %s", received_stanza); end error(new_error("unexpected-stanza", { text = "Received unexpected stanza"; stanza = tostring(received_stanza); expected = expected_stanza and tostring(expected_stanza) or nil; })); else client.last_received_id = received_stanza.attr.id; client.log("YES! %s", expected_stanza) end expected_stanza = nil; client.stream:unhook("stanza", stanza_handler); client.stream.conn:pause(); client.log("Calling done") done(); return true; end client.stream:hook("stanza", stanza_handler, 100); verse.add_task(client.stanza_timeout or default_stanza_timeout, function () done(); end); client.stream.conn:resume(); wait(); if not have_received_stanza then if expected_stanza then client.log("TIMEOUT waiting for %s", expected_stanza) local e = new_error("stanza-timeout", { text = "Timed out waiting for stanza" }); error(e); end if expected_stanza == false then client.log("Good - no stanzas were received (expected)"); done(); end end end; disconnects = function (client) client.disconnect_expected = true; client.stream:close(); end; }