wtws.js 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377
  1. /**
  2. * WTWS
  3. * @param config {username, url, token, channel, logCallback}
  4. * @constructor
  5. */
  6. const WTWS = function (config) {
  7. this.__instance = null;
  8. this.__connected = false;
  9. this.__callbackid = {};
  10. this.__openNum = 0;
  11. this.__autoNum = 0;
  12. this.__autoLine = function (timeout) {
  13. var tempNum = this.__autoNum;
  14. var thas = this;
  15. setTimeout(function () {
  16. if (tempNum === thas.__autoNum) {
  17. thas.__autoNum++
  18. if (!thas.__config.token) {
  19. thas.__log("[WS] No token");
  20. thas.__autoLine(timeout + 5);
  21. } else {
  22. thas.sendTo('refresh', function (res) {
  23. thas.__log("[WS] Connection " + (res.status ? 'success' : 'error'));
  24. thas.__autoLine(timeout + 5);
  25. });
  26. }
  27. }
  28. }, Math.min(timeout, 30) * 1000);
  29. }
  30. this.__log = function (text, event) {
  31. typeof this.__config.logCallback === "function" && this.__config.logCallback(text, event);
  32. }
  33. this.__lExists = function (string, find, lower) {
  34. string += "";
  35. find += "";
  36. if (lower !== true) {
  37. string = string.toLowerCase();
  38. find = find.toLowerCase();
  39. }
  40. return (string.substring(0, find.length) === find);
  41. }
  42. this.__rNum = function (str, fixed) {
  43. var _s = Number(str);
  44. if (_s + "" === "NaN") {
  45. _s = 0;
  46. }
  47. if (/^[0-9]*[1-9][0-9]*$/.test(fixed)) {
  48. _s = _s.toFixed(fixed);
  49. var rs = _s.indexOf('.');
  50. if (rs < 0) {
  51. _s += ".";
  52. for (var i = 0; i < fixed; i++) {
  53. _s += "0";
  54. }
  55. }
  56. }
  57. return _s;
  58. }
  59. this.__jParse = function (str, defaultVal) {
  60. if (str === null) {
  61. return defaultVal ? defaultVal : {};
  62. }
  63. if (typeof str === "object") {
  64. return str;
  65. }
  66. try {
  67. return JSON.parse(str);
  68. } catch (e) {
  69. return defaultVal ? defaultVal : {};
  70. }
  71. }
  72. this.__randString = function (len) {
  73. len = len || 32;
  74. var $chars = 'ABCDEFGHJKMNPQRSTWXYZabcdefhijkmnprstwxyz2345678oOLl9gqVvUuI1';
  75. var maxPos = $chars.length;
  76. var pwd = '';
  77. for (var i = 0; i < len; i++) {
  78. pwd += $chars.charAt(Math.floor(Math.random() * maxPos));
  79. }
  80. return pwd;
  81. }
  82. this.__urlParams = function(url, params) {
  83. if (typeof params === "object" && params !== null) {
  84. url+= "";
  85. url+= url.indexOf("?") === -1 ? '?' : '';
  86. for (var key in params) {
  87. if (!params.hasOwnProperty(key)) {
  88. continue;
  89. }
  90. url+= '&' + key + '=' + params[key];
  91. }
  92. }
  93. return url.replace("?&", "?");
  94. }
  95. this.__isArr = function (obj){
  96. return Object.prototype.toString.call(obj)=='[object Array]';
  97. }
  98. /**
  99. * 设置参数
  100. * @param config
  101. */
  102. this.config = function (config) {
  103. if (typeof config !== "object" || config === null) {
  104. config = {};
  105. }
  106. config.username = config.username || '';
  107. config.key = config.key || '';
  108. config.url = config.url || '';
  109. config.token = config.token || '';
  110. config.channel = config.channel || '';
  111. config.logCallback = config.logCallback || null;
  112. this.__config = config;
  113. return this;
  114. }
  115. /**
  116. * 连接
  117. * @param force
  118. */
  119. this.connection = function (force) {
  120. if (!this.__lExists(this.__config.url, "ws://") && !this.__lExists(this.__config.url, "wss://")) {
  121. this.__log("[WS] No connection address");
  122. return this;
  123. }
  124. if (!this.__config.token) {
  125. this.__log("[WS] No connected token");
  126. return this;
  127. }
  128. if (this.__instance !== null && force !== true) {
  129. this.__log("[WS] Connection exists");
  130. return this;
  131. }
  132. var configLists = $A.jsonParse($A.getStorage("configLists"), {});
  133. var keyConfig = configLists[this.__config.key];
  134. if (keyConfig !== null && typeof keyConfig == "object") {
  135. if (keyConfig['disabled'] === true) {
  136. this.__log("[WS] " + this.__config.key + " is disabled");
  137. return this;
  138. }
  139. }
  140. var thas = this;
  141. // 初始化客户端套接字并建立连接
  142. this.__instance = new WebSocket(this.__urlParams(this.__config.url, {
  143. token: this.__config.token,
  144. channel: this.__config.channel
  145. }));
  146. // 连接建立时触发
  147. this.__instance.onopen = function (event) {
  148. thas.__log("[WS] Connection opened", event);
  149. }
  150. // 接收到服务端推送时执行
  151. this.__instance.onmessage = function (event) {
  152. var msgDetail = thas.__jParse(event.data);
  153. if (msgDetail.messageType === 'open') {
  154. thas.__log("[WS] Connection connected");
  155. msgDetail.openNum = thas.__openNum;
  156. msgDetail.config = thas.__config;
  157. thas.__openNum++;
  158. thas.__connected = true;
  159. thas.__autoLine(30);
  160. } else if (msgDetail.messageType === 'back') {
  161. typeof thas.__callbackid[msgDetail.messageId] === "function" && thas.__callbackid[msgDetail.messageId](msgDetail.body);
  162. delete thas.__callbackid[msgDetail.messageId];
  163. return;
  164. }
  165. if (thas.__rNum(msgDetail.contentId) > 0) {
  166. thas.sendTo('roger', msgDetail.contentId);
  167. }
  168. thas.triggerMsgListener(msgDetail);
  169. };
  170. // 连接关闭时触发
  171. this.__instance.onclose = function (event) {
  172. thas.__log("[WS] Connection closed", event);
  173. thas.__connected = false;
  174. thas.__instance = null;
  175. thas.__autoLine(5);
  176. }
  177. // 连接出错
  178. this.__instance.onerror = function (event) {
  179. thas.__log("[WS] Connection error", event);
  180. thas.__connected = false;
  181. thas.__instance = null;
  182. thas.__autoLine(5);
  183. }
  184. return this;
  185. }
  186. /**
  187. * 添加消息监听
  188. * @param listenerName
  189. * @param listenerType
  190. * @param callback
  191. */
  192. this.setOnMsgListener = function (listenerName, listenerType, callback) {
  193. if (typeof listenerName != "string") {
  194. return this;
  195. }
  196. if (typeof listenerType === "function") {
  197. callback = listenerType;
  198. listenerType = [];
  199. }
  200. if (!this.__isArr(listenerType)) {
  201. listenerType = [listenerType];
  202. }
  203. if (typeof callback === "function") {
  204. this.__msgListenerObject[listenerName] = {
  205. callback: callback,
  206. listenerType: listenerType,
  207. }
  208. }
  209. return this;
  210. }
  211. this.triggerMsgListener = function (msgDetail) {
  212. var key, item;
  213. for (key in this.__msgListenerObject) {
  214. if (!this.__msgListenerObject.hasOwnProperty(key)) {
  215. continue;
  216. }
  217. item = this.__msgListenerObject[key];
  218. if (item.listenerType.length > 0 && item.listenerType.indexOf(msgDetail.messageType) === -1) {
  219. continue;
  220. }
  221. if (typeof item.callback === "function") {
  222. item.callback(msgDetail);
  223. }
  224. }
  225. }
  226. this.__msgListenerObject = {}
  227. /**
  228. * 添加特殊监听
  229. * @param listenerName
  230. * @param callback
  231. */
  232. this.setOnSpecialListener = function (listenerName, callback) {
  233. if (typeof listenerName != "string") {
  234. return this;
  235. }
  236. if (typeof callback === "function") {
  237. this.__specialListenerObject[listenerName] = {
  238. callback: callback,
  239. }
  240. }
  241. return this;
  242. }
  243. this.triggerSpecialListener = function (simpleMsg) {
  244. var key, item;
  245. for (key in this.__specialListenerObject) {
  246. if (!this.__specialListenerObject.hasOwnProperty(key)) {
  247. continue;
  248. }
  249. item = this.__specialListenerObject[key];
  250. if (typeof item.callback === "function") {
  251. item.callback(simpleMsg);
  252. }
  253. }
  254. }
  255. this.__specialListenerObject = {}
  256. /**
  257. * 发送消息
  258. * @param messageType 会话类型
  259. * - refresh: 刷新
  260. * - unread: 未读信息总数量
  261. * - read: 已读会员信息
  262. * - roger: 收到信息回执
  263. * - user: 指定target
  264. * - team: 团队会员
  265. * @param target 发送目标
  266. * @param body 发送内容(对象或数组)
  267. * @param callback 发送回调
  268. * @param againNum
  269. */
  270. this.sendTo = function (messageType, target, body, callback, againNum = 0) {
  271. if (typeof target === "object" && typeof body === "undefined") {
  272. body = target;
  273. target = null;
  274. }
  275. if (typeof target === "function") {
  276. body = target;
  277. target = null;
  278. }
  279. if (typeof body === "function") {
  280. callback = body;
  281. body = null;
  282. }
  283. if (body === null || typeof body !== "object") {
  284. body = {};
  285. }
  286. //
  287. var thas = this;
  288. if (this.__instance === null || this.__connected === false) {
  289. if (againNum < 10 && messageType != 'team') {
  290. setTimeout(function () {
  291. thas.sendTo(messageType, target, body, callback, thas.__rNum(againNum) + 1)
  292. }, 600);
  293. if (againNum === 0) {
  294. this.connection();
  295. }
  296. } else {
  297. if (this.__instance === null) {
  298. this.__log("[WS] Service not connected");
  299. typeof callback === "function" && callback({status: 0, message: '服务未连接'});
  300. } else {
  301. this.__log("[WS] Failed connection");
  302. typeof callback === "function" && callback({status: 0, message: '未连接成功'});
  303. }
  304. }
  305. return this;
  306. }
  307. if (['refresh', 'unread', 'read', 'roger', 'user', 'team'].indexOf(messageType) === -1) {
  308. this.__log("[WS] Wrong message messageType: " + messageType);
  309. typeof callback === "function" && callback({status: 0, message: '错误的消息类型: ' + messageType});
  310. return this;
  311. }
  312. //
  313. var contentId = 0;
  314. if (messageType === 'roger') {
  315. contentId = target;
  316. target = null;
  317. }
  318. var messageId = '';
  319. if (typeof callback === "string" && callback === 'special') {
  320. callback = function (res) {
  321. res.status === 1 && thas.triggerSpecialListener({
  322. target: target,
  323. body: body,
  324. });
  325. }
  326. }
  327. if (typeof callback === "function") {
  328. messageId = this.__randString(16);
  329. this.__callbackid[messageId] = callback;
  330. }
  331. this.__instance.send(JSON.stringify({
  332. messageType: messageType,
  333. messageId: messageId,
  334. contentId: contentId,
  335. channel: this.__config.channel,
  336. username: this.__config.username,
  337. target: target,
  338. body: body,
  339. time: Math.round(new Date().getTime() / 1000),
  340. }));
  341. return this;
  342. }
  343. /**
  344. * 关闭连接
  345. */
  346. this.close = function () {
  347. if (this.__instance === null) {
  348. this.__log("[WS] Service not connected");
  349. return this;
  350. }
  351. if (this.__connected === false) {
  352. this.__log("[WS] Failed connection");
  353. return this;
  354. }
  355. this.__instance.close();
  356. return this;
  357. }
  358. return this.config(config);
  359. }