mtl-js-sdk
Version:
879 lines (748 loc) • 32 kB
JavaScript
"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;
};