UNPKG

@foxglove/xmlrpc

Version:

TypeScript library implementing an XMLRPC client and server with pluggable server backend

180 lines 6.64 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.serializeFault = exports.serializeMethodResponse = exports.serializeMethodCall = exports.XmlRpcError = void 0; const byte_base64_1 = require("byte-base64"); const xmlbuilder2_1 = require("xmlbuilder2"); const CustomType_1 = require("./CustomType"); const DateFormatter_1 = require("./DateFormatter"); const illegalChars = /^(?![^<&]*]]>[^<&]*)[^<&]*$/; const dateFormatter = new DateFormatter_1.DateFormatter(); // ref <http://xmlrpc-epi.sourceforge.net/specs/rfc.fault_codes.php> var XmlRpcError; (function (XmlRpcError) { XmlRpcError[XmlRpcError["APPLICATION_ERROR"] = -32500] = "APPLICATION_ERROR"; XmlRpcError[XmlRpcError["NOT_FOUND_ERROR"] = -32601] = "NOT_FOUND_ERROR"; XmlRpcError[XmlRpcError["INVALID_PARAMS_ERROR"] = -32602] = "INVALID_PARAMS_ERROR"; })(XmlRpcError = exports.XmlRpcError || (exports.XmlRpcError = {})); // Creates the XML for an XML-RPC method call function serializeMethodCall(method, params = [], encoding) { const xml = (0, xmlbuilder2_1.create)({ version: "1.0", encoding }) .ele("methodCall") .ele("methodName") .txt(method) .up() .ele("params"); params.forEach((param) => serializeValue(param, xml.ele("param"))); // Includes the <?xml ...> declaration return xml.doc().toString(); } exports.serializeMethodCall = serializeMethodCall; // Creates the XML for an XML-RPC method response function serializeMethodResponse(result) { const xml = (0, xmlbuilder2_1.create)().ele("methodResponse").ele("params").ele("param"); serializeValue(result, xml); // Includes the <?xml ...> declaration return xml.doc().toString(); } exports.serializeMethodResponse = serializeMethodResponse; function serializeFault(fault) { const xml = (0, xmlbuilder2_1.create)().ele("methodResponse").ele("fault"); const faultCode = fault.faultCode ?? XmlRpcError.APPLICATION_ERROR; const faultString = fault.faultString ?? fault.message; serializeValue({ faultCode, faultString }, xml); // Includes the <?xml ...> declaration return xml.doc().toString(); } exports.serializeFault = serializeFault; function serializeValue(value, xml) { let current = { value, xml }; const stack = [current]; let valueNode; let next; while (stack.length > 0) { current = stack[stack.length - 1]; if (current.index != undefined) { // Iterating a compound next = getNextItemsFrame(current); if (next != undefined) { stack.push(next); } else { stack.pop(); } } else { // we're about to add a new value (compound or simple) valueNode = current.xml.ele("value"); switch (typeof current.value) { case "boolean": appendBoolean(current.value, valueNode); stack.pop(); break; case "string": appendString(current.value, valueNode); stack.pop(); break; case "number": appendNumber(current.value, valueNode); stack.pop(); break; case "object": if (current.value == undefined) { valueNode.ele("nil"); stack.pop(); } else if (current.value instanceof Date) { appendDatetime(current.value, valueNode); stack.pop(); } else if (Buffer.isBuffer(current.value)) { appendBuffer(current.value, valueNode); stack.pop(); } else if (current.value instanceof CustomType_1.CustomType) { current.value.serialize(valueNode); stack.pop(); } else { if (Array.isArray(current.value)) { current.xml = valueNode.ele("array").ele("data"); } else { current.xml = valueNode.ele("struct"); current.keys = Object.keys(current.value); } current.index = 0; next = getNextItemsFrame(current); if (next != undefined) { stack.push(next); } else { stack.pop(); } } break; default: stack.pop(); break; } } } } function getNextItemsFrame(frame) { let nextFrame; if (frame.keys != undefined && frame.index != undefined) { if (frame.index < frame.keys.length) { const key = frame.keys[frame.index++]; const member = frame.xml.ele("member").ele("name").txt(key).up(); nextFrame = { value: frame.value[key], xml: member, }; } } else if (frame.index != undefined && Array.isArray(frame.value) && frame.index < frame.value.length) { nextFrame = { value: frame.value[frame.index], xml: frame.xml, }; frame.index++; } return nextFrame; } // eslint-disable-next-line @foxglove/no-boolean-parameters function appendBoolean(value, xml) { xml.ele("boolean").txt(value ? "1" : "0"); } function appendString(value, xml) { if (!illegalChars.test(value)) { xml.ele("string").dat(value); } else { xml.ele("string").txt(value); } } function appendNumber(value, xml) { if (value % 1 === 0) { xml.ele("int").txt(String(value)); } else if (value === Infinity) { xml.ele("double").txt("inf"); } else if (value === -Infinity) { xml.ele("double").txt("-inf"); } else if (isNaN(value)) { xml.ele("double").txt("nan"); } else { xml.ele("double").txt(String(value)); } } function appendDatetime(value, xml) { xml.ele("dateTime.iso8601").txt(dateFormatter.encodeIso8601(value)); } function appendBuffer(value, xml) { xml.ele("base64").txt((0, byte_base64_1.bytesToBase64)(value)); } //# sourceMappingURL=Serializer.js.map