wtws.js 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367
  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.url = config.url || '';
  108. config.token = config.token || '';
  109. config.channel = config.channel || '';
  110. config.logCallback = config.logCallback || null;
  111. this.__config = config;
  112. return this;
  113. }
  114. /**
  115. * 连接
  116. * @param force
  117. */
  118. this.connection = function (force) {
  119. if (!this.__lExists(this.__config.url, "ws://") && !this.__lExists(this.__config.url, "wss://")) {
  120. this.__log("[WS] No connection address");
  121. return this;
  122. }
  123. if (!this.__config.token) {
  124. this.__log("[WS] No connected token");
  125. return this;
  126. }
  127. if (this.__instance !== null && force !== true) {
  128. this.__log("[WS] Connection exists");
  129. return this;
  130. }
  131. var thas = this;
  132. // 初始化客户端套接字并建立连接
  133. this.__instance = new WebSocket(this.__urlParams(this.__config.url, {
  134. token: this.__config.token,
  135. channel: this.__config.channel
  136. }));
  137. // 连接建立时触发
  138. this.__instance.onopen = function (event) {
  139. thas.__log("[WS] Connection opened", event);
  140. }
  141. // 接收到服务端推送时执行
  142. this.__instance.onmessage = function (event) {
  143. var msgDetail = thas.__jParse(event.data);
  144. if (msgDetail.messageType === 'open') {
  145. thas.__log("[WS] Connection connected");
  146. msgDetail.openNum = thas.__openNum;
  147. msgDetail.config = thas.__config;
  148. thas.__openNum++;
  149. thas.__connected = true;
  150. thas.__autoLine(30);
  151. } else if (msgDetail.messageType === 'back') {
  152. typeof thas.__callbackid[msgDetail.messageId] === "function" && thas.__callbackid[msgDetail.messageId](msgDetail.body);
  153. delete thas.__callbackid[msgDetail.messageId];
  154. return;
  155. }
  156. if (thas.__rNum(msgDetail.contentId) > 0) {
  157. thas.sendTo('roger', msgDetail.contentId);
  158. }
  159. thas.triggerMsgListener(msgDetail);
  160. };
  161. // 连接关闭时触发
  162. this.__instance.onclose = function (event) {
  163. thas.__log("[WS] Connection closed", event);
  164. thas.__connected = false;
  165. thas.__instance = null;
  166. thas.__autoLine(5);
  167. }
  168. // 连接出错
  169. this.__instance.onerror = function (event) {
  170. thas.__log("[WS] Connection error", event);
  171. thas.__connected = false;
  172. thas.__instance = null;
  173. thas.__autoLine(5);
  174. }
  175. return this;
  176. }
  177. /**
  178. * 添加消息监听
  179. * @param listenerName
  180. * @param listenerType
  181. * @param callback
  182. */
  183. this.setOnMsgListener = function (listenerName, listenerType, callback) {
  184. if (typeof listenerName != "string") {
  185. return this;
  186. }
  187. if (typeof listenerType === "function") {
  188. callback = listenerType;
  189. listenerType = [];
  190. }
  191. if (!this.__isArr(listenerType)) {
  192. listenerType = [listenerType];
  193. }
  194. if (typeof callback === "function") {
  195. this.__msgListenerObject[listenerName] = {
  196. callback: callback,
  197. listenerType: listenerType,
  198. }
  199. }
  200. return this;
  201. }
  202. this.triggerMsgListener = function (msgDetail) {
  203. var key, item;
  204. for (key in this.__msgListenerObject) {
  205. if (!this.__msgListenerObject.hasOwnProperty(key)) {
  206. continue;
  207. }
  208. item = this.__msgListenerObject[key];
  209. if (item.listenerType.length > 0 && item.listenerType.indexOf(msgDetail.messageType) === -1) {
  210. continue;
  211. }
  212. if (typeof item.callback === "function") {
  213. item.callback(msgDetail);
  214. }
  215. }
  216. }
  217. this.__msgListenerObject = {}
  218. /**
  219. * 添加特殊监听
  220. * @param listenerName
  221. * @param callback
  222. */
  223. this.setOnSpecialListener = function (listenerName, callback) {
  224. if (typeof listenerName != "string") {
  225. return this;
  226. }
  227. if (typeof callback === "function") {
  228. this.__specialListenerObject[listenerName] = {
  229. callback: callback,
  230. }
  231. }
  232. return this;
  233. }
  234. this.triggerSpecialListener = function (simpleMsg) {
  235. var key, item;
  236. for (key in this.__specialListenerObject) {
  237. if (!this.__specialListenerObject.hasOwnProperty(key)) {
  238. continue;
  239. }
  240. item = this.__specialListenerObject[key];
  241. if (typeof item.callback === "function") {
  242. item.callback(simpleMsg);
  243. }
  244. }
  245. }
  246. this.__specialListenerObject = {}
  247. /**
  248. * 发送消息
  249. * @param messageType 会话类型
  250. * - refresh: 刷新
  251. * - unread: 未读信息总数量
  252. * - read: 已读会员信息
  253. * - roger: 收到信息回执
  254. * - user: 指定target
  255. * - team: 团队会员
  256. * @param target 发送目标
  257. * @param body 发送内容(对象或数组)
  258. * @param callback 发送回调
  259. * @param againNum
  260. */
  261. this.sendTo = function (messageType, target, body, callback, againNum = 0) {
  262. if (typeof target === "object" && typeof body === "undefined") {
  263. body = target;
  264. target = null;
  265. }
  266. if (typeof target === "function") {
  267. body = target;
  268. target = null;
  269. }
  270. if (typeof body === "function") {
  271. callback = body;
  272. body = null;
  273. }
  274. if (body === null || typeof body !== "object") {
  275. body = {};
  276. }
  277. //
  278. var thas = this;
  279. if (this.__instance === null || this.__connected === false) {
  280. if (againNum < 10 && messageType != 'team') {
  281. setTimeout(function () {
  282. thas.sendTo(messageType, target, body, callback, thas.__rNum(againNum) + 1)
  283. }, 600);
  284. if (againNum === 0) {
  285. this.connection();
  286. }
  287. } else {
  288. if (this.__instance === null) {
  289. this.__log("[WS] Service not connected");
  290. typeof callback === "function" && callback({status: 0, message: '服务未连接'});
  291. } else {
  292. this.__log("[WS] Failed connection");
  293. typeof callback === "function" && callback({status: 0, message: '未连接成功'});
  294. }
  295. }
  296. return this;
  297. }
  298. if (['refresh', 'unread', 'read', 'roger', 'user', 'team'].indexOf(messageType) === -1) {
  299. this.__log("[WS] Wrong message messageType: " + messageType);
  300. typeof callback === "function" && callback({status: 0, message: '错误的消息类型: ' + messageType});
  301. return this;
  302. }
  303. //
  304. var contentId = 0;
  305. if (messageType === 'roger') {
  306. contentId = target;
  307. target = null;
  308. }
  309. var messageId = '';
  310. if (typeof callback === "string" && callback === 'special') {
  311. callback = function (res) {
  312. res.status === 1 && thas.triggerSpecialListener({
  313. target: target,
  314. body: body,
  315. });
  316. }
  317. }
  318. if (typeof callback === "function") {
  319. messageId = this.__randString(16);
  320. this.__callbackid[messageId] = callback;
  321. }
  322. this.__instance.send(JSON.stringify({
  323. messageType: messageType,
  324. messageId: messageId,
  325. contentId: contentId,
  326. channel: this.__config.channel,
  327. username: this.__config.username,
  328. target: target,
  329. body: body,
  330. time: Math.round(new Date().getTime() / 1000),
  331. }));
  332. return this;
  333. }
  334. /**
  335. * 关闭连接
  336. */
  337. this.close = function () {
  338. if (this.__instance === null) {
  339. this.__log("[WS] Service not connected");
  340. return this;
  341. }
  342. if (this.__connected === false) {
  343. this.__log("[WS] Failed connection");
  344. return this;
  345. }
  346. this.__instance.close();
  347. return this;
  348. }
  349. return this.config(config);
  350. }