var config = require('../config'); var cloudReady; // The SDK timeout option does not protect us when its Promise/callback never // settles. Bound initialization and every request outside the native SDK too. function bounded(operation, milliseconds, message, code) { return new Promise(function (resolve, reject) { var settled = false; var timer = setTimeout(function () { var error = new Error(message); error.code = code; finish(reject, error); }, milliseconds); function finish(callback, value) { if (settled) return; settled = true; clearTimeout(timer); callback(value); } Promise.resolve().then(operation).then(function (value) { finish(resolve, value); }, function (error) { finish(reject, error); }); }); } function unwrap(result) { if (typeof result === 'string') result = JSON.parse(result); if (result && typeof result.success === 'boolean') { if (!result.success) throw new Error(result.errorMessage || '服务暂不可用'); return typeof result.data === 'string' ? JSON.parse(result.data) : result.data; } return result; } function initCloud() { if (!cloudReady) { var initializing = bounded(function () { var sdk = require('@tbmp/mp-cloud-sdk'), cloud = sdk.default || sdk; return Promise.resolve(cloud.init({ env: config.cloudEnv })).then(function (ok) { if (!ok) throw new Error('淘宝云服务初始化失败'); return cloud; }); }, 15000, '淘宝云服务连接超时,请稍后重试', 'CLOUD_INIT_TIMEOUT').catch(function (err) { if (cloudReady === initializing) cloudReady = null; throw err; }); cloudReady = initializing; } return cloudReady; } function request(path, body, token) { var headers = { 'Content-Type': 'application/json;charset=UTF-8' }; if (token) headers.Authorization = 'Bearer ' + token; if (config.transport === 'direct') { if (!/^http:\/\/(localhost|127\.0\.0\.1)(:\d+)?$/.test(config.baseUrl)) return Promise.reject(new Error('直连接口仅用于本机联调')); return bounded(function () { return new Promise(function (resolve, reject) { my.request({ url: config.baseUrl + config.basePath + path, method: 'POST', headers: headers, data: JSON.stringify(body), dataType: 'json', timeout: 10000, success: function (res) { try { if ((res.status || res.statusCode) !== 200) throw new Error('服务暂不可用'); resolve(unwrap(res.data)); } catch (e) { reject(e); } }, fail: function () { reject(new Error('网络异常,请稍后重试')); } }); }); }, 12000, '网络请求超时,请稍后重试', 'REQUEST_TIMEOUT'); } var cloudType = config.cloudType || 'empty'; if (cloudType === 'empty' && (!config.cloudAppId || !/^https:\/\//.test(config.baseUrl))) { return Promise.reject(new Error('请先配置淘宝云应用和 HTTPS 服务地址')); } return initCloud().then(function (cloud) { var exts = { timeout: 10000 }; if (config.cloudAppId) exts.cloudAppId = config.cloudAppId; if (cloudType === 'empty') exts.domain = config.baseUrl; return bounded(function () { return cloud.application.httpRequest({ path: config.basePath + path, method: 'POST', headers: headers, params: {}, body: body, exts: exts }); }, 12000, '网络请求超时,请稍后重试', 'REQUEST_TIMEOUT'); }).then(unwrap); } module.exports = { request: request, unwrap: unwrap };