WebSokcet.js 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503
  1. // +----------------------------------------------------------------------
  2. // | 桌子工作室 [webSokcet] V0.12015014 Released
  3. // | 上行数据 clinet 下行数据 service
  4. // +----------------------------------------------------------------------
  5. // | Copyright (c) 2018-2019 ,MrTable All rights reserved.
  6. // +----------------------------------------------------------------------
  7. // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
  8. // +----------------------------------------------------------------------
  9. // | Author: Mr Table <admin@hjf.pw>
  10. // +----------------------------------------------------------------------
  11. import CryptoJS from "../vendor/CryptoJS.js";
  12. import { Base64 } from '../vendor/base64.js';
  13. import Message from "./Message.js";
  14. class WebSokcet {
  15. index = 0;
  16. //scoket
  17. socketTask = null;
  18. //事件返回
  19. eventCall = null;
  20. //是否已连接
  21. socketOpen = false;
  22. //定时器
  23. //心跳
  24. timerId = 0;
  25. //重发包
  26. timerId2 = 0;
  27. //是否在重连中
  28. isReconnect = false;
  29. //临时获取数据
  30. tmpData = [];
  31. //临时提交数据包[上行数据]
  32. tmpCliData = [];
  33. //临时提交数据包[下行数据]
  34. tmpSerData = [];
  35. //设备标识符
  36. deveicId = 0;
  37. //重试次数
  38. retryCount = 5;
  39. isClose = false;
  40. opts = {};
  41. constructor(opt) {
  42. let option = {wsUrl:""};
  43. this.opts = this.extend(option,opt);
  44. }
  45. /**
  46. * 连接socket
  47. */
  48. connect() {
  49. var that = this;
  50. this.isClose = false;
  51. this.socketTask = new wxSocket({
  52. wsUrl: this.opts.wsUrl,
  53. //打开
  54. onOpen:(res => {
  55. console.log("webSokcet连接成功");
  56. that.socketOpen = true;
  57. if (that.eventCall != null) that.eventCall('onOpen', '');
  58. //心跳包
  59. that.heartBeat();
  60. }),
  61. //获取消息
  62. onMessage:(onMessage) => {
  63. var aData = that.asyMessage(onMessage);
  64. if (aData == null) return;
  65. if (aData == '') return;
  66. console.log("接受到消息:" + JSON.stringify(aData));
  67. //确认帧【客户端主包】
  68. if (aData.msgType == 2) {
  69. that.ackFrame(aData);
  70. return;
  71. }
  72. //检查重复包帧【服务端主包】
  73. if (that.checkFrame(aData)) {
  74. if (that.eventCall != null) that.eventCall('onSendSuccess', aData);
  75. return;
  76. }
  77. that.tmpSerData.push({ time: new Date().getTime(),data: aData, msgId: aData.msgId});
  78. aData.isReSend = true;
  79. if(aData.isAsk) {
  80. let obj = new Message();
  81. obj.code = aData.code;
  82. obj.msgType = 2;
  83. obj.askId = aData.msgId;
  84. obj.data = that.eventCall == null ? "" : that.eventCall('onMessage', aData);
  85. this.send(obj.getData(),false);
  86. } else {
  87. if (that.eventCall != null) that.eventCall('onMessage', aData);
  88. }
  89. },
  90. //获取错误信息
  91. onError:res=>{
  92. console.log(res);
  93. that.socketOpen = false;
  94. if (res.errMsg != 'exceed max task count'){
  95. if (that.eventCall != null) that.eventCall('onError', res.errMsg);
  96. if(!this.isClose) that.reConnon();
  97. } else {
  98. if (that.eventCall != null) that.eventCall('onStop', res.errMsg);
  99. }
  100. },
  101. onClose:onClose => {
  102. console.log("webSokcet已关闭");
  103. that.socketOpen = false;
  104. if (that.eventCall != null) that.eventCall('onClose', '');
  105. this.socketTask.socket.close();
  106. if(!this.isClose) that.reConnon();
  107. }
  108. });
  109. }
  110. /**
  111. * 设置事件
  112. */
  113. setBackCall(call) {
  114. // console.log(call,'设置事件')
  115. this.eventCall = call;
  116. }
  117. ttClose(){
  118. clearInterval(this.timerId);
  119. clearInterval(this.timerId2);
  120. this.isClose = true;
  121. if(this.socketTask != null)
  122. this.socketTask.socket.close();
  123. }
  124. /**
  125. * 设置生成密钥
  126. * @param key
  127. */
  128. setKey(key) {
  129. this.opts.key = key;
  130. }
  131. /**
  132. * 发送数据
  133. * @param data 数据
  134. * fn
  135. * error
  136. * @returns {boolean}
  137. *
  138. */
  139. send(data,fn = null,error = null) {
  140. if (!this.socketOpen) { return null; }
  141. //发送数据
  142. try {
  143. //生成消息[分配设备ID]
  144. if (data.msgId == "") data.msgId = this.createMsgId();
  145. //解析加密数据
  146. console.log("发送数据:" + JSON.stringify(data.getData()));
  147. var AES = new CryptoJS.AES(this.opts.key);
  148. var jsonStr = AES.encrypt(JSON.stringify(data.getData()));
  149. //发送数据到服务器
  150. this.socketTask.send({data:jsonStr});
  151. //确认证就不存到缓存
  152. if (!data.ask) return null;
  153. //是否缓存存在
  154. var msgObj = this.findCliMsgId(data.msgId);
  155. //记录发送数据
  156. if (msgObj == null){
  157. this.tmpCliData.push({
  158. 'msgId' : data.msgId,//消息ID
  159. 'data' : data,
  160. 'count' : 1,//尝试次数
  161. 'time' : new Date().getTime(),//最红发送时间
  162. 'code' : 0,
  163. 'fn' : fn,
  164. 'error' : error
  165. });
  166. } else {
  167. msgObj['count']++;
  168. msgObj['time'] = new Date().getTime();
  169. }
  170. return data.msgId;
  171. } catch (e) {
  172. console.log(e.message);
  173. return null;
  174. }
  175. }
  176. /**
  177. * 掉线从连接
  178. */
  179. reConnon() {
  180. clearInterval(this.timerId);
  181. clearInterval(this.timerId2);
  182. var time = new Date().getTime();
  183. for (var i in this.tmpSerData) {
  184. var d = this.tmpSerData[i];
  185. if (time - d.time > 10 * 1000){
  186. this.tmpSerData.splice(i, 1);
  187. if (this.eventCall != null) this.eventCall('onSendError', d.data);
  188. }
  189. }
  190. setTimeout(function () {
  191. if (this.socketTask.readyState == 3) {
  192. console.log('webSokcet重连接');
  193. this.connect(this.token);
  194. }
  195. }.bind(this), 2000);
  196. }
  197. /**
  198. * 心跳包
  199. */
  200. heartBeat() {
  201. this.timerId = setInterval(function () {
  202. if (this.socketTask.readyState == 1) {
  203. this.socketTask.send({ data: '01'});
  204. if (this.eventCall != null) this.eventCall('onHeartBeat', {});
  205. }
  206. }.bind(this), 10 * 1000);
  207. //重发包
  208. this.timerId2 = setInterval(function () {
  209. if (this.socketTask.readyState == 1) {
  210. //重发机制
  211. this.reSend();
  212. //清理下行包
  213. this.clerSerData();
  214. }
  215. }.bind(this), 5 * 1000);
  216. return this;
  217. }
  218. /**
  219. * 数据重发
  220. */
  221. reSend(){
  222. var time = new Date().getTime();
  223. for (var i in this.tmpCliData) {
  224. var d = this.tmpCliData[i];
  225. //重发
  226. if(d.count < this.retryCount && time - d.time> 5000) {
  227. d.time = time;
  228. if (this.eventCall != null) this.eventCall('onReSend', d.data,d.count);
  229. this.send(d.data,false,null,null);
  230. continue;
  231. }
  232. if(d.count >= this.retryCount) {
  233. //发送失败
  234. if (this.eventCall != null) this.eventCall('onSendError', d.data);
  235. if(d.error != null) d.error();
  236. this.tmpCliData.splice(i, 1);
  237. }
  238. }
  239. }
  240. /**
  241. * 清理下行数据包[超过30秒]
  242. */
  243. clerSerData(){
  244. var time = new Date().getTime();
  245. for (var i in this.tmpSerData) {
  246. var d = this.tmpSerData[i];
  247. if (time - d.time > 30 * 1000){
  248. this.tmpSerData.splice(i, 1);
  249. }
  250. }
  251. }
  252. /**
  253. * 查找消息位置[上行数据]
  254. */
  255. findCliMsgId(msgId){
  256. for (var i = 0; i < this.tmpCliData.length;i++){
  257. if (this.tmpCliData[i].msgId == msgId) return this.tmpCliData[i];
  258. }
  259. return null;
  260. }
  261. /**
  262. * 重复包检测【服务端主包】【服务端重发消息(重复包拦截)】
  263. */
  264. checkFrame(data){
  265. // console.log(this.tmpSerData);
  266. for(var i in this.tmpSerData) {
  267. if(this.tmpSerData[i].data.msgId == data.msgId) {
  268. let sendAr = this.tmpSerData[i].data;
  269. if(sendAr.isAsk) {
  270. let obj = new Message();
  271. obj.code = sendAr.code;
  272. obj.msgType = 2;
  273. obj.askId = sendAr.msgId;
  274. obj.data = sendAr.data;
  275. this.send(obj.getData(),false);
  276. return true;
  277. }
  278. }
  279. }
  280. return false;
  281. }
  282. /**
  283. *
  284. * 确认帧【客户端主包】【取消客户端重发消息】
  285. *
  286. */
  287. ackFrame(data) {
  288. for (var i = 0; i < this.tmpCliData.length; i++) {
  289. if (this.tmpCliData[i].msgId == data.askId){
  290. if(this.tmpCliData[i].fn !== null) this.tmpCliData[i].fn(data.data);
  291. this.tmpCliData.splice(i, 1);
  292. break;
  293. }
  294. }
  295. }
  296. /**
  297. * 解析uStr
  298. */
  299. asyMessage(uStr) {
  300. try{
  301. //不支持这个
  302. if(uStr instanceof ArrayBuffer) {
  303. return null;
  304. }
  305. //是否分割线
  306. var isEof = false;
  307. if(uStr.length >= 4) {
  308. //\r\n\r\n
  309. if(uStr[uStr.length - 1] == "\n"
  310. && uStr[uStr.length - 2] == "\r"
  311. && uStr[uStr.length - 3] == "\n"
  312. && uStr[uStr.length - 4] == "\r"
  313. ) {
  314. isEof = true;
  315. }
  316. }
  317. //获取全部数据
  318. if (isEof) {
  319. var unAr = [],unArStr = "";
  320. //累加之前数据分包
  321. for (var i in this.tmpData) {
  322. unAr.push(this.tmpData[i]);
  323. }
  324. unArStr = unAr.join('');
  325. unArStr += uStr;
  326. this.tmpData = [];
  327. if(unArStr == "") return null;
  328. var AES = new CryptoJS.AES(this.opts.key);
  329. var data = AES.decrypt(unArStr.trim());
  330. if(data == "") return null;
  331. //console.log(data);
  332. return JSON.parse(data);
  333. } else {
  334. this.tmpData.push(uStr);
  335. }
  336. } catch(err) {
  337. console.log(err);
  338. return null;
  339. }
  340. }
  341. /**
  342. * 格式化转化
  343. */
  344. Uint8ArrayToString(fileData) {
  345. var dataString = "";
  346. for (var i = 0; i < fileData.length; i++) {
  347. dataString += String.fromCharCode(fileData[i]);
  348. }
  349. return dataString
  350. }
  351. createMsgId(){
  352. this.index ++;
  353. return "web" + this.deveicId + new Date().getTime() + this.index;
  354. }
  355. /**
  356. * 配置数据默认匹配
  357. * $a 默认数据比如:[]
  358. * $b 现在有
  359. */
  360. extend($a, $b) {
  361. let $r = [];
  362. //先遍历$b数据
  363. for (var i in $b) {
  364. $r[i] = $b[i];
  365. }
  366. //遍历默认数据
  367. for (var i in $a) {
  368. if ($r[i] == null) $r[i] = $a[i];
  369. }
  370. return $r;
  371. }
  372. }
  373. /**
  374. * websokcet
  375. * @param options
  376. * @returns {websocket}
  377. */
  378. class wxSocket {
  379. readyState = 0;
  380. socket = null;
  381. opts = {
  382. wsUrl: "",
  383. onOpen:()=>{},
  384. onMessage:()=>{},
  385. onError:()=>{},
  386. onClose:()=>{}
  387. };
  388. constructor(opt) {
  389. this.opts = this.extend(this.opts,opt);
  390. this.onInit();
  391. }
  392. onInit(){
  393. console.log('发起链接');
  394. console.log(this.opts.wsUrl);
  395. this.socket = uni.connectSocket({
  396. url:this.opts.wsUrl,
  397. complete:(res)=>{}
  398. });
  399. if(this.socket == null ){
  400. setTimeout(()=>{
  401. this.onInit();
  402. },1000);
  403. return;
  404. } else {
  405. //监听返回
  406. this.socket.onMessage(onMessage => { this.onMessage(onMessage);});
  407. this.socket.onOpen(res => { this.onOpen(res); });
  408. this.socket.onError(res => {this.onError(res);});
  409. this.socket.onClose(res => {this.onClose(res);});
  410. }
  411. }
  412. send(data) {
  413. this.socket.send({ data : data.data});
  414. }
  415. onOpen(event){
  416. this.bOpen = true;
  417. if(this.opts.onOpen){
  418. this.readyState= 1;
  419. this.opts.onOpen(event);
  420. }
  421. }
  422. /**
  423. *
  424. * @param msg
  425. */
  426. onSend(msg){
  427. if(this.opts.onSend){
  428. this.opts.onSend(msg);
  429. }
  430. this.socket.send(msg);
  431. }
  432. /**
  433. *
  434. * @param msg
  435. */
  436. onMessage(msg){
  437. if(this.opts.onMessage){
  438. this.opts.onMessage(msg.data);
  439. }
  440. }
  441. /**
  442. *
  443. * @param event
  444. */
  445. onError(event){
  446. console.log(event);
  447. if(this.opts.onError){
  448. this.readyState = 3;
  449. this.opts.onError(event);
  450. }
  451. }
  452. /**
  453. *
  454. * @param event
  455. */
  456. onClose(event){
  457. if(this.opts.onClose){
  458. this.readyState = 3;
  459. this.opts.onClose(event);
  460. }
  461. if(this.socket.close() != null){
  462. this.socket = null;
  463. }
  464. }
  465. extend($a, $b){
  466. let $r = [];for (var i in $b) {$r[i] = $b[i];}for (var i in $a) {if ($r[i] == null) $r[i] = $a[i];}return $r;
  467. }
  468. }
  469. export default WebSokcet