UNPKG

mtl-js-sdk

Version:

879 lines (748 loc) 32 kB
"use strict"; function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; } function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(source, true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(source).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; } function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { Promise.resolve(value).then(_next, _throw); } } function _asyncToGenerator(fn) { return function () { var self = this, args = arguments; return new Promise(function (resolve, reject) { var gen = fn.apply(self, args); function _next(value) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value); } function _throw(err) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err); } _next(undefined); }); }; } function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; } function _typeof(obj) { if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); } module.exports = function (dependencies) { var uuid = dependencies.uuid, md5 = dependencies.md5, axios = dependencies.axios; var logger = { enable: false, info: function info(msg) { if (this.enable) { console.log("[多端协同] " + msg); } }, error: function error(msg) { if (this.enable) { console.log("%c[多端协同] " + msg, "color:red"); } } }; var SocketClient = require("./client")({ logger: logger }); var STORAGE_KEY = "MTL.COOP.STORAGE"; var REPLY_LISTENER_TYPE = "MTL_LISTENER_REPLY"; // 消息监听类型,仅监听某条消息的回复 function validateOptions(options) { var expectedOptions = { server: "string", restServer: "string", wssPort: "number", etp: "string", app: "string", appSecret: "string" }; for (var key in expectedOptions) { if (options[key] === null || options[key] === undefined || _typeof(options[key]) !== expectedOptions[key]) { throw new Error("Option [" + key + "] is " + options[key] + ". This may cause unexpected behaviour."); } } } var Manager = /*#__PURE__*/ function () { function Manager(options) { _classCallCheck(this, Manager); // TODO: 登录方案需要修改。(现状: 1.需要传 appSecret) -> (理想: 1.仅需要 password 验证); // validateOptions(options); this.isHttps = options.isHttps || true; this.server = options.server; this.restServer = options.restServer; this.wssPort = options.wssPort; this.etp = options.etp; this.app = options.app; this.appSecret = options.appSecret; this.userinfo = null; this.client = null; this.listeners = {}; this.listenerMap = {}; } _createClass(Manager, [{ key: "login", value: function () { var _login = _asyncToGenerator( /*#__PURE__*/ regeneratorRuntime.mark(function _callee(_ref) { var user, password, server, wssPort, restServer, etp, app, isHttps, appSecret, scheme, response, pwd, token, client, cache, deviceId, deviceName, auth; return regeneratorRuntime.wrap(function _callee$(_context) { while (1) { switch (_context.prev = _context.next) { case 0: user = _ref.user, password = _ref.password; server = this.server, wssPort = this.wssPort, restServer = this.restServer, etp = this.etp, app = this.app, isHttps = this.isHttps, appSecret = this.appSecret; scheme = isHttps ? "https" : "http"; // 第一步: 获取 userPwd _context.next = 5; return axios({ method: "post", url: "".concat(scheme, "://").concat(restServer, "/sysadmin/rest/multiterminal/").concat(etp, "/").concat(app, "/auth/app"), data: { userid: user, cipher: md5(etp + app + user + appSecret) } }); case 5: response = _context.sent; pwd = response.data.data.userPwd; // 第二步: 获取 token _context.next = 9; return axios({ method: "post", url: "".concat(scheme, "://").concat(restServer, "/sysadmin/rest/multiterminal/").concat(etp, "/").concat(app, "/auth/user"), data: { userid: user, cipher: md5(etp + app + user + pwd), passWord: md5(password).toUpperCase() } }); case 9: response = _context.sent; token = response.data.data.token; // 第三步: 连接 Socket client = null; _context.next = 14; return new Promise(function (resolve, reject) { client = new SocketClient("wss://".concat(server, ":").concat(wssPort), resolve, reject); }); case 14: cache = localStorage.getItem(STORAGE_KEY); cache = cache && JSON.parse(cache) || {}; deviceId = cache.deviceId || uuid(); deviceName = cache.deviceName || "WEB-" + deviceId.split("-")[0]; if (deviceId != cache.deviceId || deviceName != cache.deviceName) { cache.deviceId = deviceId; cache.deviceName = deviceName; localStorage.setItem(STORAGE_KEY, JSON.stringify(cache)); } // 第四步: 发送认证报文 _context.next = 21; return client.sendAuthPacket({ usr: "".concat(user, ".").concat(app, ".").concat(etp), atk: token, deviceId: deviceId, deviceName: deviceName }); case 21: auth = _context.sent; if (!(auth && auth.code == 200)) { _context.next = 29; break; } this.client = client; this.userinfo = { user: user, token: token, deviceId: deviceId, deviceName: deviceName }; this.client.onmessage = this._onmessage.bind(this); return _context.abrupt("return", auth); case 29: throw new Error("发送认证报文失败, " + auth && JSON.stringify(auth)); case 30: case "end": return _context.stop(); } } }, _callee, this); })); function login(_x) { return _login.apply(this, arguments); } return login; }() }, { key: "logout", value: function logout() { if (this.client) this.client.close(); this.client = null; } // 获取当前设备的 openId }, { key: "getOpenId", value: function () { var _getOpenId = _asyncToGenerator( /*#__PURE__*/ regeneratorRuntime.mark(function _callee2() { var permissions, _this$userinfo, token, deviceId, url, response, _args2 = arguments; return regeneratorRuntime.wrap(function _callee2$(_context2) { while (1) { switch (_context2.prev = _context2.next) { case 0: permissions = _args2.length > 0 && _args2[0] !== undefined ? _args2[0] : {}; _this$userinfo = this.userinfo, token = _this$userinfo.token, deviceId = _this$userinfo.deviceId; url = this._baseUrl() + "openId/" + deviceId; _context2.next = 5; return axios({ method: "post", url: url, params: { token: token }, data: { permissions: permissions } }); case 5: response = _context2.sent; if (!(response.data.result == "success")) { _context2.next = 8; break; } return _context2.abrupt("return", response.data.data.openId); case 8: throw new Error(response.data.result || JSON.stringify(response.data)); case 9: case "end": return _context2.stop(); } } }, _callee2, this); })); function getOpenId() { return _getOpenId.apply(this, arguments); } return getOpenId; }() // 通过 openId 获取设备信息 }, { key: "getDeviceInfo", value: function () { var _getDeviceInfo = _asyncToGenerator( /*#__PURE__*/ regeneratorRuntime.mark(function _callee3(openId) { var token, url, response; return regeneratorRuntime.wrap(function _callee3$(_context3) { while (1) { switch (_context3.prev = _context3.next) { case 0: token = this.userinfo.token; url = this._baseUrl() + "openId"; _context3.next = 4; return axios({ method: "get", url: url, params: { token: token, openId: openId }, headers: { "Content-Type": "application/json;charset=utf-8" }, data: {} }); case 4: response = _context3.sent; if (!(response.data.result == "success")) { _context3.next = 7; break; } return _context3.abrupt("return", response.data.data); case 7: throw new Error(response.data.errorMsg || JSON.stringify(response.data)); case 8: case "end": return _context3.stop(); } } }, _callee3, this); })); function getDeviceInfo(_x2) { return _getDeviceInfo.apply(this, arguments); } return getDeviceInfo; }() }, { key: "sendCommand", value: function () { var _sendCommand = _asyncToGenerator( /*#__PURE__*/ regeneratorRuntime.mark(function _callee4(_ref2) { var cmd, url, listener, token, data, response; return regeneratorRuntime.wrap(function _callee4$(_context4) { while (1) { switch (_context4.prev = _context4.next) { case 0: cmd = _ref2.cmd, url = _ref2.url, listener = _ref2.listener; token = this.userinfo.token; url = url || this._baseUrl() + "command"; data = this._commandToData(cmd); logger.info("发送指令", url.split("/").pop(), data); _context4.next = 7; return axios({ method: "post", url: url, params: { token: token }, data: data }); case 7: response = _context4.sent; if (!(response.data.result == "success")) { _context4.next = 11; break; } if (typeof listener == "function") { this.addListener(REPLY_LISTENER_TYPE, { commandId: data.commandId }, listener); } return _context4.abrupt("return", response.data); case 11: throw new Error(response.data.errorMsg); case 12: case "end": return _context4.stop(); } } }, _callee4, this); })); function sendCommand(_x3) { return _sendCommand.apply(this, arguments); } return sendCommand; }() // MARK: 事件监听 }, { key: "addListener", value: function addListener(type, options, listener) { if (typeof type != "string" || type.length == 0) { logger.error("type 应该是一个非空的字符串"); return; } if (listener && typeof listener != "function") { logger.error("listener should be a function"); return; } var identify; if (type == REPLY_LISTENER_TYPE) { identify = options.commandId; if (typeof identify != "string" || identify.length == 0) { throw new Error("添加监听失败,需要 commandId"); } if (this.listeners[identify]) { throw new Error("添加监听失败,不能重复监听同一条消息的回复"); } listener.identify = identify; this.listeners[identify] = listener; } else { identify = uuid(); listener.identify = identify; this.listeners[identify] = listener; } var listenerIds = this.listenerMap[type] || []; listenerIds.push(identify); this.listenerMap[type] = listenerIds; return identify; } }, { key: "removeListener", value: function removeListener(identify) { if (identify && typeof identify == "string") this.listeners[identify] = null; } // MARK: - 授权相关 // 申请设备访问权限 }, { key: "requestAccess", value: function () { var _requestAccess = _asyncToGenerator( /*#__PURE__*/ regeneratorRuntime.mark(function _callee5(_ref3) { var to, permissions, allPermissions, onResponse, commandParams, commandType, cmd, url; return regeneratorRuntime.wrap(function _callee5$(_context5) { while (1) { switch (_context5.prev = _context5.next) { case 0: to = _ref3.to, permissions = _ref3.permissions, allPermissions = _ref3.allPermissions, onResponse = _ref3.onResponse; commandParams = { permissions: permissions, allPermissions: allPermissions ? 0 : 1 }; commandType = "MTL_APPLY_PERMISSION"; cmd = { commandType: commandType, commandParams: commandParams, to: to }; url = this._baseUrl() + "permissions/apply"; _context5.next = 7; return this.sendCommand({ cmd: cmd, url: url, listener: onResponse }); case 7: return _context5.abrupt("return", _context5.sent); case 8: case "end": return _context5.stop(); } } }, _callee5, this); })); function requestAccess(_x4) { return _requestAccess.apply(this, arguments); } return requestAccess; }() // 处理设备访问权限请求 }, { key: "processAccessRequest", value: function () { var _processAccessRequest = _asyncToGenerator( /*#__PURE__*/ regeneratorRuntime.mark(function _callee6(_ref4, agree) { var to, permissions, allPermissions, sourceCommandId, commandParams, commandType, cmd, url; return regeneratorRuntime.wrap(function _callee6$(_context6) { while (1) { switch (_context6.prev = _context6.next) { case 0: to = _ref4.to, permissions = _ref4.permissions, allPermissions = _ref4.allPermissions, sourceCommandId = _ref4.sourceCommandId; commandParams = { permissions: permissions, allPermissions: typeof allPermissions === "boolean" ? allPermissions ? 0 : 1 : allPermissions, result: agree ? 0 : 1 }; // result: 0.同意;1.拒绝; commandType = "MTL_APPLY_PERMISSION"; cmd = { commandType: commandType, commandParams: commandParams, to: to, sourceCommandId: sourceCommandId }; url = this._baseUrl() + "permissions/process"; _context6.next = 7; return this.sendCommand({ cmd: cmd, url: url }); case 7: return _context6.abrupt("return", _context6.sent); case 8: case "end": return _context6.stop(); } } }, _callee6, this); })); function processAccessRequest(_x5, _x6) { return _processAccessRequest.apply(this, arguments); } return processAccessRequest; }() // MARK: - 设备相关 /** * 获取设备列表 * @param {*} type 0.我授权的;1.授权给我的;2.0+1;3.我的设备; */ }, { key: "getDevices", value: function () { var _getDevices = _asyncToGenerator( /*#__PURE__*/ regeneratorRuntime.mark(function _callee7(_ref5) { var _ref5$startIndex, startIndex, _ref5$pageSize, pageSize, type, _this$userinfo2, token, deviceId, url, params, response; return regeneratorRuntime.wrap(function _callee7$(_context7) { while (1) { switch (_context7.prev = _context7.next) { case 0: _ref5$startIndex = _ref5.startIndex, startIndex = _ref5$startIndex === void 0 ? 0 : _ref5$startIndex, _ref5$pageSize = _ref5.pageSize, pageSize = _ref5$pageSize === void 0 ? 100 : _ref5$pageSize, type = _ref5.type; if (!(typeof type != "number" || type < 0 || type > 3)) { _context7.next = 3; break; } throw new Error("参数 type 格式不对或值不在[0, 3]区间内"); case 3: _this$userinfo2 = this.userinfo, token = _this$userinfo2.token, deviceId = _this$userinfo2.deviceId; url = this._baseUrl() + (type == 3 ? "mydevices" : "devices"); params = { token: token, startIndex: startIndex, pageSize: pageSize }; if (type != 3) { params.bindingType = type; params.clientIdentify = deviceId; } _context7.next = 9; return axios({ method: "get", url: url, params: params }); case 9: response = _context7.sent; if (!(response.data.result == "success")) { _context7.next = 12; break; } return _context7.abrupt("return", response.data.data); case 12: throw new Error(response.data.errorMsg); case 13: case "end": return _context7.stop(); } } }, _callee7, this); })); function getDevices(_x7) { return _getDevices.apply(this, arguments); } return getDevices; }() /** * 删除设备 * @param {*} type 0.我授权的;1.授权给我的;3.我的设备; * @param {*} device 设备信息 { clientIdentify, userId, appId } */ }, { key: "deleteDevice", value: function () { var _deleteDevice = _asyncToGenerator( /*#__PURE__*/ regeneratorRuntime.mark(function _callee8(type, device) { var _this$userinfo3, token, deviceId, user, app, url, params, data, toClientIdentify, toUserId, toAppId, response; return regeneratorRuntime.wrap(function _callee8$(_context8) { while (1) { switch (_context8.prev = _context8.next) { case 0: if (!(typeof type != "number" || type < 0 || type > 3)) { _context8.next = 2; break; } throw new Error("参数 type 格式不对或值不在[0, 3]区间内"); case 2: _this$userinfo3 = this.userinfo, token = _this$userinfo3.token, deviceId = _this$userinfo3.deviceId, user = _this$userinfo3.user, app = _this$userinfo3.app; url = this._baseUrl(); _context8.t0 = type; _context8.next = _context8.t0 === 0 ? 7 : _context8.t0 === 1 ? 9 : _context8.t0 === 3 ? 11 : 13; break; case 7: url += "devices/byBindingDevices"; return _context8.abrupt("break", 13); case 9: url += "devices/bindingDevices"; return _context8.abrupt("break", 13); case 11: url += "mydevices/" + device.clientIdentify; return _context8.abrupt("break", 13); case 13: params = { token: token }; data = null; if (type != 3) { toClientIdentify = device.clientIdentify, toUserId = device.userId, toAppId = device.appId; data = { fromAppId: app, fromClientIdentify: deviceId, fromUserId: user, toClientIdentify: toClientIdentify, toUserId: toUserId, toAppId: toAppId }; } _context8.next = 18; return axios({ method: "delete", url: url, params: params, data: data }); case 18: response = _context8.sent; if (!(response.data.result == "success")) { _context8.next = 21; break; } return _context8.abrupt("return", response.data.data); case 21: throw new Error(response.data.errorMsg); case 22: case "end": return _context8.stop(); } } }, _callee8, this); })); function deleteDevice(_x8, _x9) { return _deleteDevice.apply(this, arguments); } return deleteDevice; }() // MARK: - private method }, { key: "_baseUrl", value: function _baseUrl() { if (!this.userinfo.token) throw new Error("未登录"); var server = this.restServer, etp = this.etp, app = this.app, isHttps = this.isHttps; var user = this.userinfo.user; return "".concat(isHttps ? "https" : "http", "://").concat(server, "/sysadmin/rest/user/").concat(etp, "/").concat(app, "/").concat(user, "/multiterminals/"); } // 收到多端消息回调 }, { key: "_onmessage", value: function _onmessage(msg) { var category = msg.category, attributes = msg.attributes; var ignoredCategories = ["addBinding", "removeBinding"]; if (ignoredCategories.indexOf(category) !== -1) { // TODO: 提供一种监听类型,通知用户设备列表有变化,需要刷新。 return; } if (category == "clientCommand") { // 用户指令 var specialTypes = ["MTL_APPLY_PERMISSION"]; var commandType = attributes.commandType; if (specialTypes.indexOf(commandType) !== -1) { // 特殊类型的消息(如: 权限申请)不触发普通消息的监听。 var _iteratorNormalCompletion = true; var _didIteratorError = false; var _iteratorError = undefined; try { for (var _iterator = this._getListeners(commandType)[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) { var listener = _step.value; listener(this._dataToCommand(attributes)); } } catch (err) { _didIteratorError = true; _iteratorError = err; } finally { try { if (!_iteratorNormalCompletion && _iterator["return"] != null) { _iterator["return"](); } } finally { if (_didIteratorError) { throw _iteratorError; } } } } else { // 其它类型消息都是普通消息 var _iteratorNormalCompletion2 = true; var _didIteratorError2 = false; var _iteratorError2 = undefined; try { for (var _iterator2 = this._getListeners("message")[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) { var _listener = _step2.value; _listener(this._dataToCommand(attributes)); } } catch (err) { _didIteratorError2 = true; _iteratorError2 = err; } finally { try { if (!_iteratorNormalCompletion2 && _iterator2["return"] != null) { _iterator2["return"](); } } finally { if (_didIteratorError2) { throw _iteratorError2; } } } } } else if (category == "commandResponse") { // 回复消息 var sourceCommandId = attributes.sourceCommandId; var _listener2 = this._getListeners(REPLY_LISTENER_TYPE).find(function (item) { return item.identify == sourceCommandId; }); _listener2 && _listener2(this._dataToCommand(attributes)); } } // 通过 type 获取 listeners }, { key: "_getListeners", value: function _getListeners(type) { var listenerIds = this.listenerMap[type] || []; var invalidIds = []; var listeners = []; var _iteratorNormalCompletion3 = true; var _didIteratorError3 = false; var _iteratorError3 = undefined; try { for (var _iterator3 = listenerIds[Symbol.iterator](), _step3; !(_iteratorNormalCompletion3 = (_step3 = _iterator3.next()).done); _iteratorNormalCompletion3 = true) { var identify = _step3.value; var listener = this.listeners[identify]; if (listener) { listeners.push(listener); } else { invalidIds.push(identify); } } } catch (err) { _didIteratorError3 = true; _iteratorError3 = err; } finally { try { if (!_iteratorNormalCompletion3 && _iterator3["return"] != null) { _iterator3["return"](); } } finally { if (_didIteratorError3) { throw _iteratorError3; } } } listenerIds = listenerIds.filter(function (item) { return invalidIds.indexOf(item.identify) === -1; }); this.listenerMap[type] = listenerIds; return listeners; } // 将指令对象还原成原始数据结构,用于发送网络请求。 }, { key: "_commandToData", value: function _commandToData(cmd) { var _this$userinfo4 = this.userinfo, app = _this$userinfo4.app, user = _this$userinfo4.user, deviceId = _this$userinfo4.deviceId; var from = cmd.from || { appId: app, clientIdentify: deviceId, userId: user }; var to = cmd.to || {}; var complex = { commandId: uuid(), fromAppId: from.appId, fromClientIdentify: from.clientIdentify, fromUserId: from.userId, toAppId: to.appId, toClientIdentify: to.clientIdentify, toUserId: to.userId }; var origin = _objectSpread({}, cmd); delete origin.from; delete origin.to; return Object.assign(origin, complex); } // 将原始数据转换成指令对象,方便用户使用。 }, { key: "_dataToCommand", value: function _dataToCommand(data) { var cmd = _objectSpread({}, data); var fromAppId = cmd.fromAppId, fromClientIdentify = cmd.fromClientIdentify, fromUserId = cmd.fromUserId; delete cmd.fromAppId; delete cmd.fromClientIdentify; delete cmd.fromUserId; cmd.from = { appId: fromAppId, clientIdentify: fromClientIdentify, userId: fromUserId }; return cmd; } }]); return Manager; }(); return Manager; };