北斗短报文通信服务平台
This commit is contained in:
9
app/middleware/packageBuild/buildXFType100.js
Normal file
9
app/middleware/packageBuild/buildXFType100.js
Normal file
@@ -0,0 +1,9 @@
|
||||
// 构造集团客户认证请求信息的数据部分
|
||||
// 将token中的每一位字符转为ascii码后再转为十六进制字符串,最后重新拼接起来
|
||||
module.exports = (token) => {
|
||||
let code = '';
|
||||
for (let i = 0; i < token.length; i++) {
|
||||
code = code + token.charCodeAt(i).toString(16);
|
||||
}
|
||||
return code;
|
||||
};
|
||||
26
app/middleware/packageBuild/packageBuild.js
Normal file
26
app/middleware/packageBuild/packageBuild.js
Normal file
@@ -0,0 +1,26 @@
|
||||
// 构造发送包,传入参数nowData和resendData
|
||||
// nowData为当前数据段,resendData为重发数据段
|
||||
// nowData和resendData都为数组,数组元素的内容为:信息类型编号 + 信息内容长度 + 信息内容
|
||||
module.exports = (app, nowData, resendData) => {
|
||||
const utils = app.middleware.utils;
|
||||
utils.intrinsic.packageNumber++;
|
||||
let now = new Date();
|
||||
let sendTime = utils.packageItem(2, now.getFullYear()) +
|
||||
utils.packageItem(1, now.getMonth() + 1) +
|
||||
utils.packageItem(1, now.getDate());
|
||||
let packageMsg = utils.packageItem(2, app.config.socketClient.id) +
|
||||
utils.packageItem(2, app.config.socketClient.destination) +
|
||||
utils.packageItem(4, utils.intrinsic.packageNumber) +
|
||||
utils.packageItem(1, nowData.length) +
|
||||
utils.packageItem(2, utils.arrItemLength(nowData)) +
|
||||
(resendData ? '01' : '00') +
|
||||
(resendData ? utils.packageItem(1, resendData.length) : '00') +
|
||||
(resendData ? utils.packageItem(2, utils.arrItemLength(resendData)) : '0000') +
|
||||
sendTime +
|
||||
utils.arrTotalItem(nowData) +
|
||||
(resendData ? sendTime : '') +
|
||||
(resendData ? utils.arrTotalItem(resendData) : '') +
|
||||
utils.intrinsic.separateIdentifiers;
|
||||
const buffer = Buffer.from(packageMsg, 'hex');
|
||||
return buffer;
|
||||
};
|
||||
32
app/middleware/parseDataPackage/parseDataPackage.js
Normal file
32
app/middleware/parseDataPackage/parseDataPackage.js
Normal file
@@ -0,0 +1,32 @@
|
||||
// 解析数据包
|
||||
module.exports = (middleware, data) => {
|
||||
const utils = middleware.utils;
|
||||
const shunt = middleware.shunt;
|
||||
let msg;
|
||||
if (data == 'e5bf83e8b7b3') {
|
||||
msg = 'e5bf83e8b7b37878787888888888';
|
||||
} else {
|
||||
let regex = /..?/g,
|
||||
arr = data.match(regex),
|
||||
baseArr = utils.getArr(arr, 0, 14),
|
||||
baseObj = {
|
||||
infoSource: { label: "信源", data: parseInt(baseArr[0] + baseArr[1], 16) },
|
||||
destination: { label: "信宿", data: parseInt(baseArr[2] + baseArr[3], 16) },
|
||||
packageNumber: { label: "包序号", data: parseInt(baseArr[4] + baseArr[5] + baseArr[6] + baseArr[7], 16) },
|
||||
dataItem: { label: "当前数据项", data: parseInt(baseArr[8], 16) },
|
||||
dataLength: { label: "当前数据段总长度", data: parseInt(baseArr[9] + baseArr[10], 16) },
|
||||
resendFlag: { label: "重发标志", data: parseInt(baseArr[11], 16) },
|
||||
resendItem: { label: "重发数据项", data: parseInt(baseArr[12], 16) },
|
||||
resendLength: { label: "重发数据段总长度", data: parseInt(baseArr[13] + baseArr[14], 16) },
|
||||
dataContent: { label: "数据段", }
|
||||
};
|
||||
if (baseObj.dataItem.data !== 0) {
|
||||
shunt.selectXFType(middleware, 'now', baseObj, arr);
|
||||
}
|
||||
if (baseObj.resendFlag.data !== 0) {
|
||||
shunt.selectXFType(middleware, 'resend', baseObj, arr);
|
||||
}
|
||||
msg = baseObj;
|
||||
}
|
||||
return msg;
|
||||
};
|
||||
24
app/middleware/parseDataPackage/parseMsg.js
Normal file
24
app/middleware/parseDataPackage/parseMsg.js
Normal file
@@ -0,0 +1,24 @@
|
||||
// 解析通信服务的通信数据
|
||||
module.exports = (type, msg) => {
|
||||
let regex, arr, result = '';
|
||||
if (type == '0000') {
|
||||
// 0000, 汉字编码,按14bit区位编码,前7位为区码,后7位为位码
|
||||
// 区号和位号分别加上160,再分别转换成十六进制数,就成为四位的十六进制GB2312国家标准编码
|
||||
regex = /.......?/g;
|
||||
arr = msg.match(regex);
|
||||
for (let t = 0; t < arr.length; t += 2) {
|
||||
result = result + (parseInt(arr[t], 2) + 160).toString(16) + (parseInt(arr[t + 1], 2) + 160).toString(16);
|
||||
}
|
||||
} else if (type == '0001') {
|
||||
// 0001,BCD码,按4bit编码,将每4bit二进制转换为一个十进制数,再拼接成字符串
|
||||
regex = /....?/g;
|
||||
arr = msg.match(regex);
|
||||
arr.forEach(element => {
|
||||
result = result + parseInt(element, 2);
|
||||
});
|
||||
} else {
|
||||
// 保留,二进制转为十进制
|
||||
result = parseInt(msg, 2);
|
||||
}
|
||||
return result;
|
||||
};
|
||||
125
app/middleware/parseDataPackage/parseXFType004.js
Normal file
125
app/middleware/parseDataPackage/parseXFType004.js
Normal file
@@ -0,0 +1,125 @@
|
||||
// 解析通信服务信息
|
||||
module.exports = (middleware, dataArr, objCtx) => {
|
||||
const utils = middleware.utils;
|
||||
const parseDataPackage = middleware.parseDataPackage;
|
||||
let informationFieldString = utils.hexToBinary(utils.getString(dataArr, 0, dataArr.length - 1));
|
||||
objCtx.msgContent = {
|
||||
originalMsg: utils.getString(dataArr, 0, dataArr.length - 1),
|
||||
outboundTypeIdentification: { label: "出站类型标识", data: parseInt(informationFieldString.slice(0, 8), 2) },
|
||||
receiverType: { label: "收方类型", data: parseInt(informationFieldString.slice(8, 16), 2) },
|
||||
receiverAddress: { label: "收方地址", data: parseInt(informationFieldString.slice(parseInt(informationFieldString.slice(8, 16), 2) == 0 ? 40 : 16, 64), 2) },
|
||||
msgLength: { label: "信息长度", data: parseInt(informationFieldString.slice(64, 80), 2) },
|
||||
msgCategory: {
|
||||
label: "信息类别",
|
||||
retain: { label: "保留", data: informationFieldString.slice(80, 81) },
|
||||
outboundFrameCategory: { label: "出站帧类别", data: informationFieldString.slice(81, 83) },
|
||||
typeOfCommunication: { label: "通信类型", },
|
||||
},
|
||||
};
|
||||
informationFieldString = informationFieldString.slice(83, objCtx.msgContent.msgLength.data + 80);
|
||||
switch (informationFieldString.slice(0, 2)) {
|
||||
case '00':
|
||||
objCtx.msgContent.msgCategory.typeOfCommunication.shortMsg = { label: "短报文", data: informationFieldString.slice(0, 2) };
|
||||
objCtx.msgContent.msgCategory.typeOfCommunication.senderType = { label: "发方类型", data: informationFieldString.slice(2, 3) };
|
||||
objCtx.msgContent.msgCategory.typeOfCommunication.packetID = {
|
||||
label: "报文标识",
|
||||
instantMessages: { label: "是否为即时报文出站", data: informationFieldString.slice(3, 4) },
|
||||
acknowledgmentOfReceipt: { label: "是否需要收方用户自动回执", data: informationFieldString.slice(4, 5) },
|
||||
};
|
||||
break;
|
||||
case '01':
|
||||
if (informationFieldString.slice(2, 3) == '0') {
|
||||
objCtx.msgContent.msgCategory.typeOfCommunication.onDemandCommunications = { label: "点播通信", data: informationFieldString.slice(0, 3) };
|
||||
objCtx.msgContent.msgCategory.typeOfCommunication.senderType = { label: "发方类型", data: informationFieldString.slice(3, 4) };
|
||||
objCtx.msgContent.msgCategory.typeOfCommunication.realTimeIdentification = { label: "实时标识", data: informationFieldString.slice(4, 5) };
|
||||
} else {
|
||||
objCtx.msgContent.msgCategory.typeOfCommunication.retain = { label: "保留", data: informationFieldString.slice(0, 5) };
|
||||
}
|
||||
break;
|
||||
case '10':
|
||||
if (informationFieldString.slice(0, 5) == '10000') {
|
||||
objCtx.msgContent.msgCategory.typeOfCommunication.receiptQueryResults = { label: "回执查询结果", data: informationFieldString.slice(0, 5) };
|
||||
} else {
|
||||
objCtx.msgContent.msgCategory.typeOfCommunication.retain = { label: "保留", data: informationFieldString.slice(0, 5) };
|
||||
}
|
||||
break;
|
||||
case '11':
|
||||
if (informationFieldString.slice(0, 5) == '11000') {
|
||||
objCtx.msgContent.msgCategory.typeOfCommunication.multicastCommunication = { label: "组播通信", data: informationFieldString.slice(0, 5) };
|
||||
} else if (informationFieldString.slice(0, 5) == '11010') {
|
||||
objCtx.msgContent.msgCategory.typeOfCommunication.broadcastCommunications = { label: "通播通信", data: informationFieldString.slice(0, 5) };
|
||||
} else {
|
||||
objCtx.msgContent.msgCategory.typeOfCommunication.retain = { label: "保留", data: informationFieldString.slice(0, 5) };
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
};
|
||||
if (informationFieldString.slice(0, 2) == '00' || informationFieldString.slice(0, 3) == '010' || informationFieldString.slice(0, 5) == '11000' || informationFieldString.slice(0, 5) == '11010') {
|
||||
let typeMsg = informationFieldString.slice(0, 5);
|
||||
objCtx.msgContent.outboundMsg = {
|
||||
label: "出站信息段",
|
||||
firstFrame: { label: "是否首帧", data: informationFieldString.slice(5, 6) },
|
||||
resumeFrame: { label: "有无续帧", data: informationFieldString.slice(6, 7) },
|
||||
senderAddress: { label: "发方地址", },
|
||||
};
|
||||
if (typeMsg.slice(0, 3) == '001' || typeMsg.slice(0, 4) == '0101') {
|
||||
objCtx.msgContent.outboundMsg.senderAddress.data = parseInt(informationFieldString.slice(7, 55), 2);
|
||||
informationFieldString = informationFieldString.slice(55, informationFieldString.length);
|
||||
} else {
|
||||
objCtx.msgContent.outboundMsg.senderAddress.data = parseInt(informationFieldString.slice(7, 31), 2);
|
||||
informationFieldString = informationFieldString.slice(31, informationFieldString.length);
|
||||
};
|
||||
objCtx.msgContent.outboundMsg.sendMsgTime = {
|
||||
label: "发信时间",
|
||||
weeklyInstructions: { label: "周指示", data: parseInt(informationFieldString.slice(0, 1), 2) },
|
||||
intraWeekSeconds: { label: "周内秒", data: parseInt(informationFieldString.slice(1, 21), 2) },
|
||||
};
|
||||
if (typeMsg.slice(0, 2) == '00' && objCtx.msgContent.receiverAddress.data == '通播地址') {
|
||||
objCtx.msgContent.outboundMsg.ancillaryInformation = {
|
||||
label: "辅助信息",
|
||||
msgNumber: { label: "信息编号", data: parseInt(informationFieldString.slice(21, 29), 2) },
|
||||
};
|
||||
informationFieldString = informationFieldString.slice(29, informationFieldString.length);
|
||||
} else if (typeMsg.slice(0, 2) == '00' && objCtx.msgContent.receiverAddress.data == '组播地址') {
|
||||
objCtx.msgContent.outboundMsg.ancillaryInformation = {
|
||||
label: "辅助信息",
|
||||
totalGroupMembers: { label: "编组组员总数", data: parseInt(informationFieldString.slice(21, 28), 2) },
|
||||
onlineGroupMembers: { label: "在线组员数", data: parseInt(informationFieldString.slice(28, 35), 2) },
|
||||
msgNumber: { label: "信息编号", data: parseInt(informationFieldString.slice(35, 43), 2) },
|
||||
};
|
||||
informationFieldString = informationFieldString.slice(43, informationFieldString.length);
|
||||
} else if (typeMsg.slice(0, 5) == '11000') {
|
||||
objCtx.msgContent.outboundMsg.multicastAncillaryInformation = {
|
||||
label: "组播辅助信息",
|
||||
totalGroupMembers: { label: "编组组员总数", data: parseInt(informationFieldString.slice(21, 28), 2) },
|
||||
onlineGroupMembers: { label: "在线组员数", data: parseInt(informationFieldString.slice(28, 35), 2) },
|
||||
};
|
||||
informationFieldString = informationFieldString.slice(35, informationFieldString.length);
|
||||
} else {
|
||||
informationFieldString = informationFieldString.slice(21, informationFieldString.length);
|
||||
}
|
||||
objCtx.msgContent.outboundMsg.encodingCategory = { label: "编码类别", data: informationFieldString.slice(0, 4) }
|
||||
objCtx.msgContent.outboundMsg.msgData = { label: "通信数据", data: parseDataPackage.parseMsg(objCtx.msgContent.outboundMsg.encodingCategory.data, informationFieldString.slice(4, informationFieldString.length)) }
|
||||
} else if (informationFieldString.slice(0, 5) == '10000') {
|
||||
objCtx.msgContent.receiptQueryResults = {
|
||||
label: "回执查询结果",
|
||||
communicationRecipientAddress: { label: "通信收方地址", data: parseInt(informationFieldString.slice(5, 29), 2), },
|
||||
receiptsNumber: { label: "回执数", data: parseInt(informationFieldString.slice(29, 32), 2), },
|
||||
}
|
||||
if (objCtx.msgContent.receiptQueryResults.receiptsNumber.data !== 0) {
|
||||
informationFieldString = informationFieldString.slice(32, informationFieldString.length);
|
||||
for (let k = 0; k < objCtx.msgContent.receiptQueryResults.receiptsNumber.data; k++) {
|
||||
let communicationTime = "communicationTime" + (k + 1);
|
||||
objCtx.msgContent.receiptQueryResults[communicationTime] = {
|
||||
label: "通信发信时间" + (k + 1),
|
||||
weeklyInstructions: { label: "周指示", data: parseInt(informationFieldString.slice(0, 1), 2) },
|
||||
intraWeekSeconds: { label: "周内秒", data: parseInt(informationFieldString.slice(1, 21), 2) },
|
||||
}
|
||||
informationFieldString = informationFieldString.slice(21, informationFieldString.length);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
objCtx.msgContent.retain = { label: "保留", data: informationFieldString.slice(5, informationFieldString.length), }
|
||||
};
|
||||
};
|
||||
52
app/middleware/parseDataPackage/parseXFType005.js
Normal file
52
app/middleware/parseDataPackage/parseXFType005.js
Normal file
@@ -0,0 +1,52 @@
|
||||
// 解析广播服务信息
|
||||
module.exports = (middleware, dataArr, objCtx) => {
|
||||
const utils = middleware.utils;
|
||||
let fixedFieldString = utils.hexToBinary(utils.getString(dataArr, 0, 15).slice(0, 16)),
|
||||
informationFieldString = utils.hexToBinary(utils.getString(dataArr, 17, objCtx.contentLength.data + 3));
|
||||
objCtx.msgContent = {
|
||||
fixedField: {
|
||||
label: "固定域",
|
||||
satelliteNumber: { label: "卫星号", data: parseInt(fixedFieldString.slice(0, 6), 2) },
|
||||
beamNumber: { label: "波束号", data: parseInt(fixedFieldString.slice(6, 10), 2) },
|
||||
hyperframeCount: { label: "超帧计数", data: parseInt(fixedFieldString.slice(10, 27), 2) },
|
||||
weeklyCount: { label: "周计数", data: parseInt(fixedFieldString.slice(27, 40), 2) },
|
||||
frequencyDynamicControl: { label: "频度动态控制", data: parseInt(fixedFieldString.slice(40, 44), 2) },
|
||||
outboundDelayForecast: { label: "出站时延预报", data: parseInt(fixedFieldString.slice(44, 48), 2) },
|
||||
integrityInformation: { label: "完好性信息", data: parseInt(fixedFieldString.slice(48, 50), 2) },
|
||||
reserved1: { label: "保留1", data: parseInt(fixedFieldString.slice(50, 55), 2) },
|
||||
reserved2: { label: "保留2", data: parseInt(fixedFieldString.slice(55, 64), 2) },
|
||||
repeat: { label: "重复" },
|
||||
},
|
||||
msgType: { label: "MsgType", data: parseInt(utils.hexToBinary(dataArr[16]), 2) },
|
||||
informationField: { label: "类别信息域", },
|
||||
}
|
||||
objCtx.msgContent.informationField.satellitesNumber = { label: "本帧电文包括卫星数", data: parseInt(informationFieldString.slice(0, 3), 2) };
|
||||
informationFieldString = informationFieldString.slice(3, informationFieldString.length);
|
||||
if (objCtx.msgContent.informationField.satellitesNumber.data !== 0) {
|
||||
for (let j = 0; j < objCtx.msgContent.informationField.satellitesNumber.data; j++) {
|
||||
let satellitesObj = "satellitesObj" + (j + 1);
|
||||
objCtx.msgContent.informationField[satellitesObj] = {
|
||||
label: "卫星" + (j + 1),
|
||||
PRNNumber: { label: "导航PRN号", data: parseInt(informationFieldString.slice(0, 6), 2) },
|
||||
beamsNumber: { label: "出站波束数量", data: parseInt(informationFieldString.slice(6, 10), 2) },
|
||||
reserved1: { label: "保留1", data: parseInt(informationFieldString.slice(10, 16), 2) },
|
||||
reserved2: { label: "保留2", data: parseInt(informationFieldString.slice(16, 22), 2) },
|
||||
}
|
||||
informationFieldString = informationFieldString.slice(22, informationFieldString.length);
|
||||
if (objCtx.msgContent.informationField[satellitesObj].beamsNumber.data !== 0) {
|
||||
for (let l = 0; l < objCtx.msgContent.informationField[satellitesObj].beamsNumber.data; l++) {
|
||||
let CenterObj = "CenterObj" + (l + 1);
|
||||
objCtx.msgContent.informationField[satellitesObj][CenterObj] = {
|
||||
label: "波束" + (l + 1) + "中心经纬度",
|
||||
longitude: { label: "经度", data: parseInt(informationFieldString.slice(0, 1), 2) == 0 ? parseInt(informationFieldString.slice(1, 9), 2) : '-' + parseInt(informationFieldString.slice(1, 9), 2) },
|
||||
latitude: { label: "纬度", data: parseInt(informationFieldString.slice(9, 10), 2) == 0 ? parseInt(informationFieldString.slice(10, 17), 2) : '-' + parseInt(informationFieldString.slice(10, 17), 2) },
|
||||
}
|
||||
informationFieldString = informationFieldString.slice(17, informationFieldString.length);
|
||||
}
|
||||
}
|
||||
}
|
||||
objCtx.msgContent.informationField.reserved = { label: "保留", data: informationFieldString };
|
||||
} else {
|
||||
objCtx.msgContent.informationField.reserved = { label: "保留", data: informationFieldString };
|
||||
}
|
||||
};
|
||||
16
app/middleware/parseDataPackage/parseXFType099.js
Normal file
16
app/middleware/parseDataPackage/parseXFType099.js
Normal file
@@ -0,0 +1,16 @@
|
||||
// 解析集团客户认证结果信息
|
||||
module.exports = (dataArr, objCtx) => {
|
||||
let authCoed = parseInt(dataArr.pop(), 16);
|
||||
if (authCoed == 1) {
|
||||
let token = '';
|
||||
dataArr.forEach(element => {
|
||||
token = token + String.fromCodePoint(parseInt(element, 16));
|
||||
});
|
||||
objCtx.token = token;
|
||||
objCtx.authStatus = '1';
|
||||
objCtx.resultMsg = '认证成功';
|
||||
} else if (authCoed == 0) {
|
||||
objCtx.authStatus = '0';
|
||||
objCtx.resultMsg = '认证失败';
|
||||
}
|
||||
};
|
||||
50
app/middleware/shunt/selectXFType.js
Normal file
50
app/middleware/shunt/selectXFType.js
Normal file
@@ -0,0 +1,50 @@
|
||||
// 解析服务信息类型
|
||||
module.exports = (middleware, item, baseObj, arr) => {
|
||||
const utils = middleware.utils;
|
||||
const parseDataPackage = middleware.parseDataPackage;
|
||||
let dataCtx = baseObj.dataContent, objName, labelString, dataArr, itemLength, itemType;
|
||||
if (item == 'now') {
|
||||
objName = 'nowData';
|
||||
labelString = '当前';
|
||||
itemLength = baseObj.dataLength.data;
|
||||
dataArr = utils.getArr(arr, 15, 15 + itemLength - 1);
|
||||
itemType = baseObj.dataItem.data;
|
||||
} else if (item == 'resend') {
|
||||
objName = 'resendData';
|
||||
labelString = '重发';
|
||||
itemLength = baseObj.resendLength.data;
|
||||
dataArr = utils.getArr(arr, 15 + baseObj.dataLength.data, 15 + baseObj.dataLength.data + itemLength - 1);
|
||||
itemType = baseObj.resendItem.data;
|
||||
}
|
||||
dataCtx[objName] = {
|
||||
label: labelString + "数据段",
|
||||
timeObj: {
|
||||
year: { label: "年", data: parseInt(dataArr[0] + dataArr[1], 16) },
|
||||
month: { label: "月", data: parseInt(dataArr[2], 16) },
|
||||
day: { label: "日", data: parseInt(dataArr[3], 16) },
|
||||
}
|
||||
}
|
||||
dataArr = utils.getArr(dataArr, 4, itemLength - 1);
|
||||
for (let i = 0; i < itemType; i++) {
|
||||
let contentObj = "contentObj" + (i + 1);
|
||||
dataCtx[objName][contentObj] = {
|
||||
label: labelString + "数据内容" + (i + 1),
|
||||
typeNumber: { label: "信息类型编号", data: parseInt(dataArr[0] + dataArr[1], 16) },
|
||||
contentLength: { label: "信息内容长度", data: parseInt(dataArr[2] + dataArr[3], 16) },
|
||||
}
|
||||
if (dataCtx[objName][contentObj].contentLength.data !== 0) {
|
||||
dataArr = utils.getArr(dataArr, 4, itemLength - 5);
|
||||
switch (dataCtx[objName][contentObj].typeNumber.data) {
|
||||
case 4: parseDataPackage.parseXFType004(middleware, dataArr, dataCtx[objName][contentObj]);
|
||||
break;
|
||||
case 5: parseDataPackage.parseXFType005(middleware, dataArr, dataCtx[objName][contentObj]);
|
||||
break;
|
||||
case 99: parseDataPackage.parseXFType099(dataArr, dataCtx[objName][contentObj]);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
dataArr = utils.getArr(dataArr, dataCtx[objName][contentObj].contentLength.data, itemLength - 1);
|
||||
}
|
||||
};
|
||||
8
app/middleware/shunt/socketEmitter.js
Normal file
8
app/middleware/shunt/socketEmitter.js
Normal file
@@ -0,0 +1,8 @@
|
||||
// socket事件监听器
|
||||
const EventEmitter = require('events');
|
||||
|
||||
const socketEmitter = new EventEmitter();
|
||||
|
||||
module.exports = () => {
|
||||
return socketEmitter;
|
||||
};
|
||||
14
app/middleware/shunt/socketResult.js
Normal file
14
app/middleware/shunt/socketResult.js
Normal file
@@ -0,0 +1,14 @@
|
||||
// 对数据包解析结果做类型判断,并根据不同类型返回不同结果
|
||||
module.exports = (data) => {
|
||||
for (let item in data) {
|
||||
if (data[item].typeNumber) {
|
||||
if (data[item].typeNumber.data == 4) {
|
||||
return { type: 4, data: data[item] };
|
||||
} else if (data[item].typeNumber.data == 5) {
|
||||
return { type: 5, data: data[item] };
|
||||
} else if (data[item].typeNumber.data == 99) {
|
||||
return { type: 99, data: data[item].authStatus };
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
135
app/middleware/socket/socketClient.js
Normal file
135
app/middleware/socket/socketClient.js
Normal file
@@ -0,0 +1,135 @@
|
||||
// socket客户端
|
||||
const net = require('net');
|
||||
|
||||
module.exports = (app) => {
|
||||
const { middleware } = app;
|
||||
const packageBuild = middleware.packageBuild;
|
||||
const utils = middleware.utils;
|
||||
const parseDataPackage = middleware.parseDataPackage;
|
||||
const shunt = middleware.shunt;
|
||||
|
||||
const client = new net.Socket();
|
||||
|
||||
let times, connectSwitch = true, reconnectSwitch = false;
|
||||
|
||||
setTimeout(() => {
|
||||
reconnectSwitch = true;
|
||||
}, 66000);
|
||||
|
||||
const createClient = () => {
|
||||
if(connectSwitch) {
|
||||
connectSwitch = false;
|
||||
client.connect(app.config.socketClient.port, app.config.socketClient.ip, () => {
|
||||
console.log(`socket: 连接到服务端: ${app.config.socketClient.ip + ':' + app.config.socketClient.port}`);
|
||||
client.setKeepAlive(true, 60000);
|
||||
reconnectSwitch = true;
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
createClient();
|
||||
|
||||
// 重连服务端
|
||||
const reconnect = () => {
|
||||
if (reconnectSwitch) {
|
||||
reconnectSwitch = false;
|
||||
setTimeout(() => {
|
||||
connectSwitch = true;
|
||||
createClient();
|
||||
}, 66000);
|
||||
}
|
||||
};
|
||||
|
||||
client.on('connectTimeout', () => {
|
||||
reconnect();
|
||||
});
|
||||
|
||||
client.on('timeout', () => {
|
||||
reconnect();
|
||||
});
|
||||
|
||||
client.on('end', () => {
|
||||
reconnect();
|
||||
});
|
||||
|
||||
client.on('close', () => {
|
||||
reconnect();
|
||||
});
|
||||
|
||||
client.on('error', (err) => {
|
||||
utils.log('../../../socketLog', err);
|
||||
reconnect();
|
||||
});
|
||||
|
||||
client.on('connect', () => {
|
||||
// 连接成功后的逻辑...
|
||||
client.write(packageBuild.packageBuild(app, [utils.packageItem(2, 100) + utils.packageItem(2, packageBuild.buildXFType100(app.config.socketClient.token).length / 2) + packageBuild.buildXFType100(app.config.socketClient.token)]));
|
||||
});
|
||||
|
||||
client.on('data', async (data) => {
|
||||
// 在这里可以处理从服务器接收到的数据
|
||||
// utils.log('../../../socketLog', data);
|
||||
let msg = parseDataPackage.parseDataPackage(middleware, data.toString('hex').slice(0, data.toString('hex').length - 16));
|
||||
if (msg == utils.intrinsic.heart) {
|
||||
clearTimeout(times);
|
||||
times = setTimeout(() => {
|
||||
client.write(Buffer.from(msg, 'hex'));
|
||||
}, 10000);
|
||||
} else {
|
||||
let nowResult = shunt.socketResult(msg.dataContent.nowData);
|
||||
let resendResult = shunt.socketResult(msg.dataContent.resendData);
|
||||
// 当前消息处理
|
||||
if (nowResult.type == 99) {
|
||||
// token验证处理程序
|
||||
if (nowResult.data == '1') {
|
||||
client.write(Buffer.from(utils.intrinsic.heart, 'hex'));
|
||||
} else {
|
||||
reconnect();
|
||||
}
|
||||
} else if (nowResult.type == 4) {
|
||||
const { msgContent } = nowResult.data;
|
||||
const { outboundMsg, receiverAddress, originalMsg } = msgContent;
|
||||
const { senderAddress, msgData, encodingCategory } = outboundMsg;
|
||||
// socket接收消息后触发事件监听器,将消息发送给websocket客户端并存储在数据库中
|
||||
shunt.socketEmitter().emit(senderAddress.data, { encode_type: parseInt(encodingCategory.data), msg_data: msgData.data, created_at: new Date() });
|
||||
await app.curl('http://127.0.0.1:' + app.server.address().port + '/shortMsg', {
|
||||
dataType: 'json',
|
||||
contentType: 'application/x-www-form-urlencoded',
|
||||
method: 'POST',
|
||||
timeout: 3000,
|
||||
data: {
|
||||
card_id: senderAddress.data,
|
||||
receiver_address: receiverAddress.data,
|
||||
original_msg: originalMsg,
|
||||
send_type: 0,
|
||||
encode_type: parseInt(encodingCategory.data),
|
||||
msg_data: msgData.data,
|
||||
created_at: new Date()
|
||||
},
|
||||
});
|
||||
}
|
||||
// 重发消息处理
|
||||
if (resendResult && resendResult.type == 4) {
|
||||
const { msgContent } = resendResult.data;
|
||||
const { outboundMsg, receiverAddress } = msgContent;
|
||||
const { senderAddress, msgData, encodingCategory } = outboundMsg;
|
||||
// socket接收消息后触发事件监听器,将消息发送给websocket客户端并存储在数据库中
|
||||
shunt.socketEmitter().emit(senderAddress.data, msgData.data);
|
||||
await app.curl('http://127.0.0.1:' + app.server.address().port + '/shortMsg', {
|
||||
dataType: 'json',
|
||||
contentType: 'application/x-www-form-urlencoded',
|
||||
method: 'POST',
|
||||
timeout: 3000,
|
||||
data: {
|
||||
card_id: senderAddress.data,
|
||||
receiver_address: receiverAddress.data,
|
||||
msg: data.toString(),
|
||||
send_type: 1,
|
||||
encode_type: parseInt(encodingCategory.data),
|
||||
msg_data: msgData.data,
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
8
app/middleware/utils/arrItemLength.js
Normal file
8
app/middleware/utils/arrItemLength.js
Normal file
@@ -0,0 +1,8 @@
|
||||
// 计算数组中十六进制数据的总字节数,并在最终结果中加上时间信息的4字节长度
|
||||
module.exports = (arr) => {
|
||||
let length = 0;
|
||||
arr.forEach(element => {
|
||||
length = length + (element.length / 2);
|
||||
});
|
||||
return length + 4;
|
||||
};
|
||||
8
app/middleware/utils/arrTotalItem.js
Normal file
8
app/middleware/utils/arrTotalItem.js
Normal file
@@ -0,0 +1,8 @@
|
||||
// 将数组中的所有元素按下标顺序拼接成字符串
|
||||
module.exports = (arr) => {
|
||||
let total = '';
|
||||
arr.forEach(element => {
|
||||
total = total + element;
|
||||
});
|
||||
return total;
|
||||
};
|
||||
10
app/middleware/utils/getArr.js
Normal file
10
app/middleware/utils/getArr.js
Normal file
@@ -0,0 +1,10 @@
|
||||
// 截取数组元素,组成新数组并返回
|
||||
module.exports = (arr, start, end) => {
|
||||
let newArr = [];
|
||||
arr.forEach((element, index) => {
|
||||
if (index >= start && index <= end) {
|
||||
newArr.push(element);
|
||||
}
|
||||
});
|
||||
return newArr;
|
||||
};
|
||||
10
app/middleware/utils/getString.js
Normal file
10
app/middleware/utils/getString.js
Normal file
@@ -0,0 +1,10 @@
|
||||
// 截取数组元素,拼接成字符串并返回
|
||||
module.exports = (arr, start, end) => {
|
||||
let newString = '';
|
||||
arr.forEach((element, index) => {
|
||||
if (index >= start && index <= end) {
|
||||
newString = newString + element;
|
||||
}
|
||||
});
|
||||
return newString;
|
||||
};
|
||||
13
app/middleware/utils/getTimes.js
Normal file
13
app/middleware/utils/getTimes.js
Normal file
@@ -0,0 +1,13 @@
|
||||
// 返回时间对象
|
||||
module.exports = () => {
|
||||
let now = new Date(),
|
||||
times = {
|
||||
year: now.getFullYear(),
|
||||
month: now.getMonth() + 1,
|
||||
day: now.getDate(),
|
||||
hour: now.getHours(),
|
||||
minute: now.getMinutes(),
|
||||
second: now.getSeconds()
|
||||
};
|
||||
return times;
|
||||
};
|
||||
15
app/middleware/utils/hexToBinary.js
Normal file
15
app/middleware/utils/hexToBinary.js
Normal file
@@ -0,0 +1,15 @@
|
||||
// 十六进制转二进制
|
||||
module.exports = (hex) => {
|
||||
let hexChars = '0123456789ABCDEF';
|
||||
let binaryString = '';
|
||||
for (let i = 0; i < hex.length; i++) {
|
||||
let hexIndex = hexChars.indexOf(hex[i].toUpperCase());
|
||||
let binaryDigit = hexIndex.toString(2);
|
||||
// 确保每个十六进制数字转换为四位二进制数字
|
||||
while (binaryDigit.length < 4) {
|
||||
binaryDigit = '0' + binaryDigit;
|
||||
}
|
||||
binaryString += binaryDigit;
|
||||
}
|
||||
return binaryString;
|
||||
};
|
||||
8
app/middleware/utils/intrinsic.js
Normal file
8
app/middleware/utils/intrinsic.js
Normal file
@@ -0,0 +1,8 @@
|
||||
module.exports = {
|
||||
// 数据包最后固定十六进制串作为TCP流的分隔识别符
|
||||
separateIdentifiers: '7878787888888888',
|
||||
// 心跳检测信息固定格式
|
||||
heart: 'e5bf83e8b7b37878787888888888',
|
||||
// 包序号,从0开始,随程序运行变大
|
||||
packageNumber: 0,
|
||||
};
|
||||
72
app/middleware/utils/log.js
Normal file
72
app/middleware/utils/log.js
Normal file
@@ -0,0 +1,72 @@
|
||||
// 错误日志
|
||||
const fs = require('fs');
|
||||
const os = require('os');
|
||||
const path = require('path');
|
||||
|
||||
const dirCheck = (dirPath) => {
|
||||
// 检查文件夹是否存在
|
||||
fs.access(dirPath, fs.constants.F_OK, (err) => {
|
||||
if (err) {
|
||||
// 文件夹不存在
|
||||
console.log('文件夹不存在,正在创建...');
|
||||
fs.mkdir(dirPath, { recursive: true }, (err) => {
|
||||
if (err) throw err;
|
||||
console.log('文件夹已创建');
|
||||
});
|
||||
} else {
|
||||
// 文件夹存在
|
||||
console.log('文件夹已存在');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = (filePath, msg) => {
|
||||
// 获取时间
|
||||
let now = new Date(),
|
||||
times = {
|
||||
year: now.getFullYear(),
|
||||
month: now.getMonth() + 1,
|
||||
day: now.getDate(),
|
||||
hour: now.getHours(),
|
||||
minute: now.getMinutes(),
|
||||
second: now.getSeconds()
|
||||
};
|
||||
// 获取操作系统类型
|
||||
const type = os.type();
|
||||
console.log(`操作系统类型: ${type}`);
|
||||
filePath = path.join(__dirname, filePath);
|
||||
dirCheck(filePath);
|
||||
const yearPath = filePath + '/' + times.year;
|
||||
dirCheck(yearPath);
|
||||
const monthPath = yearPath + '/' + times.month;
|
||||
dirCheck(monthPath);
|
||||
const dayPath = monthPath + '/' + times.day + '.txt';
|
||||
const logTime = '[' + times.year + '-' + times.month + '-' + times.day + '>>>' + times.hour + ':' + times.minute + ':' + times.second + ']' + '>>>';
|
||||
let crlf;
|
||||
// 判断操作系统类型,设置换行符
|
||||
if (type === 'Windows_NT') {
|
||||
crlf = '\n';
|
||||
} else {
|
||||
crlf = '\r\n';
|
||||
}
|
||||
// 读取文件内容
|
||||
fs.readFile(dayPath, 'utf8', (err, data) => {
|
||||
if (err) {
|
||||
if (err.code === 'ENOENT') {
|
||||
// 文件不存在,直接写入新内容(这里实际上还是使用了覆盖的方式)
|
||||
fs.writeFile(dayPath, logTime + msg + crlf, (err) => {
|
||||
if (err) throw err;
|
||||
console.log('文件已创建并写入新内容');
|
||||
});
|
||||
} else {
|
||||
throw err;
|
||||
}
|
||||
} else {
|
||||
// 文件存在,追加新内容
|
||||
fs.appendFile(dayPath, logTime + msg + crlf, (err) => {
|
||||
if (err) throw err;
|
||||
console.log('新内容已追加到文件');
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
8
app/middleware/utils/packageItem.js
Normal file
8
app/middleware/utils/packageItem.js
Normal file
@@ -0,0 +1,8 @@
|
||||
// 判断十六进制数据的长度,若长度不满足条件,则在左侧补0,直至长度满足条件
|
||||
module.exports = (length, data) => {
|
||||
let item = data.toString(16);
|
||||
for (let i = 0; i < (length * 2) - data.toString(16).length; i++) {
|
||||
item = '0' + item;
|
||||
}
|
||||
return item;
|
||||
};
|
||||
47
app/middleware/webSocket/webSocketServer.js
Normal file
47
app/middleware/webSocket/webSocketServer.js
Normal file
@@ -0,0 +1,47 @@
|
||||
// webSocket服务端
|
||||
const http = require('http');
|
||||
const { Server } = require('socket.io');
|
||||
|
||||
module.exports = (app) => {
|
||||
// 创建HTTP服务器并监听8010端口
|
||||
const server = http.createServer(function (req, res) {
|
||||
if (req.url === '/') {
|
||||
res.writeHead(200, {'Content-Type': 'text/plain'});
|
||||
res.end('Hello World!');
|
||||
}
|
||||
}).listen(app.config.webSocketServer.port);
|
||||
|
||||
let io = new Server(server, {
|
||||
cors: {
|
||||
origin: "http://127.0.0.1", // 生产环境应指定具体域名
|
||||
methods: ["GET", "POST"]
|
||||
},
|
||||
// path: app.config.webSocketServer.path,
|
||||
transports: ['websocket', 'polling'],
|
||||
connectionStateRecovery: {}
|
||||
});
|
||||
|
||||
console.log(`websocket: ${ app.config.webSocketServer.ip }服务器已启动,监听端口:${ app.config.webSocketServer.port }`);
|
||||
|
||||
const socketEmitter = app.middleware.shunt.socketEmitter();
|
||||
const utils = app.middleware.utils;
|
||||
|
||||
io.on('connection', (socket) => {
|
||||
socket.on('message', (cardID) => {
|
||||
if(socketEmitter.listeners(cardID).length !== 0) {
|
||||
socketEmitter.removeAllListeners(cardID);
|
||||
};
|
||||
socketEmitter.on(cardID, (msg) => {
|
||||
socket.emit(cardID, msg);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
io.on('error', (err) => {
|
||||
utils.log('../../webSocketLog', err);
|
||||
io = new Server(app.config.webSocketServer.port, {
|
||||
cors: true,
|
||||
connectionStateRecovery: {}
|
||||
});
|
||||
});
|
||||
};
|
||||
Reference in New Issue
Block a user