@colyseus/core
Version:
Multiplayer Framework for Node.js.
114 lines (85 loc) • 3.57 kB
text/typescript
import { Packr } from '@colyseus/msgpackr';
import { encode, type Iterator } from '@colyseus/schema';
import { Protocol } from '@colyseus/shared-types';
// Inter-process communication protocol
export const IpcProtocol = {
SUCCESS: 0,
ERROR: 1,
TIMEOUT: 2,
} as const;
export type IpcProtocol = typeof IpcProtocol[keyof typeof IpcProtocol];
const packr = new Packr({
useRecords: false, // increased compatibility with decoders other than "msgpackr"
});
// msgpackr workaround: initialize buffer
packr.encode(undefined);
export const getMessageBytes = {
[Protocol.JOIN_ROOM]: (reconnectionToken: string, serializerId: string, handshake?: Uint8Array) => {
const it: Iterator = { offset: 1 };
packr.buffer[0] = Protocol.JOIN_ROOM;
packr.buffer[it.offset++] = Buffer.byteLength(reconnectionToken, "utf8");
encode.utf8Write(packr.buffer, reconnectionToken, it);
packr.buffer[it.offset++] = Buffer.byteLength(serializerId, "utf8");
encode.utf8Write(packr.buffer, serializerId, it);
let handshakeLength = handshake?.byteLength || 0;
// check if buffer needs to be resized
if (handshakeLength > packr.buffer.byteLength - it.offset) {
packr.useBuffer(Buffer.alloc(it.offset + handshakeLength, packr.buffer));
}
if (handshakeLength > 0) {
packr.buffer.set(handshake, it.offset);
}
return Buffer.from(packr.buffer.subarray(0, it.offset + handshakeLength));
},
[Protocol.ERROR]: (code: number, message: string = '') => {
const it: Iterator = { offset: 1 };
packr.buffer[0] = Protocol.ERROR;
encode.number(packr.buffer, code, it);
encode.string(packr.buffer, message, it);
return Buffer.from(packr.buffer.subarray(0, it.offset));
},
[Protocol.ROOM_STATE]: (bytes: number[]) => {
return [Protocol.ROOM_STATE, ...bytes];
},
[Protocol.PING]: () => {
packr.buffer[0] = Protocol.PING;
return Buffer.from(packr.buffer.subarray(0, 1));
},
raw: (code: Protocol, type: string | number, message?: any, rawMessage?: Uint8Array | Buffer) => {
const it: Iterator = { offset: 1 };
packr.buffer[0] = code;
if (typeof (type) === 'string') {
encode.string(packr.buffer, type, it);
} else {
encode.number(packr.buffer, type, it);
}
if (message !== undefined) {
// force to encode from offset
packr.position = 0;
//
// TODO: remove this after issue is fixed https://github.com/kriszyp/msgpackr/issues/139
//
// - This check is only required when running integration tests.
// (colyseus.js' usage of msgpackr/buffer is conflicting)
//
if (process.env.NODE_ENV !== "production") {
packr.useBuffer(packr.buffer);
}
// pack message into the same packr.buffer
const endOfBufferOffset = packr.pack(message, 2048 + it.offset).byteLength;
// 2048 = RESERVE_START_SPACE
return Buffer.from(packr.buffer.subarray(0, endOfBufferOffset));
} else if (rawMessage !== undefined) {
// check if buffer needs to be resized
// TODO: can we avoid this?
if (rawMessage.length + it.offset > packr.buffer.byteLength) {
packr.useBuffer(Buffer.alloc(it.offset + rawMessage.length, packr.buffer));
}
// copy raw message into packr.buffer
packr.buffer.set(rawMessage, it.offset);
return Buffer.from(packr.buffer.subarray(0, it.offset + rawMessage.byteLength));
} else {
return Buffer.from(packr.buffer.subarray(0, it.offset));
}
},
};