# HG changeset patch # User Kim Alvefur # Date 1582376899 -3600 # Node ID 987b203bb091c265f1b162f062316407e8c960cb # Parent 25a3ad36ef3e0e56e49fd8fe4fc40d08b051ff3c mod_rest: Restructure JSON / Stanza mapping definitions It was a pain to remember which index had the mapping function for which direction. This is more readable. diff -r 25a3ad36ef3e -r 987b203bb091 mod_rest/jsonmap.lib.lua --- a/mod_rest/jsonmap.lib.lua Sat Feb 22 13:51:59 2020 +0100 +++ b/mod_rest/jsonmap.lib.lua Sat Feb 22 14:08:19 2020 +0100 @@ -7,8 +7,8 @@ -- Reused in many XEPs so declared up here local dataform = { -- Generic and complete dataforms mapping - "func", "jabber:x:data", "x", - function (s) + type = "func", xmlns = "jabber:x:data", tagname = "x", + st2json = function (s) local fields = array(); local form = { type = s.attr.type; @@ -47,7 +47,7 @@ end return form; end; - function (x) + json2st = function (x) if type(x) == "table" and x ~= json.null then local form = st.stanza("x", { xmlns = "jabber:x:data", type = x.type }); if x.title then @@ -90,9 +90,9 @@ end; }; -local function formdata(s,t) +local function formdata(s, t) local form = st.stanza("x", { xmlns = "jabber:x:data", type = t }); - for k,v in pairs(s) do + for k, v in pairs(s) do form:tag("field", { var = k }); if type(v) == "string" then form:text_tag("value", v); @@ -124,41 +124,41 @@ status = "text_tag", priority = "text_tag", - state = {"name", "http://jabber.org/protocol/chatstates"}, - nick = {"text_tag", "http://jabber.org/protocol/nick", "nick"}, - delay = {"attr", "urn:xmpp:delay", "delay", "stamp"}, - replace = {"attr", "urn:xmpp:message-correct:0", "replace", "id"}, + state = { type = "name", xmlns = "http://jabber.org/protocol/chatstates" }, + nick = { type = "text_tag", xmlns = "http://jabber.org/protocol/nick", tagname = "nick" }, + delay = { type = "attr", xmlns = "urn:xmpp:delay", tagname = "delay", attr = "stamp" }, + replace = { type = "attr", xmlns = "urn:xmpp:message-correct:0", tagname = "replace", attr = "id" }, -- XEP-0045 MUC -- TODO history, password, ??? - join = {"bool_tag", "http://jabber.org/protocol/muc", "x"}, + join = { type = "bool_tag", xmlns = "http://jabber.org/protocol/muc", tagname = "x" }, -- XEP-0071 html = { - "func", "http://jabber.org/protocol/xhtml-im", "html", - function (s) --> json string - return (tostring(s:get_child("body", "http://www.w3.org/1999/xhtml")):gsub(" xmlns='[^']*'","", 1)); + type = "func", xmlns = "http://jabber.org/protocol/xhtml-im", tagname = "html", + st2json = function (s) --> json string + return (tostring(s:get_child("body", "http://www.w3.org/1999/xhtml")):gsub(" xmlns='[^']*'", "", 1)); end; - function (s) --> xml + json2st = function (s) --> xml if type(s) == "string" then - return assert(xml.parse([[]]..s..[[]])); + return assert(xml.parse("" .. s .. "")); end end; }; -- XEP-0199: XMPP Ping - ping = {"bool_tag", "urn:xmpp:ping", "ping"}, + ping = { type = "bool_tag", xmlns = "urn:xmpp:ping", tagname = "ping" }, -- XEP-0092: Software Version - version = {"func", "jabber:iq:version", "query", - function (s) + version = { type = "func", xmlns = "jabber:iq:version", tagname = "query", + st2json = function (s) return { name = s:get_child_text("name"); version = s:get_child_text("version"); os = s:get_child_text("os"); } end, - function (s) + json2st = function (s) local v = st.stanza("query", { xmlns = "jabber:iq:version" }); if type(s) == "table" then v:text_tag("name", s.name); @@ -173,8 +173,8 @@ -- XEP-0030 disco = { - "func", "http://jabber.org/protocol/disco#info", "query", - function (s) --> array of features + type = "func", xmlns = "http://jabber.org/protocol/disco#info", tagname = "query", + st2json = function (s) --> array of features local identities, features = array(), array(); for tag in s:childtags() do if tag.name == "identity" and tag.attr.category and tag.attr.type then @@ -185,7 +185,7 @@ end return { node = s.attr.node, identities = identities, features = features, }; end; - function (s) + json2st = function (s) if type(s) == "table" and s ~= json.null then local disco = st.stanza("query", { xmlns = "http://jabber.org/protocol/disco#info", node = s.node }); if s.identities then @@ -206,10 +206,10 @@ }; items = { - "func", "http://jabber.org/protocol/disco#items", "query", - function (s) --> array of features | map with node + type = "func", xmlns = "http://jabber.org/protocol/disco#items", tagname = "query", + st2json = function (s) --> array of features | map with node if s.attr.node and s.tags[1] == nil then - return { node = s.attr. node }; + return { node = s.attr.node }; end local items = array(); @@ -218,7 +218,7 @@ end return items; end; - function (s) + json2st = function (s) if type(s) == "table" and s ~= json.null then local disco = st.stanza("query", { xmlns = "http://jabber.org/protocol/disco#items", node = s.node }); for _, item in ipairs(s) do @@ -236,8 +236,8 @@ }; -- XEP-0050: Ad-Hoc Commands - command = {"func", "http://jabber.org/protocol/commands", "command", - function (s) + command = { type = "func", xmlns = "http://jabber.org/protocol/commands", tagname = "command", + st2json = function (s) local cmd = { action = s.attr.action, node = s.attr.node, @@ -261,19 +261,19 @@ }; end if form then - cmd.form = dataform[4](form); + cmd.form = dataform[4] (form); end return cmd; end; - function (s) + json2st = function (s) if type(s) == "table" and s ~= json.null then local cmd = st.stanza("command", { - xmlns = "http://jabber.org/protocol/commands", - action = s.action, - node = s.node, - sessionid = s.sessionid, - status = s.status, - }); + xmlns = "http://jabber.org/protocol/commands", + action = s.action, + node = s.node, + sessionid = s.sessionid, + status = s.status, + }); if type(s.actions) == "table" then cmd:tag("actions", { execute = s.actions.execute }); do @@ -292,24 +292,24 @@ cmd:text_tag("note", s.note.text, { type = s.note.type }); end if s.form then - cmd:add_child(dataform[5](s.form)); + cmd:add_child(dataform[5] (s.form)); elseif s.data then cmd:add_child(formdata(s.data)); end return cmd; elseif type(s) == "string" then -- assume node - return st.stanza("command", { xmlns = "http://jabber.org/protocol/commands", node = s }); + return st.stanza("command", { xmlns = "http://jabber.org/protocol/commands", node = s }); end -- else .. missing required attribute end; }; -- XEP-0066: Out of Band Data - oob_url = {"func", "jabber:iq:oob", "query", - function (s) + oob_url = { type = "func", xmlns = "jabber:iq:oob", tagname = "query", + st2json = function (s) return s:get_child_text("url"); end; - function (s) + json2st = function (s) if type(s) == "string" then return st.stanza("query", { xmlns = "jabber:iq:oob" }):text_tag("url", s); end @@ -317,8 +317,8 @@ }; -- XEP-XXXX: User-defined Data Transfer - payload = {"func", "urn:xmpp:udt:0", "payload", - function (s) + payload = { type = "func", xmlns = "urn:xmpp:udt:0", tagname = "payload", + st2json = function (s) local rawjson = s:get_child_text("json", "urn:xmpp:json:0"); if not rawjson then return nil, "missing-json-payload"; end local parsed, err = json.decode(rawjson); @@ -328,10 +328,10 @@ data = parsed; }; end; - function (s) + json2st = function (s) if type(s) == "table" then return st.stanza("payload", { xmlns = "urn:xmpp:udt:0", datatype = s.datatype }) - :tag("json", { xmlns = "urn:xmpp:json:0" }):text(json.encode(s.data)); + :tag("json", { xmlns = "urn:xmpp:json:0" }):text(json.encode(s.data)); end; end }; @@ -340,13 +340,13 @@ dataform = dataform; -- Simpler mapping from JSON map - formdata = {"func", "jabber:x:data", "", - function () + formdata = { type = "func", xmlns = "jabber:x:data", tagname = "", + st2json = function () -- Tricky to do in a generic way without each form layout -- In the future, some well-known layouts might be understood return nil, "not-implemented"; end, - formdata, + json2st = formdata, }; }; @@ -414,27 +414,27 @@ for k, mapping in pairs(field_mappings) do if mapping == "text_tag" then t[k] = s:get_child_text(k); - elseif mapping[1] == "text_tag" then - t[k] = s:get_child_text(mapping[3], mapping[2]); - elseif mapping[1] == "name" then - local child = s:get_child(nil, mapping[2]); + elseif mapping.type == "text_tag" then + t[k] = s:get_child_text(mapping.tagname, mapping.xmlns); + elseif mapping.type == "name" then + local child = s:get_child(nil, mapping.xmlns); if child then t[k] = child.name; end - elseif mapping[1] == "attr" then - local child = s:get_child(mapping[3], mapping[2]) + elseif mapping.type == "attr" then + local child = s:get_child(mapping.tagname, mapping.xmlns); if child then - t[k] = child.attr[mapping[4]]; + t[k] = child.attr[mapping.attr]; end - elseif mapping[1] == "bool_tag" then - if s:get_child(mapping[3], mapping[2]) then + elseif mapping.type == "bool_tag" then + if s:get_child(mapping.tagname, mapping.xmlns) then t[k] = true; end - elseif mapping[1] == "func" then - local child = s:get_child(mapping[3], mapping[2] or k); + elseif mapping.type == "func" and mapping.st2json then + local child = s:get_child(mapping.tagname, mapping.xmlns or k); -- TODO handle err if child then - t[k] = mapping[4](child); + t[k] = mapping.st2json(child); end end end @@ -493,16 +493,16 @@ s:text_tag(k, v); elseif mapping == "attr" then -- luacheck: ignore 542 -- handled already - elseif mapping[1] == "text_tag" then - s:text_tag(mapping[3] or k, v, mapping[2] and { xmlns = mapping[2] }); - elseif mapping[1] == "name" then - s:tag(v, { xmlns = mapping[2] }):up(); - elseif mapping[1] == "attr" then - s:tag(mapping[3] or k, { xmlns = mapping[2], [ mapping[4] or k ] = v }):up(); - elseif mapping[1] == "bool_tag" then - s:tag(mapping[3] or k, { xmlns = mapping[2] }):up(); - elseif mapping[1] == "func" then - s:add_child(mapping[5](v)):up(); + elseif mapping.type == "text_tag" then + s:text_tag(mapping.tagname or k, v, mapping.xmlns and { xmlns = mapping.xmlns }); + elseif mapping.type == "name" then + s:tag(v, { xmlns = mapping.xmlns }):up(); + elseif mapping.type == "attr" then + s:tag(mapping.tagname or k, { xmlns = mapping.xmlns, [mapping.attr or k] = v }):up(); + elseif mapping.type == "bool_tag" then + s:tag(mapping.tagname or k, { xmlns = mapping.xmlns }):up(); + elseif mapping.type == "func" and mapping.json2st then + s:add_child(mapping.json2st(v)):up(); end else return nil, "unknown-field";