|
|
@@ -0,0 +1,505 @@
|
|
|
+import { encrypt50, decrypt50 } from './crypto';
|
|
|
+
|
|
|
+/**
|
|
|
+ * 4.0 行情报文协议(Len >= 15 byte,大端字节序)
|
|
|
+ * Header byte 1 包头 0xFF
|
|
|
+ * Length UInt32 4 长度
|
|
|
+ * mainClassNumber byte 1 大类号
|
|
|
+ * subClassNumber UInt16 2 小类号
|
|
|
+ * SerialNumber UInt32 4 流水号
|
|
|
+ * Mode byte 1 内容类型(0:ProtoBuff; 1:Json; 2:Zip+ProtoBuff)
|
|
|
+ * Version byte 1 版本号
|
|
|
+ * Content byte[] n 数据体 心跳数据体长度为0,目前不对4.0(行情)报文进行加解密
|
|
|
+ * End byte 1 包尾 0x0
|
|
|
+ */
|
|
|
+export class Package40 {
|
|
|
+ /** 包头 */
|
|
|
+ header = 0xff;
|
|
|
+ /** 包长度 */
|
|
|
+ packageLength = 0;
|
|
|
+ /** 大类(服务端会自动变成回复的大类号) */
|
|
|
+ mainClassNumber = 0;
|
|
|
+ /** 小类 */
|
|
|
+ subClassNumber = 0;
|
|
|
+ /** 流水号 */
|
|
|
+ serialNumber = 0;
|
|
|
+ /** 内容类型 */
|
|
|
+ mode = 0;
|
|
|
+ /** 版本号 */
|
|
|
+ version = 0;
|
|
|
+ /** 数据体 */
|
|
|
+ content?: Uint8Array;
|
|
|
+ /** 包尾 */
|
|
|
+ end = 0x0;
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 构造函数,把报文字节流装箱成报文对象
|
|
|
+ */
|
|
|
+ constructor(contentOrNumber: number | Uint8Array, content?: Uint8Array) {
|
|
|
+ if (contentOrNumber instanceof Uint8Array) {
|
|
|
+ // 接收信息装箱
|
|
|
+ if (contentOrNumber.length < 15) return;
|
|
|
+
|
|
|
+ this.header = contentOrNumber[0];
|
|
|
+ this.packageLength = new DataView(new Uint8Array(contentOrNumber.subarray(1, 5)).buffer).getUint32(0, false);
|
|
|
+ this.mainClassNumber = contentOrNumber[5];
|
|
|
+ this.subClassNumber = new DataView(new Uint8Array(contentOrNumber.subarray(6, 8)).buffer).getUint16(0, false);
|
|
|
+ this.serialNumber = new DataView(new Uint8Array(contentOrNumber.subarray(8, 12)).buffer).getUint32(0, false);
|
|
|
+ this.mode = contentOrNumber[12];
|
|
|
+ this.version = contentOrNumber[13];
|
|
|
+
|
|
|
+ if (contentOrNumber.length > 15) {
|
|
|
+ this.content = contentOrNumber.subarray(14, contentOrNumber.length - 1);
|
|
|
+ }
|
|
|
+ this.end = contentOrNumber[contentOrNumber.length - 1];
|
|
|
+ } else {
|
|
|
+ // 发送信息装箱
|
|
|
+ this.mainClassNumber = contentOrNumber;
|
|
|
+ this.content = content;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 获取可发送的包数据流
|
|
|
+ */
|
|
|
+ data(): Uint8Array {
|
|
|
+ if (this.content) {
|
|
|
+ this.packageLength = this.content.length + 15;
|
|
|
+ } else {
|
|
|
+ this.packageLength = 15;
|
|
|
+ }
|
|
|
+
|
|
|
+ const rst = new Uint8Array(this.packageLength);
|
|
|
+ let pos = 0;
|
|
|
+ // 包头
|
|
|
+ rst[pos] = this.header;
|
|
|
+ pos++;
|
|
|
+ // 包长度
|
|
|
+ let dataView = new DataView(new ArrayBuffer(4));
|
|
|
+ dataView.setUint32(0, this.packageLength, false);
|
|
|
+ rst.set(new Uint8Array(dataView.buffer), pos);
|
|
|
+ pos += 4;
|
|
|
+ // 大类号
|
|
|
+ rst[pos] = this.mainClassNumber;
|
|
|
+ pos++;
|
|
|
+ // 小类号
|
|
|
+ dataView = new DataView(new ArrayBuffer(2));
|
|
|
+ dataView.setUint16(0, this.subClassNumber, false);
|
|
|
+ rst.set(new Uint8Array(dataView.buffer), pos);
|
|
|
+ pos += 2;
|
|
|
+ // 流水号
|
|
|
+ dataView = new DataView(new ArrayBuffer(4));
|
|
|
+ dataView.setUint32(0, this.serialNumber, false);
|
|
|
+ rst.set(new Uint8Array(dataView.buffer), pos);
|
|
|
+ pos += 4;
|
|
|
+ // 内容类型
|
|
|
+ rst[pos] = this.mode;
|
|
|
+ pos++;
|
|
|
+ // 版本号
|
|
|
+ rst[pos] = this.version;
|
|
|
+ pos++;
|
|
|
+ // 数据体
|
|
|
+ if (this.content) rst.set(this.content, pos);
|
|
|
+ // 包尾
|
|
|
+ rst[this.packageLength - 1] = this.end;
|
|
|
+
|
|
|
+ return rst;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * 5.0 交易报文协议(Len >= 24 byte,小端字节序)
|
|
|
+ * Header byte 1 包头 0xFF
|
|
|
+ * Length UInt32 4 长度
|
|
|
+ * FunCode UInt32 4 功能码(0代表心跳)
|
|
|
+ * SessionID UInt32 4 会话ID
|
|
|
+ * Mode byte 1 内容类型(0:ProtoBuff;1:Json;2:Zip+ProtoBuff)
|
|
|
+ * Version byte 1 版本号
|
|
|
+ * SerialNumber UInt32 4 流水号
|
|
|
+ * Content byte[] n 数据内容(心跳数据体长度为0)
|
|
|
+ * CRC UInt32 4 检验和 头19个字节检验和
|
|
|
+ * End byte 1 包尾 0x0
|
|
|
+ */
|
|
|
+export class Package50 {
|
|
|
+ /** 包头 */
|
|
|
+ header = 0xff;
|
|
|
+ /** 长度 */
|
|
|
+ packageLength = 0;
|
|
|
+ /** 功能码(0代表心跳) */
|
|
|
+ funCode = 0;
|
|
|
+ /** 会话ID */
|
|
|
+ sessionID = 0;
|
|
|
+ /** 内容类型(0:ProtoBuff;1:Json;2:Zip+ProtoBuff) */
|
|
|
+ mode = 0;
|
|
|
+ /** 版本号 */
|
|
|
+ version = 0;
|
|
|
+ /** 流水号 */
|
|
|
+ serialNumber = 0;
|
|
|
+ /** 数据内容(心跳数据体长度为0) */
|
|
|
+ content?: Uint8Array;
|
|
|
+ /** 检验和 */
|
|
|
+ crc = 0;
|
|
|
+ /** 包尾 */
|
|
|
+ end = 0;
|
|
|
+
|
|
|
+ constructor(funCodeOrNumber: number | Uint8Array, content?: Uint8Array) {
|
|
|
+ if (funCodeOrNumber instanceof Uint8Array) {
|
|
|
+ // 接收信息装箱
|
|
|
+ if (funCodeOrNumber.length < 24) return;
|
|
|
+
|
|
|
+ // 先尝试对数据体进行解密
|
|
|
+ let decryptData: Uint8Array | null = null;
|
|
|
+ if (funCodeOrNumber.length > 24) {
|
|
|
+ const content = funCodeOrNumber.subarray(19, funCodeOrNumber.length - 4 - 1);
|
|
|
+ decryptData = decrypt50(content);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 长度
|
|
|
+ this.packageLength = new DataView(new Uint8Array(funCodeOrNumber.subarray(1, 5)).buffer).getUint32(0, true);
|
|
|
+ // 功能码
|
|
|
+ this.funCode = new DataView(new Uint8Array(funCodeOrNumber.subarray(5, 9)).buffer).getUint32(0, true);
|
|
|
+ // 流水号
|
|
|
+ this.serialNumber = new DataView(new Uint8Array(funCodeOrNumber.subarray(15, 19)).buffer).getUint32(0, true);
|
|
|
+ // 内容
|
|
|
+ if (decryptData) {
|
|
|
+ this.content = decryptData;
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ // 发送信息装箱
|
|
|
+ this.funCode = funCodeOrNumber;
|
|
|
+ this.content = content;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ data(): Uint8Array {
|
|
|
+ // 先尝试加密内容
|
|
|
+ let encryptData: Uint8Array | null = null;
|
|
|
+ if (this.content) {
|
|
|
+ encryptData = encrypt50(this.content);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 重新计算整包长度
|
|
|
+ this.packageLength = 24;
|
|
|
+ if (encryptData) {
|
|
|
+ this.packageLength = 19 + encryptData.length + 5;
|
|
|
+ }
|
|
|
+
|
|
|
+ const rst = new Uint8Array(this.packageLength);
|
|
|
+ let pos = 0;
|
|
|
+
|
|
|
+ // 报文头
|
|
|
+ rst[pos] = this.header;
|
|
|
+ pos++;
|
|
|
+ // 长度
|
|
|
+ let dataView = new DataView(new ArrayBuffer(4));
|
|
|
+ dataView.setUint32(0, this.packageLength, true);
|
|
|
+ rst.set(new Uint8Array(dataView.buffer), pos);
|
|
|
+ pos += 4;
|
|
|
+ // 功能码
|
|
|
+ dataView = new DataView(new ArrayBuffer(4));
|
|
|
+ dataView.setUint32(0, this.funCode, true);
|
|
|
+ rst.set(new Uint8Array(dataView.buffer), pos);
|
|
|
+ pos += 4;
|
|
|
+ // 会话ID
|
|
|
+ dataView = new DataView(new ArrayBuffer(4));
|
|
|
+ dataView.setUint32(0, this.sessionID, true);
|
|
|
+ rst.set(new Uint8Array(dataView.buffer), pos);
|
|
|
+ pos += 4;
|
|
|
+ // 内容类型
|
|
|
+ rst[pos] = 0x0;
|
|
|
+ pos++;
|
|
|
+ // 版本号
|
|
|
+ rst[pos] = 0x0;
|
|
|
+ pos++;
|
|
|
+ // 流水号
|
|
|
+ dataView = new DataView(new ArrayBuffer(4));
|
|
|
+ dataView.setUint32(0, this.serialNumber, true);
|
|
|
+ rst.set(new Uint8Array(dataView.buffer), pos);
|
|
|
+ pos += 4;
|
|
|
+ // 报文内容
|
|
|
+ if (encryptData) {
|
|
|
+ rst.set(encryptData, pos);
|
|
|
+ pos += encryptData.length;
|
|
|
+ }
|
|
|
+ // 校验和
|
|
|
+ const crcByte = rst.subarray(0, 19); // 复制报文头,以便于校验和计算
|
|
|
+ dataView = new DataView(new ArrayBuffer(4));
|
|
|
+ dataView.setUint32(0, this.getCRC32(crcByte), true);
|
|
|
+ rst.set(new Uint8Array(dataView.buffer), pos);
|
|
|
+ // 包尾
|
|
|
+ rst[this.packageLength - 1] = this.end;
|
|
|
+
|
|
|
+ return rst;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 计算检验和
|
|
|
+ * @param crcByte 目标数据
|
|
|
+ */
|
|
|
+ getCRC32(crcByte: Uint8Array) {
|
|
|
+ const table = [
|
|
|
+ 0x00000000,
|
|
|
+ 0x77073096,
|
|
|
+ 0xee0e612c,
|
|
|
+ 0x990951ba,
|
|
|
+ 0x076dc419,
|
|
|
+ 0x706af48f,
|
|
|
+ 0xe963a535,
|
|
|
+ 0x9e6495a3,
|
|
|
+ 0x0edb8832,
|
|
|
+ 0x79dcb8a4,
|
|
|
+ 0xe0d5e91e,
|
|
|
+ 0x97d2d988,
|
|
|
+ 0x09b64c2b,
|
|
|
+ 0x7eb17cbd,
|
|
|
+ 0xe7b82d07,
|
|
|
+ 0x90bf1d91,
|
|
|
+ 0x1db71064,
|
|
|
+ 0x6ab020f2,
|
|
|
+ 0xf3b97148,
|
|
|
+ 0x84be41de,
|
|
|
+ 0x1adad47d,
|
|
|
+ 0x6ddde4eb,
|
|
|
+ 0xf4d4b551,
|
|
|
+ 0x83d385c7,
|
|
|
+ 0x136c9856,
|
|
|
+ 0x646ba8c0,
|
|
|
+ 0xfd62f97a,
|
|
|
+ 0x8a65c9ec,
|
|
|
+ 0x14015c4f,
|
|
|
+ 0x63066cd9,
|
|
|
+ 0xfa0f3d63,
|
|
|
+ 0x8d080df5,
|
|
|
+ 0x3b6e20c8,
|
|
|
+ 0x4c69105e,
|
|
|
+ 0xd56041e4,
|
|
|
+ 0xa2677172,
|
|
|
+ 0x3c03e4d1,
|
|
|
+ 0x4b04d447,
|
|
|
+ 0xd20d85fd,
|
|
|
+ 0xa50ab56b,
|
|
|
+ 0x35b5a8fa,
|
|
|
+ 0x42b2986c,
|
|
|
+ 0xdbbbc9d6,
|
|
|
+ 0xacbcf940,
|
|
|
+ 0x32d86ce3,
|
|
|
+ 0x45df5c75,
|
|
|
+ 0xdcd60dcf,
|
|
|
+ 0xabd13d59,
|
|
|
+ 0x26d930ac,
|
|
|
+ 0x51de003a,
|
|
|
+ 0xc8d75180,
|
|
|
+ 0xbfd06116,
|
|
|
+ 0x21b4f4b5,
|
|
|
+ 0x56b3c423,
|
|
|
+ 0xcfba9599,
|
|
|
+ 0xb8bda50f,
|
|
|
+ 0x2802b89e,
|
|
|
+ 0x5f058808,
|
|
|
+ 0xc60cd9b2,
|
|
|
+ 0xb10be924,
|
|
|
+ 0x2f6f7c87,
|
|
|
+ 0x58684c11,
|
|
|
+ 0xc1611dab,
|
|
|
+ 0xb6662d3d,
|
|
|
+ 0x76dc4190,
|
|
|
+ 0x01db7106,
|
|
|
+ 0x98d220bc,
|
|
|
+ 0xefd5102a,
|
|
|
+ 0x71b18589,
|
|
|
+ 0x06b6b51f,
|
|
|
+ 0x9fbfe4a5,
|
|
|
+ 0xe8b8d433,
|
|
|
+ 0x7807c9a2,
|
|
|
+ 0x0f00f934,
|
|
|
+ 0x9609a88e,
|
|
|
+ 0xe10e9818,
|
|
|
+ 0x7f6a0dbb,
|
|
|
+ 0x086d3d2d,
|
|
|
+ 0x91646c97,
|
|
|
+ 0xe6635c01,
|
|
|
+ 0x6b6b51f4,
|
|
|
+ 0x1c6c6162,
|
|
|
+ 0x856530d8,
|
|
|
+ 0xf262004e,
|
|
|
+ 0x6c0695ed,
|
|
|
+ 0x1b01a57b,
|
|
|
+ 0x8208f4c1,
|
|
|
+ 0xf50fc457,
|
|
|
+ 0x65b0d9c6,
|
|
|
+ 0x12b7e950,
|
|
|
+ 0x8bbeb8ea,
|
|
|
+ 0xfcb9887c,
|
|
|
+ 0x62dd1ddf,
|
|
|
+ 0x15da2d49,
|
|
|
+ 0x8cd37cf3,
|
|
|
+ 0xfbd44c65,
|
|
|
+ 0x4db26158,
|
|
|
+ 0x3ab551ce,
|
|
|
+ 0xa3bc0074,
|
|
|
+ 0xd4bb30e2,
|
|
|
+ 0x4adfa541,
|
|
|
+ 0x3dd895d7,
|
|
|
+ 0xa4d1c46d,
|
|
|
+ 0xd3d6f4fb,
|
|
|
+ 0x4369e96a,
|
|
|
+ 0x346ed9fc,
|
|
|
+ 0xad678846,
|
|
|
+ 0xda60b8d0,
|
|
|
+ 0x44042d73,
|
|
|
+ 0x33031de5,
|
|
|
+ 0xaa0a4c5f,
|
|
|
+ 0xdd0d7cc9,
|
|
|
+ 0x5005713c,
|
|
|
+ 0x270241aa,
|
|
|
+ 0xbe0b1010,
|
|
|
+ 0xc90c2086,
|
|
|
+ 0x5768b525,
|
|
|
+ 0x206f85b3,
|
|
|
+ 0xb966d409,
|
|
|
+ 0xce61e49f,
|
|
|
+ 0x5edef90e,
|
|
|
+ 0x29d9c998,
|
|
|
+ 0xb0d09822,
|
|
|
+ 0xc7d7a8b4,
|
|
|
+ 0x59b33d17,
|
|
|
+ 0x2eb40d81,
|
|
|
+ 0xb7bd5c3b,
|
|
|
+ 0xc0ba6cad,
|
|
|
+ 0xedb88320,
|
|
|
+ 0x9abfb3b6,
|
|
|
+ 0x03b6e20c,
|
|
|
+ 0x74b1d29a,
|
|
|
+ 0xead54739,
|
|
|
+ 0x9dd277af,
|
|
|
+ 0x04db2615,
|
|
|
+ 0x73dc1683,
|
|
|
+ 0xe3630b12,
|
|
|
+ 0x94643b84,
|
|
|
+ 0x0d6d6a3e,
|
|
|
+ 0x7a6a5aa8,
|
|
|
+ 0xe40ecf0b,
|
|
|
+ 0x9309ff9d,
|
|
|
+ 0x0a00ae27,
|
|
|
+ 0x7d079eb1,
|
|
|
+ 0xf00f9344,
|
|
|
+ 0x8708a3d2,
|
|
|
+ 0x1e01f268,
|
|
|
+ 0x6906c2fe,
|
|
|
+ 0xf762575d,
|
|
|
+ 0x806567cb,
|
|
|
+ 0x196c3671,
|
|
|
+ 0x6e6b06e7,
|
|
|
+ 0xfed41b76,
|
|
|
+ 0x89d32be0,
|
|
|
+ 0x10da7a5a,
|
|
|
+ 0x67dd4acc,
|
|
|
+ 0xf9b9df6f,
|
|
|
+ 0x8ebeeff9,
|
|
|
+ 0x17b7be43,
|
|
|
+ 0x60b08ed5,
|
|
|
+ 0xd6d6a3e8,
|
|
|
+ 0xa1d1937e,
|
|
|
+ 0x38d8c2c4,
|
|
|
+ 0x4fdff252,
|
|
|
+ 0xd1bb67f1,
|
|
|
+ 0xa6bc5767,
|
|
|
+ 0x3fb506dd,
|
|
|
+ 0x48b2364b,
|
|
|
+ 0xd80d2bda,
|
|
|
+ 0xaf0a1b4c,
|
|
|
+ 0x36034af6,
|
|
|
+ 0x41047a60,
|
|
|
+ 0xdf60efc3,
|
|
|
+ 0xa867df55,
|
|
|
+ 0x316e8eef,
|
|
|
+ 0x4669be79,
|
|
|
+ 0xcb61b38c,
|
|
|
+ 0xbc66831a,
|
|
|
+ 0x256fd2a0,
|
|
|
+ 0x5268e236,
|
|
|
+ 0xcc0c7795,
|
|
|
+ 0xbb0b4703,
|
|
|
+ 0x220216b9,
|
|
|
+ 0x5505262f,
|
|
|
+ 0xc5ba3bbe,
|
|
|
+ 0xb2bd0b28,
|
|
|
+ 0x2bb45a92,
|
|
|
+ 0x5cb36a04,
|
|
|
+ 0xc2d7ffa7,
|
|
|
+ 0xb5d0cf31,
|
|
|
+ 0x2cd99e8b,
|
|
|
+ 0x5bdeae1d,
|
|
|
+ 0x9b64c2b0,
|
|
|
+ 0xec63f226,
|
|
|
+ 0x756aa39c,
|
|
|
+ 0x026d930a,
|
|
|
+ 0x9c0906a9,
|
|
|
+ 0xeb0e363f,
|
|
|
+ 0x72076785,
|
|
|
+ 0x05005713,
|
|
|
+ 0x95bf4a82,
|
|
|
+ 0xe2b87a14,
|
|
|
+ 0x7bb12bae,
|
|
|
+ 0x0cb61b38,
|
|
|
+ 0x92d28e9b,
|
|
|
+ 0xe5d5be0d,
|
|
|
+ 0x7cdcefb7,
|
|
|
+ 0x0bdbdf21,
|
|
|
+ 0x86d3d2d4,
|
|
|
+ 0xf1d4e242,
|
|
|
+ 0x68ddb3f8,
|
|
|
+ 0x1fda836e,
|
|
|
+ 0x81be16cd,
|
|
|
+ 0xf6b9265b,
|
|
|
+ 0x6fb077e1,
|
|
|
+ 0x18b74777,
|
|
|
+ 0x88085ae6,
|
|
|
+ 0xff0f6a70,
|
|
|
+ 0x66063bca,
|
|
|
+ 0x11010b5c,
|
|
|
+ 0x8f659eff,
|
|
|
+ 0xf862ae69,
|
|
|
+ 0x616bffd3,
|
|
|
+ 0x166ccf45,
|
|
|
+ 0xa00ae278,
|
|
|
+ 0xd70dd2ee,
|
|
|
+ 0x4e048354,
|
|
|
+ 0x3903b3c2,
|
|
|
+ 0xa7672661,
|
|
|
+ 0xd06016f7,
|
|
|
+ 0x4969474d,
|
|
|
+ 0x3e6e77db,
|
|
|
+ 0xaed16a4a,
|
|
|
+ 0xd9d65adc,
|
|
|
+ 0x40df0b66,
|
|
|
+ 0x37d83bf0,
|
|
|
+ 0xa9bcae53,
|
|
|
+ 0xdebb9ec5,
|
|
|
+ 0x47b2cf7f,
|
|
|
+ 0x30b5ffe9,
|
|
|
+ 0xbdbdf21c,
|
|
|
+ 0xcabac28a,
|
|
|
+ 0x53b39330,
|
|
|
+ 0x24b4a3a6,
|
|
|
+ 0xbad03605,
|
|
|
+ 0xcdd70693,
|
|
|
+ 0x54de5729,
|
|
|
+ 0x23d967bf,
|
|
|
+ 0xb3667a2e,
|
|
|
+ 0xc4614ab8,
|
|
|
+ 0x5d681b02,
|
|
|
+ 0x2a6f2b94,
|
|
|
+ 0xb40bbe37,
|
|
|
+ 0xc30c8ea1,
|
|
|
+ 0x5a05df1b,
|
|
|
+ 0x2d02ef8d,
|
|
|
+ ];
|
|
|
+ let crc = 0xffffffff;
|
|
|
+ for (let i = 0; i < crcByte.length; i++) {
|
|
|
+ crc = (crc >>> 8) ^ table[(crc ^ crcByte[i]) & 0xff];
|
|
|
+ }
|
|
|
+ crc = crc ^ 0xffffffff;
|
|
|
+ return crc;
|
|
|
+ }
|
|
|
+}
|