UNPKG

gads

Version:

An unofficial JS client library for the SOAP-based DFP Ads API

204 lines 8.69 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const util_1 = require("../common/util"); const soap_1 = require("soap"); const wsdlToMetaServiceTranslator_1 = require("./wsdlToMetaServiceTranslator"); const xmlToJsTranslator_1 = require("./xmlToJsTranslator"); /* tslint:disable:no-any */ class SoapClientFactory { constructor() { this.xmlToJsTranslator = new xmlToJsTranslator_1.XmlToJsTranslator(); this.wsdlToMetaServiceTranslator = new wsdlToMetaServiceTranslator_1.WsdlToMetaServiceTranslator(); } getSoapClient(wsdlUrl, config) { return this.createSoapClient(wsdlUrl, config) .then((client) => { return this.xmlToJsTranslator.translate(client.wsdl.xml) .then(wsdl => this.wsdlToMetaServiceTranslator.translate(wsdl)) .then(metaService => { for (const methodName in metaService.methods) { if (metaService.methods.hasOwnProperty(methodName)) { client[methodName] = this.wrapSoapClientMethod(client, methodName, metaService, config); } } }) .then(() => client); }); } createSoapClient(wsdlUrl, config) { return new Promise((resolve, reject) => { // Create options const options = { attributesKey: '$attr', // Whether to cache WSDL files or request them every time disableCache: !config.cache, // HTTP headers to be sent on WSDL requests wsdl_headers: { connection: 'keep-alive' }, // Options for the request module on WSDL requests wsdl_options: Object.assign({ timeout: 3600, gzip: config.enableCompression }, config.proxy ? config.proxy.getProxyInfo() : {}) }; // Create client soap_1.createClient(wsdlUrl, options, (err, client) => { err ? reject(err) : resolve(client); }); }) .then(client => { this.addLogging(client, config); return client; }); } wrapSoapClientMethod(client, methodName, metaService, config) { const method = client[methodName]; const metaArg = metaService.interfaces[metaService.methods[methodName].inputs[0].type]; return (arg, cb) => { // Add HTTP headers const promise = new Promise((resolve, reject) => { config.headerHandler.generateHttpHeaders((err, headers) => { err ? reject(err) : resolve(headers); }); }) .then(httpHeaders => { for (const key in httpHeaders) { if (httpHeaders.hasOwnProperty(key)) { client.addHttpHeader(key, httpHeaders[key]); } } }) // Add SOAP headers .then(() => new Promise((resolve, reject) => { config.headerHandler.generateSoapHeaders((err, headers) => { err ? reject(err) : resolve(headers); }); })) .then(soapHeaders => { client.clearSoapHeaders(); for (const header of soapHeaders) { client.addSoapHeader(header.value, header.name, header.namespace, header.xmlns); } }) // Fix request's property order since it matters to SOAP server .then(() => this.sanitizeSoapClientMethodArg(arg, metaArg, metaService)) // Perform a SOAP call .then(arg => new Promise((resolve, reject) => { const options = { gzip: config.enableCompression, time: true, postProcess: (xml) => { return xml.replace(' xsi:nil="true"', ''); } }; method.call(client, arg, (err, res //, rawRes: string, soapHeader: any, rawReq: string ) => { err ? reject(err) : resolve(res); }, Object.assign(options, config.proxy ? config.proxy.getProxyInfo() : {})); })); return util_1.callbackOrPromise(cb, promise); }; } flattenInterfaceProperties(metaInterface, metaService) { const props = {}; // Set super properties first for (const interfaceName of metaInterface.extends) { const superInterface = metaService.interfaces[interfaceName]; const superProps = this.flattenInterfaceProperties(superInterface, metaService); Object.assign(props, superProps); } // Set properties return Object.assign(props, metaInterface.properties); } sanitizeSoapClientMethodArg(arg, metaArg, metaService) { const out = {}; const stack = [{ arg, metaArg, out }]; // For each arg in the stack do { const { arg, metaArg, out } = stack.pop(); const props = this.flattenInterfaceProperties(metaArg, metaService); // Set correct property order for output for (const name in props) { if (props.hasOwnProperty(name)) { out[name] = undefined; } } // For each property in arg for (const key in arg) { if (arg.hasOwnProperty(key)) { // Push null and unknown properties verbatim if (arg[key] == null || !out.hasOwnProperty(key)) { out[key] = arg[key]; continue; } // Push properties verbatim that are not interfaces const prop = props[key]; const metaArg = metaService.interfaces[prop.type]; if (!metaArg) { out[key] = arg[key]; continue; } // If array or object if (prop.isArray && arg[key] instanceof Array) { const outs = out[key] = []; for (const v of arg[key]) { const out = {}; outs.push(out); stack.push({ arg: v, metaArg, out }); } continue; } // If Object stack.push({ arg: arg[key], metaArg, out: out[key] = {} }); } } } while (stack.length > 0); return out; } addLogging(client, config) { client.on('request', (_, eid) => { if (config.logger) { const msg = `[${(new Date()).toISOString()}] REQUEST id=${eid}\n`; config.logger.log(msg); } }); client.on('soapError', (_, eid) => { if (config.logger) { const msg = `[${(new Date()).toISOString()}] ERROR id=${eid}\n`; config.logger.error(msg); } }); client.on('response', (body, res, eid) => { if (!config.logger) { return; } const request = res.request; // Print header let msg = `[${(new Date()).toISOString()}] RESPONSE id=${eid}`; msg = msg + ` responseTime=${res.elapsedTime}\n`; msg = msg + `${request.method} ${res.statusCode}`; msg = msg + ` (${res.statusMessage}) ${res.url}\n\n`; // Print request for (const header in request.headers) { if (!request.headers.hasOwnProperty(header)) { continue; } let val = request.headers[header]; if (header.toLowerCase() === 'authorization') { val = 'REDACTED'; } msg = msg + `${header}: ${val}\n`; } msg = msg + `\n${request.body}\n\n`; // Print response for (const header in res.headers) { if (res.headers.hasOwnProperty(header)) { msg = msg + `${header}: ${res.headers[header]}\n`; } } msg = msg + `\n${body}\n`; config.logger.log(msg); }); } } exports.SoapClientFactory = SoapClientFactory; //# sourceMappingURL=soapClientFactory.js.map