Tue, 03 Nov 2015 17:37:15 +0100
scansion.objects.client: Hold of reading from clients when they are not expecting stanzas
local async = require "scansion.async"; local verse = require "verse".init("client"); local parse_xml = require "scansion.xml".parse; local stanza_timeout = 5; local stanzacmp = require "scansion.stanzacmp"; local function filter_expression(script, s) local expr = s:match("^%$%{(.+)%}$"); if not expr then return s end local name, value_name = expr:match("^(.+)'s (.+)$"); assert(name, "Unable to parse expression: "..expr); local key = value_name:lower():gsub(" ", "_"); assert(script.objects[name], "Unknown object called "..name); local value = script.objects[name][key]; assert(value ~= nil, "Unknown attribute (of "..name.."): "..value_name); return value; end local function fill_vars(script, stanza) for k, v in pairs(stanza.attr) do stanza.attr[k] = filter_expression(script, v); end for i, child in ipairs(stanza) do if type(child) == "string" then stanza[i] = filter_expression(script, child); elseif type(child) == "table" then fill_vars(script, child); end end return stanza; end 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); end; connects = function (client) local wait, done = async.waiter(); client.stream:hook("ready", function () client.log"ready" done() client.log("ready done") client.stream.conn:pause() 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 = fill_vars(client.script, assert(parse_xml((table.concat(data):gsub("\t", " "))))); client.stream:send(stanza); end; receives = function (client, data) local wait, done = async.waiter(); local expected_stanza = fill_vars(client.script, assert(parse_xml((table.concat(data):gsub("\t", " "))))); local function stanza_handler(received_stanza) if not stanzacmp.stanzas_match(expected_stanza, received_stanza) then client.log("NOT IT!") client.log("Expected: %s", expected_stanza); client.log("Received: %s", received_stanza); error("Received unexpected stanza"); else client.log("YES! %s", expected_stanza) end expected_stanza = nil; client.stream:unhook("stanza", stanza_handler); client.stream.conn:pause(); done(); end client.stream:hook("stanza", stanza_handler, 100); verse.add_task(stanza_timeout, function () if not expected_stanza then return; end -- Stanza already received client.log("TIMEOUT waiting for %s", expected_stanza) error("Timed out waiting for stanza"); done(); end); client.stream.conn:resume(); wait(); end; disconnects = function (client) client.stream:close(); end; }