ucenter-client
Version:
A full-featured UCenter client for Node.js.
143 lines (132 loc) • 3.99 kB
JavaScript
const qs = require('querystring');
const iconv = require('iconv-lite');
const convert = require('xml-js');
module.exports = function(config) {
return {
parseQueryString,
urlEncode,
urlDecode,
serializeXml,
unserializeXml,
};
/**
* parse Query String
* @param {*} query
* @returns {object}
*/
function parseQueryString(query) {
if (config.UC_CHARSET === 'utf8') return qs.parse(query);
if (/^[a-zA-Z0-9%=&\-_.+~]*$/.test(query) === false) return {}; // 不符合规范
// gbk 的情况:
const result = {};
query.split('&').forEach(v => {
const tmp = v.split('=');
result[tmp[0]] = urlDecode(tmp[1], 'gbk');
});
return result;
}
/**
* URL Encode
* @param {string} str PlainText for UrlEncode
* @param {string} charset Target charset (utf8/gbk)
* @returns {string}
*/
function urlEncode(str, charset) {
charset = charset || config.UC_CHARSET;
if (charset === 'utf8') return encodeURIComponent(str);
const rs = [];
const encodeBuf = iconv.encode(str, charset);
encodeBuf.forEach(v => {
rs.push('%' + '0'.concat(parseInt(v).toString(16)).slice(-2));
});
return rs.join('');
}
/**
* URL Decode
* @param {string} str UrlEncoded String
* @param {string} charset Source charset (utf8/gbk)
* @return {string}
*/
function urlDecode(str, charset) {
charset = charset || config.UC_CHARSET;
if (charset === 'utf8') return decodeURIComponent(str);
const strLen = str.length;
const buf = Buffer.alloc(strLen);
for (let i = 0, j = 0; i < strLen; j++) {
if (str[i] !== '%') {
buf[j] = str.charCodeAt(i);
i++;
} else {
buf[j] = parseInt(str.substring(i + 1, 2), 16);
i += 3;
}
}
return iconv.decode(buf, charset);
}
/**
* serialize Xml (JS Object 2 XML)
* @param {Object|Array} arr
* @param {boolean} htmlon Use CDATA to save string
* @param {number} level default: 1
* @returns {Buffer}
*/
function serializeXml(arr, htmlon, level) {
htmlon = !!htmlon;
level = level ? level : 1;
let s = level == 1 ? '<?xml version="1.0" encoding="ISO-8859-1"?>\r\n<root>\r\n' : '';
const space = '\t'.repeat(level);
for (let k in arr) {
s += space + `<item id="${k}">`;
if (Array.isArray(arr[k]) || (arr[k] !== null && typeof arr[k] === 'object')) {
s += '\r\n' + serializeXml(arr[k], htmlon, level + 1) + space;
} else {
s += (htmlon ? '<![CDATA[' : '') + arr[k] + (htmlon ? ']]>' : '');
}
s += '</item>\r\n';
}
s = s.replace(/([\x01-\x08\x0b-\x0c\x0e-\x1f])+/g, ' ');
if (level !== 1) return s;
s += '</root>';
return config.UC_CHARSET === 'utf8' ? Buffer.from(s) : iconv.encode(s, config.UC_CHARSET);
}
/**
* unserialize Xml (XML 2 JS Object)
* @param {string} xml UTF-8 XML
* @returns {object}
* ONLY FOR unserialize UC XML
*/
function unserializeXml(xml) {
return analyzeNode(convert.xml2js(xml, {
compact: true
}));
}
function analyzeNode(node) {
if (node.root) {
return analyzeNode(node.root);
} else if (node.item) {
if (Array.isArray(node.item)) {
if (/^\d+$/g.test(node.item[0]._attributes.id)) {
return node.item.map(v => {
return analyzeNode(v);
});
} else {
const data = {};
node.item.forEach(v => {
data[v._attributes.id] = analyzeNode(v);
});
return data;
}
} else {
const data = {};
data[node.item._attributes.id] = analyzeNode(node.item);
return data;
}
} else if (node._cdata) {
return node._cdata;
} else if (node._text) {
return node._text;
} else {
return null;
}
}
};