WebSokcet.js 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502
  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. this.eventCall = call;
  115. }
  116. ttClose(){
  117. clearInterval(this.timerId);
  118. clearInterval(this.timerId2);
  119. this.isClose = true;
  120. if(this.socketTask != null)
  121. this.socketTask.socket.close();
  122. }
  123. /**
  124. * 设置生成密钥
  125. * @param key
  126. */
  127. setKey(key) {
  128. this.opts.key = key;
  129. }
  130. /**
  131. * 发送数据
  132. * @param data 数据
  133. * fn
  134. * error
  135. * @returns {boolean}
  136. *
  137. */
  138. send(data,fn = null,error = null) {
  139. if (!this.socketOpen) { return null; }
  140. //发送数据
  141. try {
  142. //生成消息[分配设备ID]
  143. if (data.msgId == "") data.msgId = this.createMsgId();
  144. //解析加密数据
  145. console.log("发送数据:" + JSON.stringify(data.getData()));
  146. var AES = new CryptoJS.AES(this.opts.key);
  147. var jsonStr = AES.encrypt(JSON.stringify(data.getData()));
  148. //发送数据到服务器
  149. this.socketTask.send({data:jsonStr});
  150. //确认证就不存到缓存
  151. if (!data.ask) return null;
  152. //是否缓存存在
  153. var msgObj = this.findCliMsgId(data.msgId);
  154. //记录发送数据
  155. if (msgObj == null){
  156. this.tmpCliData.push({
  157. 'msgId' : data.msgId,//消息ID
  158. 'data' : data,
  159. 'count' : 1,//尝试次数
  160. 'time' : new Date().getTime(),//最红发送时间
  161. 'code' : 0,
  162. 'fn' : fn,
  163. 'error' : error
  164. });
  165. } else {
  166. msgObj['count']++;
  167. msgObj['time'] = new Date().getTime();
  168. }
  169. return data.msgId;
  170. } catch (e) {
  171. console.log(e.message);
  172. return null;
  173. }
  174. }
  175. /**
  176. * 掉线从连接
  177. */
  178. reConnon() {
  179. clearInterval(this.timerId);
  180. clearInterval(this.timerId2);
  181. var time = new Date().getTime();
  182. for (var i in this.tmpSerData) {
  183. var d = this.tmpSerData[i];
  184. if (time - d.time > 10 * 1000){
  185. this.tmpSerData.splice(i, 1);
  186. if (this.eventCall != null) this.eventCall('onSendError', d.data);
  187. }
  188. }
  189. setTimeout(function () {
  190. if (this.socketTask.readyState == 3) {
  191. console.log('webSokcet重连接');
  192. this.connect(this.token);
  193. }
  194. }.bind(this), 2000);
  195. }
  196. /**
  197. * 心跳包
  198. */
  199. heartBeat() {
  200. this.timerId = setInterval(function () {
  201. if (this.socketTask.readyState == 1) {
  202. this.socketTask.send({ data: '01'});
  203. if (this.eventCall != null) this.eventCall('onHeartBeat', {});
  204. }
  205. }.bind(this), 10 * 1000);
  206. //重发包
  207. this.timerId2 = setInterval(function () {
  208. if (this.socketTask.readyState == 1) {
  209. //重发机制
  210. this.reSend();
  211. //清理下行包
  212. this.clerSerData();
  213. }
  214. }.bind(this), 5 * 1000);
  215. return this;
  216. }
  217. /**
  218. * 数据重发
  219. */
  220. reSend(){
  221. var time = new Date().getTime();
  222. for (var i in this.tmpCliData) {
  223. var d = this.tmpCliData[i];
  224. //重发
  225. if(d.count < this.retryCount && time - d.time> 5000) {
  226. d.time = time;
  227. if (this.eventCall != null) this.eventCall('onReSend', d.data,d.count);
  228. this.send(d.data,false,null,null);
  229. continue;
  230. }
  231. if(d.count >= this.retryCount) {
  232. //发送失败
  233. if (this.eventCall != null) this.eventCall('onSendError', d.data);
  234. if(d.error != null) d.error();
  235. this.tmpCliData.splice(i, 1);
  236. }
  237. }
  238. }
  239. /**
  240. * 清理下行数据包[超过30秒]
  241. */
  242. clerSerData(){
  243. var time = new Date().getTime();
  244. for (var i in this.tmpSerData) {
  245. var d = this.tmpSerData[i];
  246. if (time - d.time > 30 * 1000){
  247. this.tmpSerData.splice(i, 1);
  248. }
  249. }
  250. }
  251. /**
  252. * 查找消息位置[上行数据]
  253. */
  254. findCliMsgId(msgId){
  255. for (var i = 0; i < this.tmpCliData.length;i++){
  256. if (this.tmpCliData[i].msgId == msgId) return this.tmpCliData[i];
  257. }
  258. return null;
  259. }
  260. /**
  261. * 重复包检测【服务端主包】【服务端重发消息(重复包拦截)】
  262. */
  263. checkFrame(data){
  264. // console.log(this.tmpSerData);
  265. for(var i in this.tmpSerData) {
  266. if(this.tmpSerData[i].data.msgId == data.msgId) {
  267. let sendAr = this.tmpSerData[i].data;
  268. if(sendAr.isAsk) {
  269. let obj = new Message();
  270. obj.code = sendAr.code;
  271. obj.msgType = 2;
  272. obj.askId = sendAr.msgId;
  273. obj.data = sendAr.data;
  274. this.send(obj.getData(),false);
  275. return true;
  276. }
  277. }
  278. }
  279. return false;
  280. }
  281. /**
  282. *
  283. * 确认帧【客户端主包】【取消客户端重发消息】
  284. *
  285. */
  286. ackFrame(data) {
  287. for (var i = 0; i < this.tmpCliData.length; i++) {
  288. if (this.tmpCliData[i].msgId == data.askId){
  289. if(this.tmpCliData[i].fn !== null) this.tmpCliData[i].fn(data.data);
  290. this.tmpCliData.splice(i, 1);
  291. break;
  292. }
  293. }
  294. }
  295. /**
  296. * 解析uStr
  297. */
  298. asyMessage(uStr) {
  299. try{
  300. //不支持这个
  301. if(uStr instanceof ArrayBuffer) {
  302. return null;
  303. }
  304. //是否分割线
  305. var isEof = false;
  306. if(uStr.length >= 4) {
  307. //\r\n\r\n
  308. if(uStr[uStr.length - 1] == "\n"
  309. && uStr[uStr.length - 2] == "\r"
  310. && uStr[uStr.length - 3] == "\n"
  311. && uStr[uStr.length - 4] == "\r"
  312. ) {
  313. isEof = true;
  314. }
  315. }
  316. //获取全部数据
  317. if (isEof) {
  318. var unAr = [],unArStr = "";
  319. //累加之前数据分包
  320. for (var i in this.tmpData) {
  321. unAr.push(this.tmpData[i]);
  322. }
  323. unArStr = unAr.join('');
  324. unArStr += uStr;
  325. this.tmpData = [];
  326. if(unArStr == "") return null;
  327. var AES = new CryptoJS.AES(this.opts.key);
  328. var data = AES.decrypt(unArStr.trim());
  329. if(data == "") return null;
  330. //console.log(data);
  331. return JSON.parse(data);
  332. } else {
  333. this.tmpData.push(uStr);
  334. }
  335. } catch(err) {
  336. console.log(err);
  337. return null;
  338. }
  339. }
  340. /**
  341. * 格式化转化
  342. */
  343. Uint8ArrayToString(fileData) {
  344. var dataString = "";
  345. for (var i = 0; i < fileData.length; i++) {
  346. dataString += String.fromCharCode(fileData[i]);
  347. }
  348. return dataString
  349. }
  350. createMsgId(){
  351. this.index ++;
  352. return "web" + this.deveicId + new Date().getTime() + this.index;
  353. }
  354. /**
  355. * 配置数据默认匹配
  356. * $a 默认数据比如:[]
  357. * $b 现在有
  358. */
  359. extend($a, $b) {
  360. let $r = [];
  361. //先遍历$b数据
  362. for (var i in $b) {
  363. $r[i] = $b[i];
  364. }
  365. //遍历默认数据
  366. for (var i in $a) {
  367. if ($r[i] == null) $r[i] = $a[i];
  368. }
  369. return $r;
  370. }
  371. }
  372. /**
  373. * websokcet
  374. * @param options
  375. * @returns {websocket}
  376. */
  377. class wxSocket {
  378. readyState = 0;
  379. socket = null;
  380. opts = {
  381. wsUrl: "",
  382. onOpen:()=>{},
  383. onMessage:()=>{},
  384. onError:()=>{},
  385. onClose:()=>{}
  386. };
  387. constructor(opt) {
  388. this.opts = this.extend(this.opts,opt);
  389. this.onInit();
  390. }
  391. onInit(){
  392. console.log('发起链接');
  393. console.log(this.opts.wsUrl);
  394. this.socket = uni.connectSocket({
  395. url:this.opts.wsUrl,
  396. complete:(res)=>{}
  397. });
  398. if(this.socket == null ){
  399. setTimeout(()=>{
  400. this.onInit();
  401. },1000);
  402. return;
  403. } else {
  404. //监听返回
  405. this.socket.onMessage(onMessage => { this.onMessage(onMessage);});
  406. this.socket.onOpen(res => { this.onOpen(res); });
  407. this.socket.onError(res => {this.onError(res);});
  408. this.socket.onClose(res => {this.onClose(res);});
  409. }
  410. }
  411. send(data) {
  412. this.socket.send({ data : data.data});
  413. }
  414. onOpen(event){
  415. this.bOpen = true;
  416. if(this.opts.onOpen){
  417. this.readyState= 1;
  418. this.opts.onOpen(event);
  419. }
  420. }
  421. /**
  422. *
  423. * @param msg
  424. */
  425. onSend(msg){
  426. if(this.opts.onSend){
  427. this.opts.onSend(msg);
  428. }
  429. this.socket.send(msg);
  430. }
  431. /**
  432. *
  433. * @param msg
  434. */
  435. onMessage(msg){
  436. if(this.opts.onMessage){
  437. this.opts.onMessage(msg.data);
  438. }
  439. }
  440. /**
  441. *
  442. * @param event
  443. */
  444. onError(event){
  445. console.log(event);
  446. if(this.opts.onError){
  447. this.readyState = 3;
  448. this.opts.onError(event);
  449. }
  450. }
  451. /**
  452. *
  453. * @param event
  454. */
  455. onClose(event){
  456. if(this.opts.onClose){
  457. this.readyState = 3;
  458. this.opts.onClose(event);
  459. }
  460. if(this.socket.close() != null){
  461. this.socket = null;
  462. }
  463. }
  464. extend($a, $b){
  465. 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;
  466. }
  467. }
  468. export default WebSokcet