feat: 更新WebSocket 优化逻辑

Signed-off-by: MiaoWoo <admin@yumc.pw>
This commit is contained in:
2021-08-03 16:59:43 +08:00
parent def62e2940
commit 586b6acbbc
45 changed files with 5465 additions and 2376 deletions

View File

@ -0,0 +1,21 @@
const PACKET_TYPES = Object.create(null) // no Map = no polyfill
PACKET_TYPES["open"] = "0"
PACKET_TYPES["close"] = "1"
PACKET_TYPES["ping"] = "2"
PACKET_TYPES["pong"] = "3"
PACKET_TYPES["message"] = "4"
PACKET_TYPES["upgrade"] = "5"
PACKET_TYPES["noop"] = "6"
const PACKET_TYPES_REVERSE = Object.create(null)
Object.keys(PACKET_TYPES).forEach(key => {
PACKET_TYPES_REVERSE[PACKET_TYPES[key]] = key
})
const ERROR_PACKET = { type: "error", data: "parser error" }
export = {
PACKET_TYPES,
PACKET_TYPES_REVERSE,
ERROR_PACKET
}

View File

@ -0,0 +1,48 @@
const { PACKET_TYPES_REVERSE, ERROR_PACKET } = require("./commons")
export const decodePacket = (encodedPacket, binaryType) => {
if (typeof encodedPacket !== "string") {
return {
type: "message",
data: mapBinary(encodedPacket, binaryType)
}
}
const type = encodedPacket.charAt(0)
if (type === "b") {
const buffer = Buffer.from(encodedPacket.substring(1), "base64")
return {
type: "message",
data: mapBinary(buffer, binaryType)
}
}
if (!PACKET_TYPES_REVERSE[type]) {
return ERROR_PACKET
}
return encodedPacket.length > 1
? {
type: PACKET_TYPES_REVERSE[type],
data: encodedPacket.substring(1)
}
: {
type: PACKET_TYPES_REVERSE[type]
}
}
const mapBinary = (data, binaryType) => {
switch (binaryType) {
case "arraybuffer":
return Buffer.isBuffer(data) ? toArrayBuffer(data) : data
case "nodebuffer":
default:
return data // assuming the data is already a Buffer
}
}
const toArrayBuffer = buffer => {
const arrayBuffer = new ArrayBuffer(buffer.length)
const view = new Uint8Array(arrayBuffer)
for (let i = 0; i < buffer.length; i++) {
view[i] = buffer[i]
}
return arrayBuffer
}

View File

@ -0,0 +1,26 @@
const { PACKET_TYPES } = require("./commons")
export const encodePacket = ({ type, data }, supportsBinary, callback) => {
console.trace('encodePacket', type, JSON.stringify(data))
if (data instanceof ArrayBuffer || ArrayBuffer.isView(data)) {
const buffer = toBuffer(data)
return callback(encodeBuffer(buffer, supportsBinary))
}
// plain string
return callback(PACKET_TYPES[type] + (data || ""))
}
const toBuffer = data => {
if (Buffer.isBuffer(data)) {
return data
} else if (data instanceof ArrayBuffer) {
return Buffer.from(data)
} else {
return Buffer.from(data.buffer, data.byteOffset, data.byteLength)
}
}
// only 'message' packets can contain binary, so the type prefix is not needed
const encodeBuffer = (data, supportsBinary) => {
return supportsBinary ? data : "b" + data.toString("base64")
}

View File

@ -0,0 +1,42 @@
import { encodePacket } from "./encodePacket"
import { decodePacket } from "./decodePacket"
const SEPARATOR = String.fromCharCode(30) // see https://en.wikipedia.org/wiki/Delimiter#ASCII_delimited_text
const encodePayload = (packets, callback) => {
// some packets may be added to the array while encoding, so the initial length must be saved
const length = packets.length
const encodedPackets = new Array(length)
let count = 0
packets.forEach((packet, i) => {
// force base64 encoding for binary packets
encodePacket(packet, false, encodedPacket => {
encodedPackets[i] = encodedPacket
if (++count === length) {
callback(encodedPackets.join(SEPARATOR))
}
})
})
}
const decodePayload = (encodedPayload, binaryType) => {
const encodedPackets = encodedPayload.split(SEPARATOR)
const packets = []
for (let i = 0; i < encodedPackets.length; i++) {
const decodedPacket = decodePacket(encodedPackets[i], binaryType)
packets.push(decodedPacket)
if (decodedPacket.type === "error") {
break
}
}
return packets
}
export default {
protocol: 4,
encodePacket,
encodePayload,
decodePacket,
decodePayload
}