scansion/objects/client.lua

Thu, 31 Dec 2015 18:19:03 +0000

author
Matthew Wild <mwild1@gmail.com>
date
Thu, 31 Dec 2015 18:19:03 +0000
changeset 66
909c00296c2a
parent 60
e032cdb517ab
child 73
1c07ef6c6502
permissions
-rw-r--r--

client: Make use of new scansion.error library, log the received stanza when different to expected one

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 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);
		-- 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", "  ")))));
		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(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(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;
}

mercurial