123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502 |
- // +----------------------------------------------------------------------
- // | 桌子工作室 [webSokcet] V0.12015014 Released
- // | 上行数据 clinet 下行数据 service
- // +----------------------------------------------------------------------
- // | Copyright (c) 2018-2019 ,MrTable All rights reserved.
- // +----------------------------------------------------------------------
- // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
- // +----------------------------------------------------------------------
- // | Author: Mr Table <admin@hjf.pw>
- // +----------------------------------------------------------------------
- import CryptoJS from "../vendor/CryptoJS.js";
- import { Base64 } from '../vendor/base64.js';
- import Message from "./Message.js";
- class WebSokcet {
- index = 0;
- //scoket
- socketTask = null;
- //事件返回
- eventCall = null;
- //是否已连接
- socketOpen = false;
- //定时器
- //心跳
- timerId = 0;
- //重发包
- timerId2 = 0;
- //是否在重连中
- isReconnect = false;
- //临时获取数据
- tmpData = [];
- //临时提交数据包[上行数据]
- tmpCliData = [];
- //临时提交数据包[下行数据]
- tmpSerData = [];
- //设备标识符
- deveicId = 0;
- //重试次数
- retryCount = 5;
- isClose = false;
- opts = {};
- constructor(opt) {
- let option = {wsUrl:""};
- this.opts = this.extend(option,opt);
- }
- /**
- * 连接socket
- */
- connect() {
- var that = this;
- this.isClose = false;
- this.socketTask = new wxSocket({
- wsUrl: this.opts.wsUrl,
- //打开
- onOpen:(res => {
- console.log("webSokcet连接成功");
- that.socketOpen = true;
- if (that.eventCall != null) that.eventCall('onOpen', '');
- //心跳包
- that.heartBeat();
- }),
- //获取消息
- onMessage:(onMessage) => {
- var aData = that.asyMessage(onMessage);
- if (aData == null) return;
- if (aData == '') return;
- console.log("接受到消息:" + JSON.stringify(aData));
- //确认帧【客户端主包】
- if (aData.msgType == 2) {
- that.ackFrame(aData);
- return;
- }
-
- //检查重复包帧【服务端主包】
- if (that.checkFrame(aData)) {
- if (that.eventCall != null) that.eventCall('onSendSuccess', aData);
- return;
- }
- that.tmpSerData.push({ time: new Date().getTime(),data: aData, msgId: aData.msgId});
- aData.isReSend = true;
- if(aData.isAsk) {
- let obj = new Message();
- obj.code = aData.code;
- obj.msgType = 2;
- obj.askId = aData.msgId;
- obj.data = that.eventCall == null ? "" : that.eventCall('onMessage', aData);
- this.send(obj.getData(),false);
- } else {
- if (that.eventCall != null) that.eventCall('onMessage', aData);
- }
- },
- //获取错误信息
- onError:res=>{
- console.log(res);
- that.socketOpen = false;
- if (res.errMsg != 'exceed max task count'){
- if (that.eventCall != null) that.eventCall('onError', res.errMsg);
- if(!this.isClose) that.reConnon();
- } else {
- if (that.eventCall != null) that.eventCall('onStop', res.errMsg);
- }
- },
- onClose:onClose => {
- console.log("webSokcet已关闭");
- that.socketOpen = false;
- if (that.eventCall != null) that.eventCall('onClose', '');
- this.socketTask.socket.close();
- if(!this.isClose) that.reConnon();
- }
- });
- }
- /**
- * 设置事件
- */
- setBackCall(call) {
- this.eventCall = call;
- }
-
- ttClose(){
- clearInterval(this.timerId);
- clearInterval(this.timerId2);
- this.isClose = true;
- if(this.socketTask != null)
- this.socketTask.socket.close();
- }
- /**
- * 设置生成密钥
- * @param key
- */
- setKey(key) {
- this.opts.key = key;
- }
- /**
- * 发送数据
- * @param data 数据
- * fn
- * error
- * @returns {boolean}
- *
- */
- send(data,fn = null,error = null) {
- if (!this.socketOpen) { return null; }
- //发送数据
- try {
-
- //生成消息[分配设备ID]
- if (data.msgId == "") data.msgId = this.createMsgId();
- //解析加密数据
- console.log("发送数据:" + JSON.stringify(data.getData()));
- var AES = new CryptoJS.AES(this.opts.key);
- var jsonStr = AES.encrypt(JSON.stringify(data.getData()));
- //发送数据到服务器
- this.socketTask.send({data:jsonStr});
- //确认证就不存到缓存
- if (!data.ask) return null;
- //是否缓存存在
- var msgObj = this.findCliMsgId(data.msgId);
- //记录发送数据
- if (msgObj == null){
- this.tmpCliData.push({
- 'msgId' : data.msgId,//消息ID
- 'data' : data,
- 'count' : 1,//尝试次数
- 'time' : new Date().getTime(),//最红发送时间
- 'code' : 0,
- 'fn' : fn,
- 'error' : error
- });
- } else {
- msgObj['count']++;
- msgObj['time'] = new Date().getTime();
- }
- return data.msgId;
- } catch (e) {
- console.log(e.message);
- return null;
- }
- }
-
- /**
- * 掉线从连接
- */
- reConnon() {
- clearInterval(this.timerId);
- clearInterval(this.timerId2);
- var time = new Date().getTime();
-
- for (var i in this.tmpSerData) {
- var d = this.tmpSerData[i];
- if (time - d.time > 10 * 1000){
- this.tmpSerData.splice(i, 1);
- if (this.eventCall != null) this.eventCall('onSendError', d.data);
- }
- }
- setTimeout(function () {
- if (this.socketTask.readyState == 3) {
- console.log('webSokcet重连接');
- this.connect(this.token);
- }
- }.bind(this), 2000);
- }
- /**
- * 心跳包
- */
- heartBeat() {
- this.timerId = setInterval(function () {
- if (this.socketTask.readyState == 1) {
- this.socketTask.send({ data: '01'});
- if (this.eventCall != null) this.eventCall('onHeartBeat', {});
- }
- }.bind(this), 10 * 1000);
-
- //重发包
- this.timerId2 = setInterval(function () {
- if (this.socketTask.readyState == 1) {
- //重发机制
- this.reSend();
- //清理下行包
- this.clerSerData();
- }
- }.bind(this), 5 * 1000);
-
- return this;
- }
- /**
- * 数据重发
- */
- reSend(){
- var time = new Date().getTime();
- for (var i in this.tmpCliData) {
- var d = this.tmpCliData[i];
- //重发
- if(d.count < this.retryCount && time - d.time> 5000) {
- d.time = time;
- if (this.eventCall != null) this.eventCall('onReSend', d.data,d.count);
- this.send(d.data,false,null,null);
- continue;
- }
- if(d.count >= this.retryCount) {
- //发送失败
- if (this.eventCall != null) this.eventCall('onSendError', d.data);
- if(d.error != null) d.error();
- this.tmpCliData.splice(i, 1);
- }
- }
- }
- /**
- * 清理下行数据包[超过30秒]
- */
- clerSerData(){
- var time = new Date().getTime();
- for (var i in this.tmpSerData) {
- var d = this.tmpSerData[i];
- if (time - d.time > 30 * 1000){
- this.tmpSerData.splice(i, 1);
- }
- }
- }
- /**
- * 查找消息位置[上行数据]
- */
- findCliMsgId(msgId){
- for (var i = 0; i < this.tmpCliData.length;i++){
- if (this.tmpCliData[i].msgId == msgId) return this.tmpCliData[i];
- }
- return null;
- }
-
-
- /**
- * 重复包检测【服务端主包】【服务端重发消息(重复包拦截)】
- */
- checkFrame(data){
- // console.log(this.tmpSerData);
- for(var i in this.tmpSerData) {
- if(this.tmpSerData[i].data.msgId == data.msgId) {
- let sendAr = this.tmpSerData[i].data;
- if(sendAr.isAsk) {
- let obj = new Message();
- obj.code = sendAr.code;
- obj.msgType = 2;
- obj.askId = sendAr.msgId;
- obj.data = sendAr.data;
- this.send(obj.getData(),false);
- return true;
- }
- }
- }
- return false;
- }
- /**
- *
- * 确认帧【客户端主包】【取消客户端重发消息】
- *
- */
- ackFrame(data) {
- for (var i = 0; i < this.tmpCliData.length; i++) {
- if (this.tmpCliData[i].msgId == data.askId){
- if(this.tmpCliData[i].fn !== null) this.tmpCliData[i].fn(data.data);
- this.tmpCliData.splice(i, 1);
- break;
- }
- }
- }
- /**
- * 解析uStr
- */
- asyMessage(uStr) {
- try{
- //不支持这个
- if(uStr instanceof ArrayBuffer) {
- return null;
- }
- //是否分割线
- var isEof = false;
- if(uStr.length >= 4) {
- //\r\n\r\n
- if(uStr[uStr.length - 1] == "\n"
- && uStr[uStr.length - 2] == "\r"
- && uStr[uStr.length - 3] == "\n"
- && uStr[uStr.length - 4] == "\r"
- ) {
- isEof = true;
- }
- }
- //获取全部数据
- if (isEof) {
- var unAr = [],unArStr = "";
- //累加之前数据分包
- for (var i in this.tmpData) {
- unAr.push(this.tmpData[i]);
- }
- unArStr = unAr.join('');
- unArStr += uStr;
- this.tmpData = [];
- if(unArStr == "") return null;
- var AES = new CryptoJS.AES(this.opts.key);
- var data = AES.decrypt(unArStr.trim());
- if(data == "") return null;
- //console.log(data);
- return JSON.parse(data);
- } else {
- this.tmpData.push(uStr);
- }
- } catch(err) {
- console.log(err);
- return null;
- }
- }
- /**
- * 格式化转化
- */
- Uint8ArrayToString(fileData) {
- var dataString = "";
- for (var i = 0; i < fileData.length; i++) {
- dataString += String.fromCharCode(fileData[i]);
- }
- return dataString
- }
- createMsgId(){
- this.index ++;
- return "web" + this.deveicId + new Date().getTime() + this.index;
- }
- /**
- * 配置数据默认匹配
- * $a 默认数据比如:[]
- * $b 现在有
- */
- extend($a, $b) {
- let $r = [];
- //先遍历$b数据
- for (var i in $b) {
- $r[i] = $b[i];
- }
- //遍历默认数据
- for (var i in $a) {
- if ($r[i] == null) $r[i] = $a[i];
- }
- return $r;
- }
- }
- /**
- * websokcet
- * @param options
- * @returns {websocket}
- */
- class wxSocket {
- readyState = 0;
- socket = null;
- opts = {
- wsUrl: "",
- onOpen:()=>{},
- onMessage:()=>{},
- onError:()=>{},
- onClose:()=>{}
- };
- constructor(opt) {
- this.opts = this.extend(this.opts,opt);
- this.onInit();
- }
- onInit(){
- console.log('发起链接');
- console.log(this.opts.wsUrl);
- this.socket = uni.connectSocket({
- url:this.opts.wsUrl,
- complete:(res)=>{}
-
- });
-
- if(this.socket == null ){
- setTimeout(()=>{
- this.onInit();
- },1000);
- return;
- } else {
-
- //监听返回
- this.socket.onMessage(onMessage => { this.onMessage(onMessage);});
- this.socket.onOpen(res => { this.onOpen(res); });
- this.socket.onError(res => {this.onError(res);});
- this.socket.onClose(res => {this.onClose(res);});
- }
-
- }
- send(data) {
- this.socket.send({ data : data.data});
- }
- onOpen(event){
- this.bOpen = true;
- if(this.opts.onOpen){
- this.readyState= 1;
- this.opts.onOpen(event);
- }
- }
- /**
- *
- * @param msg
- */
- onSend(msg){
- if(this.opts.onSend){
- this.opts.onSend(msg);
- }
- this.socket.send(msg);
- }
- /**
- *
- * @param msg
- */
- onMessage(msg){
- if(this.opts.onMessage){
- this.opts.onMessage(msg.data);
- }
- }
- /**
- *
- * @param event
- */
- onError(event){
- console.log(event);
- if(this.opts.onError){
- this.readyState = 3;
- this.opts.onError(event);
- }
- }
- /**
- *
- * @param event
- */
- onClose(event){
- if(this.opts.onClose){
- this.readyState = 3;
- this.opts.onClose(event);
- }
- if(this.socket.close() != null){
- this.socket = null;
- }
- }
- extend($a, $b){
- 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;
- }
- }
- export default WebSokcet
|