wtws.js 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386
  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. $A.updateConfigLists(thas.__config.key, {
  170. online: true
  171. });
  172. };
  173. // 连接关闭时触发
  174. this.__instance.onclose = function (event) {
  175. thas.__log("[WS] Connection closed", event);
  176. thas.__connected = false;
  177. thas.__instance = null;
  178. thas.__autoLine(5);
  179. $A.updateConfigLists(thas.__config.key, {
  180. online: false
  181. });
  182. }
  183. // 连接出错
  184. this.__instance.onerror = function (event) {
  185. thas.__log("[WS] Connection error", event);
  186. thas.__connected = false;
  187. thas.__instance = null;
  188. thas.__autoLine(5);
  189. $A.updateConfigLists(thas.__config.key, {
  190. online: false
  191. });
  192. }
  193. return this;
  194. }
  195. /**
  196. * 添加消息监听
  197. * @param listenerName
  198. * @param listenerType
  199. * @param callback
  200. */
  201. this.setOnMsgListener = function (listenerName, listenerType, callback) {
  202. if (typeof listenerName != "string") {
  203. return this;
  204. }
  205. if (typeof listenerType === "function") {
  206. callback = listenerType;
  207. listenerType = [];
  208. }
  209. if (!this.__isArr(listenerType)) {
  210. listenerType = [listenerType];
  211. }
  212. if (typeof callback === "function") {
  213. this.__msgListenerObject[listenerName] = {
  214. callback: callback,
  215. listenerType: listenerType,
  216. }
  217. }
  218. return this;
  219. }
  220. this.triggerMsgListener = function (msgDetail) {
  221. var key, item;
  222. for (key in this.__msgListenerObject) {
  223. if (!this.__msgListenerObject.hasOwnProperty(key)) {
  224. continue;
  225. }
  226. item = this.__msgListenerObject[key];
  227. if (item.listenerType.length > 0 && item.listenerType.indexOf(msgDetail.messageType) === -1) {
  228. continue;
  229. }
  230. if (typeof item.callback === "function") {
  231. item.callback(msgDetail);
  232. }
  233. }
  234. }
  235. this.__msgListenerObject = {}
  236. /**
  237. * 添加特殊监听
  238. * @param listenerName
  239. * @param callback
  240. */
  241. this.setOnSpecialListener = function (listenerName, callback) {
  242. if (typeof listenerName != "string") {
  243. return this;
  244. }
  245. if (typeof callback === "function") {
  246. this.__specialListenerObject[listenerName] = {
  247. callback: callback,
  248. }
  249. }
  250. return this;
  251. }
  252. this.triggerSpecialListener = function (simpleMsg) {
  253. var key, item;
  254. for (key in this.__specialListenerObject) {
  255. if (!this.__specialListenerObject.hasOwnProperty(key)) {
  256. continue;
  257. }
  258. item = this.__specialListenerObject[key];
  259. if (typeof item.callback === "function") {
  260. item.callback(simpleMsg);
  261. }
  262. }
  263. }
  264. this.__specialListenerObject = {}
  265. /**
  266. * 发送消息
  267. * @param messageType 会话类型
  268. * - refresh: 刷新
  269. * - unread: 未读信息总数量
  270. * - read: 已读会员信息
  271. * - roger: 收到信息回执
  272. * - user: 指定target
  273. * - team: 团队会员
  274. * @param target 发送目标
  275. * @param body 发送内容(对象或数组)
  276. * @param callback 发送回调
  277. * @param againNum
  278. */
  279. this.sendTo = function (messageType, target, body, callback, againNum = 0) {
  280. if (typeof target === "object" && typeof body === "undefined") {
  281. body = target;
  282. target = null;
  283. }
  284. if (typeof target === "function") {
  285. body = target;
  286. target = null;
  287. }
  288. if (typeof body === "function") {
  289. callback = body;
  290. body = null;
  291. }
  292. if (body === null || typeof body !== "object") {
  293. body = {};
  294. }
  295. //
  296. var thas = this;
  297. if (this.__instance === null || this.__connected === false) {
  298. if (againNum < 10 && messageType != 'team') {
  299. setTimeout(function () {
  300. thas.sendTo(messageType, target, body, callback, thas.__rNum(againNum) + 1)
  301. }, 600);
  302. if (againNum === 0) {
  303. this.connection();
  304. }
  305. } else {
  306. if (this.__instance === null) {
  307. this.__log("[WS] Service not connected");
  308. typeof callback === "function" && callback({status: 0, message: '服务未连接'});
  309. } else {
  310. this.__log("[WS] Failed connection");
  311. typeof callback === "function" && callback({status: 0, message: '未连接成功'});
  312. }
  313. }
  314. return this;
  315. }
  316. if (['refresh', 'unread', 'read', 'roger', 'user', 'team'].indexOf(messageType) === -1) {
  317. this.__log("[WS] Wrong message messageType: " + messageType);
  318. typeof callback === "function" && callback({status: 0, message: '错误的消息类型: ' + messageType});
  319. return this;
  320. }
  321. //
  322. var contentId = 0;
  323. if (messageType === 'roger') {
  324. contentId = target;
  325. target = null;
  326. }
  327. var messageId = '';
  328. if (typeof callback === "string" && callback === 'special') {
  329. callback = function (res) {
  330. res.status === 1 && thas.triggerSpecialListener({
  331. target: target,
  332. body: body,
  333. });
  334. }
  335. }
  336. if (typeof callback === "function") {
  337. messageId = this.__randString(16);
  338. this.__callbackid[messageId] = callback;
  339. }
  340. this.__instance.send(JSON.stringify({
  341. messageType: messageType,
  342. messageId: messageId,
  343. contentId: contentId,
  344. channel: this.__config.channel,
  345. username: this.__config.username,
  346. target: target,
  347. body: body,
  348. time: Math.round(new Date().getTime() / 1000),
  349. }));
  350. return this;
  351. }
  352. /**
  353. * 关闭连接
  354. */
  355. this.close = function () {
  356. if (this.__instance === null) {
  357. this.__log("[WS] Service not connected");
  358. return this;
  359. }
  360. if (this.__connected === false) {
  361. this.__log("[WS] Failed connection");
  362. return this;
  363. }
  364. this.__instance.close();
  365. return this;
  366. }
  367. return this.config(config);
  368. }