21
packages/websocket/src/engine.io-parser/commons.ts
Normal file
21
packages/websocket/src/engine.io-parser/commons.ts
Normal 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
|
||||
}
|
48
packages/websocket/src/engine.io-parser/decodePacket.ts
Normal file
48
packages/websocket/src/engine.io-parser/decodePacket.ts
Normal 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
|
||||
}
|
26
packages/websocket/src/engine.io-parser/encodePacket.ts
Normal file
26
packages/websocket/src/engine.io-parser/encodePacket.ts
Normal 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")
|
||||
}
|
42
packages/websocket/src/engine.io-parser/index.ts
Normal file
42
packages/websocket/src/engine.io-parser/index.ts
Normal 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
|
||||
}
|
Reference in New Issue
Block a user