Fri, 19 Feb 2016 11:47:33 +0000
main.lua, client: Make timeouts more coherent (stanza timeout was greater than action timeout), add command-line options to change them
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 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); -- Handle unexpected disconnects client.stream:hook("disconnected", function (s) client.log("Unexpected disconnect!"); error("Unexpected disconnect"); 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 = 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 = 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(new_error("Received unexpected stanza", { stanza = tostring(received_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(client.stanza_timeout or default_stanza_timeout, function () if expected_stanza then client.log("TIMEOUT waiting for %s", expected_stanza) error("Timed out waiting for stanza"); end if expected_stanza == false then client.log("Good - no stanzas were received (expected)"); done(); end end); client.stream.conn:resume(); wait(); end; disconnects = function (client) client.stream:close(); end; }