Sat, 05 Sep 2015 23:24:15 +0100
client: Implement send/receive, including new stanzacmp library
scansion/objects/client.lua | file | annotate | diff | comparison | revisions | |
scansion/stanzacmp.lua | file | annotate | diff | comparison | revisions |
--- a/scansion/objects/client.lua Sat Sep 05 23:20:17 2015 +0100 +++ b/scansion/objects/client.lua Sat Sep 05 23:24:15 2015 +0100 @@ -3,6 +3,11 @@ verse.set_log_handler(verse._default_log_handler, { "debug", "info", "warn", "error" }); local parse_xml = require "scansion.xml".parse; + +local stanza_timeout = 5; + +local stanzacmp = require "scansion.stanzacmp"; + return { _validate = function (client) assert(client.jid, "No JID specified"); @@ -14,12 +19,25 @@ end; sends = function (client, data) - print(("%q"):format(table.concat(data))) - print(parse_xml(table.concat(data))); - print(stanza) + local stanza = parse_xml(table.concat(data)); + client.stream:send(stanza); end; receives = function (client, data) + local expected_stanza = parse_xml(table.concat(data)); + local function stanza_handler(received_stanza) + if not stanzacmp.stanzas_match(expected_stanza, received_stanza) then + print("NOT IT!") + verse.quit(); + else + print("YES!") + end + expected_stanza = nil; + end + client.stream:hook("stanza", stanza_handler, 100); + verse.add_task(stanza_timeout, function () + if not expected_stanza then return; end + end); end; disconnects = function (client)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/scansion/stanzacmp.lua Sat Sep 05 23:24:15 2015 +0100 @@ -0,0 +1,105 @@ +-- This is my attempt at a utility library to compare two XMPP stanzas +-- It is not testing for exact equivalency, but through some vague rules that felt right. +-- For example, the second stanza passed to stanzas_match() is allowed to have unexpected +-- elements and attributes at the top level. Beyond this, they must match exactly, except +-- for whitespace differences only. +-- +-- There are probably bugs, and it can probably be smarter, but I don't want to spend too +-- much time on it right now. + +local function trim(s) + return (s:gsub("^%s+", ""):gsub("%s+$", "")); +end + +local function stanzas_strict_match(stanza1, stanza2) + if stanza1.name ~= stanza2.name or stanza1.attr.xmlns ~= stanza2.attr.xmlns then + return false; + end + + for k, v in pairs(stanza1.attr) do + if stanza2.attr[k] ~= v then + return false; + end + end + + for k, v in pairs(stanza2.attr) do + if stanza1.attr[k] ~= v then + return false; + end + end + + if #stanza1.tags ~= #stanza2.tags then + return false; + end + + local stanza2_pos = 1; + for _, child in ipairs(stanza1) do + if type(child) == "table" or child:match("%S") then + local match; + local child2 = stanza2[stanza2_pos]; + while child2 and not(type(child2) == "table" or child:match("%S")) do + stanza2_pos = stanza2_pos + 1; + child2 = stanza2[stanza2_pos]; + end + if type(child) ~= type(child2) then + return false; + end + if type(child) == "table" and child2.name == child.name and child2.attr.xmlns == child.attr.xmlns then + -- Strict deep match + match = stanzas_strict_match(child, child2); + elseif type(child) == "string" then -- Text nodes, must be equal, ignoring leading/trailing whitespace + match = trim(child) == trim(child2); + end + if not match then + return false; + end + end + end + return true; +end + +-- Everything in stanza1 should be present in stanza2 + +local function stanzas_match(stanza1, stanza2) + if stanza1.name ~= stanza2.name or stanza1.attr.xmlns ~= stanza2.attr.xmlns then + return false; + end + + for k, v in pairs(stanza1.attr) do + if stanza2.attr[k] ~= v then + return false; + end + end + + local stanza2_pos = 1; + for _, child in ipairs(stanza1) do + if type(child) == "table" or child:match("%S") then + local match; + -- Iterate through remaining nodes in stanza2, looking for a match + while stanza2_pos <= #stanza2 do + local child2 = stanza2[stanza2_pos]; + stanza2_pos = stanza2_pos + 1; + + if type(child2) == type(child) then + if type(child) == "table" and child2.name == child.name and child2.attr.xmlns == child.attr.xmlns then + -- Strict deep match + match = stanzas_strict_match(child, child2); + elseif type(child) == "string" then -- Text nodes, must be equal, ignoring leading/trailing whitespace + match = trim(child) == trim(child2); + end + break; + end + end + if not match then + return false; + end + end + end + return true; +end + + +return { + stanzas_match = stanzas_match; + stanzas_strict_match = stanzas_strict_match; +};