UNPKG

workspace-integrations

Version:
201 lines (200 loc) 7.01 kB
"use strict"; /** * All http calls for communicating with Webex (device) cloud */ Object.defineProperty(exports, "__esModule", { value: true }); // node-fetch Needs to be on low version to support CommonJS / require // @ts-ignore const node_fetch_1 = require("node-fetch"); const url_join_ts_1 = require("url-join-ts"); const logger_1 = require("./logger"); const util_1 = require("./util"); let dryHandler = null; function header(accessToken) { return { Authorization: 'Bearer ' + accessToken, 'Content-Type': 'application/json', }; } // Modify fetch to throw error if http result is not 2xx, and return json always async function fetch(url, options) { if (dryHandler) { return dryHandler(url, options); } const RetryWait = 2000; let res; try { res = await (0, node_fetch_1.default)(url, options); } catch (e) { // we wait and try once more before failing (recover from intermittent network fail) logger_1.default.warn('Network failure, retrying once'); await (0, util_1.sleep)(RetryWait); try { res = await (0, node_fetch_1.default)(url, options); } catch (e) { throw (e); } } if (!res.ok) { throw new Error(JSON.stringify(await res.json())); } logger_1.default.verbose(`[${options.method || 'GET'}: ${url}`); return await res.json(); } function get(accessToken, url) { const headers = header(accessToken); const options = { headers, }; return fetch(url, options); } class HttpImpl { constructor(baseUrl, accessToken) { this.baseUrl = ''; this.accessToken = ''; this.pollDeviceData = (url) => { const headers = header(this.accessToken); return fetch(url, { headers }); }; this.xCommand = (deviceId, command, args, multiline) => { logger_1.default.info('Invoking xCommand ' + command); const url = (0, url_join_ts_1.urlJoin)(this.baseUrl, 'xapi/command', command); const body = { deviceId, }; if (args) { body.arguments = args; } if (multiline) { body.body = multiline; } const headers = header(this.accessToken); const options = { headers, method: 'POST', body: JSON.stringify(body), }; return fetch(url, options); }; this.xStatus = (deviceId, path) => { logger_1.default.info('Getting xStatus ' + path); const url = (0, url_join_ts_1.urlJoin)(this.baseUrl, '/xapi/status/', `?deviceId=${deviceId}&name=${path}`); return get(this.accessToken, url); }; this.xConfig = (deviceId, path) => { logger_1.default.info('Getting xConfig ' + path); const url = (0, url_join_ts_1.urlJoin)(this.baseUrl, '/deviceConfigurations/', `?deviceId=${deviceId}&key=${path}`); return get(this.accessToken, url); }; this.xConfigSet = (deviceId, configs) => { logger_1.default.info('Setting xConfig ' + (configs.length === 1 ? configs[0].path : '(multiple)')); const url = (0, url_join_ts_1.urlJoin)(this.baseUrl, '/deviceConfigurations/', `?deviceId=${deviceId}`); const headers = { Authorization: 'Bearer ' + this.accessToken, 'Content-Type': 'application/json-patch+json', }; const body = configs.map((config) => ({ op: 'replace', path: config.path + '/sources/configured/value', value: config.value, })); const options = { headers, body: JSON.stringify(body), method: 'PATCH', }; return fetch(url, options); }; this.getWorkspace = (accessToken, workspaceId) => { logger_1.default.info('Fetching workspace'); const url = (0, url_join_ts_1.urlJoin)(this.baseUrl, '/workspaces/', workspaceId); return get(accessToken, url); }; this.deviceDetails = (accessToken, deviceId) => { logger_1.default.info('Fetching device details'); const url = (0, url_join_ts_1.urlJoin)(this.baseUrl, '/devices/', deviceId); return get(accessToken, url); }; this.baseUrl = baseUrl; this.accessToken = accessToken; } static setDryMode(handler) { dryHandler = handler; } webexApi(partialUrl, method = 'GET', body = null, contentType = 'application/json') { const headers = header(this.accessToken); if (contentType) { headers['Content-Type'] = contentType; } const options = { method, headers, }; if (body) { options.body = JSON.stringify(body); } const url = partialUrl.startsWith('https://') ? partialUrl : (0, url_join_ts_1.urlJoin)(this.baseUrl, partialUrl); return fetch(url, options); } setAccessToken(token) { this.accessToken = token; } fullUrl(partialUrl) { return (0, url_join_ts_1.urlJoin)(this.baseUrl, partialUrl); } ping(appUrl) { return get(this.accessToken, appUrl); } static createAccessToken(oauth) { const { clientId, clientSecret, oauthUrl, refreshToken } = oauth; const headers = { 'Content-Type': 'application/json', }; const body = { grant_type: 'refresh_token', client_id: clientId, client_secret: clientSecret, refresh_token: refreshToken, }; const options = { headers, method: 'POST', body: JSON.stringify(body), }; return fetch(oauthUrl, options); } get(partialUrl) { const url = (0, url_join_ts_1.urlJoin)(this.baseUrl + partialUrl); return get(this.accessToken, url); } } HttpImpl.initIntegration = (data) => { const { accessToken, appUrl, webhook, notifications, actionsUrl } = data; const headers = header(accessToken); const body = { provisioningState: 'completed', }; if (notifications === 'webhook') { logger_1.default.info('Subscribing to notifications with web hooks'); body.webhook = webhook; body.actionsUrl = actionsUrl; } else if (notifications === 'longpolling') { logger_1.default.info('Subscribing to notifications with long polling'); body.queue = { state: 'enabled', }; } else { logger_1.default.info('Not subscribing to notifications'); } const options = { headers, method: 'PATCH', body: JSON.stringify(body), }; return fetch(appUrl, options); }; exports.default = HttpImpl;