@colyseus/bun-websockets 0.15.0 → 0.15.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +107 -18
- package/build/BunWebSockets.d.ts +3 -4
- package/build/BunWebSockets.js +29 -17
- package/build/BunWebSockets.js.map +3 -3
- package/build/BunWebSockets.mjs +30 -18
- package/build/BunWebSockets.mjs.map +3 -3
- package/build/WebSocketClient.d.ts +3 -3
- package/build/WebSocketClient.js +2 -5
- package/build/WebSocketClient.js.map +2 -2
- package/build/WebSocketClient.mjs +2 -5
- package/build/WebSocketClient.mjs.map +2 -2
- package/package.json +6 -9
- package/build/BunWebSocket.d.ts +0 -24
- package/build/BunWebSocket.js +0 -173
- package/build/BunWebSocket.js.map +0 -7
- package/build/BunWebSocket.mjs +0 -144
- package/build/BunWebSocket.mjs.map +0 -7
- package/build/WebSocketTransport.d.ts +0 -24
- package/build/WebSocketTransport.js +0 -173
- package/build/WebSocketTransport.js.map +0 -7
- package/build/WebSocketTransport.mjs +0 -144
- package/build/WebSocketTransport.mjs.map +0 -7
|
@@ -1,144 +0,0 @@
|
|
|
1
|
-
import Bun from "bun";
|
|
2
|
-
import { DummyServer, ErrorCode, matchMaker, Transport, debugAndPrintError, spliceOne, ServerError } from "@colyseus/core";
|
|
3
|
-
import { WebSocketClient, WebSocketWrapper } from "./WebSocketClient";
|
|
4
|
-
class uWebSocketsTransport extends Transport {
|
|
5
|
-
constructor(options = {}) {
|
|
6
|
-
super();
|
|
7
|
-
this.options = options;
|
|
8
|
-
if (!this.server) {
|
|
9
|
-
this.server = new DummyServer();
|
|
10
|
-
}
|
|
11
|
-
}
|
|
12
|
-
bunServer;
|
|
13
|
-
clients = [];
|
|
14
|
-
clientWrappers = /* @__PURE__ */ new WeakMap();
|
|
15
|
-
listen(port, hostname, backlog, listeningListener) {
|
|
16
|
-
const handleMatchMakeRequest = this.handleMatchMakeRequest;
|
|
17
|
-
this.bunServer = Bun.serve({
|
|
18
|
-
port,
|
|
19
|
-
hostname,
|
|
20
|
-
async fetch(req, server) {
|
|
21
|
-
const url = new URL(req.url);
|
|
22
|
-
if (url.pathname.startsWith(`/${matchMaker.controller.matchmakeRoute}`)) {
|
|
23
|
-
try {
|
|
24
|
-
const [code, response, headers] = await handleMatchMakeRequest(req, server, url);
|
|
25
|
-
return new Response(response, {
|
|
26
|
-
status: code,
|
|
27
|
-
headers: Object.assign(
|
|
28
|
-
headers,
|
|
29
|
-
matchMaker.controller.DEFAULT_CORS_HEADERS,
|
|
30
|
-
matchMaker.controller.getCorsHeaders.call(void 0, req)
|
|
31
|
-
)
|
|
32
|
-
});
|
|
33
|
-
} catch (e) {
|
|
34
|
-
return new Response(JSON.stringify({ code: e.code, error: e.message }), {
|
|
35
|
-
status: e.code || ErrorCode.MATCHMAKE_UNHANDLED,
|
|
36
|
-
headers: Object.assign(
|
|
37
|
-
{ "Content-Type": "application/json" },
|
|
38
|
-
matchMaker.controller.DEFAULT_CORS_HEADERS,
|
|
39
|
-
matchMaker.controller.getCorsHeaders.call(void 0, req)
|
|
40
|
-
)
|
|
41
|
-
});
|
|
42
|
-
}
|
|
43
|
-
} else {
|
|
44
|
-
server.upgrade(req, { data: { url } });
|
|
45
|
-
return void 0;
|
|
46
|
-
}
|
|
47
|
-
},
|
|
48
|
-
websocket: {
|
|
49
|
-
...this.options,
|
|
50
|
-
async open(ws) {
|
|
51
|
-
await this.onConnection(ws);
|
|
52
|
-
},
|
|
53
|
-
message(ws, message) {
|
|
54
|
-
this.clientWrappers.get(ws)?.emit("message", message);
|
|
55
|
-
},
|
|
56
|
-
close(ws, code, reason) {
|
|
57
|
-
spliceOne(this.clients, this.clients.indexOf(ws));
|
|
58
|
-
const clientWrapper = this.clientWrappers.get(ws);
|
|
59
|
-
if (clientWrapper) {
|
|
60
|
-
this.clientWrappers.delete(ws);
|
|
61
|
-
clientWrapper.emit("close", code);
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
});
|
|
66
|
-
listeningListener?.();
|
|
67
|
-
this.server.emit("listening");
|
|
68
|
-
return this;
|
|
69
|
-
}
|
|
70
|
-
shutdown() {
|
|
71
|
-
if (this.bunServer) {
|
|
72
|
-
this.bunServer.stop(true);
|
|
73
|
-
this.server.emit("close");
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
simulateLatency(milliseconds) {
|
|
77
|
-
const originalRawSend = WebSocketClient.prototype.raw;
|
|
78
|
-
WebSocketClient.prototype.raw = function() {
|
|
79
|
-
setTimeout(() => originalRawSend.apply(this, arguments), milliseconds);
|
|
80
|
-
};
|
|
81
|
-
}
|
|
82
|
-
async onConnection(rawClient) {
|
|
83
|
-
const wrapper = new WebSocketWrapper(rawClient);
|
|
84
|
-
this.clients.push(rawClient);
|
|
85
|
-
this.clientWrappers.set(rawClient, wrapper);
|
|
86
|
-
const parsedURL = new URL(rawClient.data.url);
|
|
87
|
-
const sessionId = parsedURL.searchParams.get("sessionId");
|
|
88
|
-
const processAndRoomId = parsedURL.pathname.match(/\/[a-zA-Z0-9_\-]+\/([a-zA-Z0-9_\-]+)$/);
|
|
89
|
-
const roomId = processAndRoomId && processAndRoomId[1];
|
|
90
|
-
const room = matchMaker.getRoomById(roomId);
|
|
91
|
-
const client = new WebSocketClient(sessionId, wrapper);
|
|
92
|
-
try {
|
|
93
|
-
if (!room || !room.hasReservedSeat(sessionId, parsedURL.searchParams.get("reconnectionToken"))) {
|
|
94
|
-
throw new Error("seat reservation expired.");
|
|
95
|
-
}
|
|
96
|
-
await room._onJoin(client, rawClient);
|
|
97
|
-
} catch (e) {
|
|
98
|
-
debugAndPrintError(e);
|
|
99
|
-
client.error(e.code, e.message, () => rawClient.close());
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
async handleMatchMakeRequest(req, server, url) {
|
|
103
|
-
switch (req.method) {
|
|
104
|
-
case "OPTIONS":
|
|
105
|
-
return [200, void 0, {}];
|
|
106
|
-
case "GET": {
|
|
107
|
-
const matchedParams = url.pathname.match(matchMaker.controller.allowedRoomNameChars);
|
|
108
|
-
const roomName = matchedParams.length > 1 ? matchedParams[matchedParams.length - 1] : "";
|
|
109
|
-
return [
|
|
110
|
-
200,
|
|
111
|
-
JSON.stringify(await matchMaker.controller.getAvailableRooms(roomName || "")),
|
|
112
|
-
{
|
|
113
|
-
"Content-Type": "application/json"
|
|
114
|
-
}
|
|
115
|
-
];
|
|
116
|
-
}
|
|
117
|
-
case "POST": {
|
|
118
|
-
if (matchMaker.isGracefullyShuttingDown) {
|
|
119
|
-
throw new ServerError(503, "server is shutting down");
|
|
120
|
-
}
|
|
121
|
-
const matchedParams = url.pathname.match(matchMaker.controller.allowedRoomNameChars);
|
|
122
|
-
const matchmakeIndex = matchedParams.indexOf(matchMaker.controller.matchmakeRoute);
|
|
123
|
-
const clientOptions = Bun.readableStreamToJSON(req.body);
|
|
124
|
-
if (clientOptions === void 0) {
|
|
125
|
-
throw new Error("invalid JSON input");
|
|
126
|
-
}
|
|
127
|
-
const method = matchedParams[matchmakeIndex + 1];
|
|
128
|
-
const roomName = matchedParams[matchmakeIndex + 2] || "";
|
|
129
|
-
return [
|
|
130
|
-
200,
|
|
131
|
-
JSON.stringify(await matchMaker.controller.invokeMethod(method, roomName, clientOptions)),
|
|
132
|
-
{
|
|
133
|
-
"Content-Type": "application/json"
|
|
134
|
-
}
|
|
135
|
-
];
|
|
136
|
-
}
|
|
137
|
-
default:
|
|
138
|
-
return void 0;
|
|
139
|
-
}
|
|
140
|
-
}
|
|
141
|
-
}
|
|
142
|
-
export {
|
|
143
|
-
uWebSocketsTransport
|
|
144
|
-
};
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"version": 3,
|
|
3
|
-
"sources": ["../src/WebSocketTransport.ts"],
|
|
4
|
-
"sourcesContent": ["/// <reference types=\"bun-types\" />\nimport Bun, { Server, ServerWebSocket, WebSocketHandler } from \"bun\";\n\nimport http from 'http';\n\nimport { DummyServer, ErrorCode, matchMaker, Transport, debugAndPrintError, spliceOne, ServerError } from '@colyseus/core';\nimport { WebSocketClient, WebSocketWrapper } from './WebSocketClient';\n\nexport type TransportOptions = Partial<Omit<WebSocketHandler, \"message\" | \"open\" | \"drain\" | \"close\" | \"ping\" | \"pong\">>;\n\ninterface WebSocketData {\n url: URL;\n // query: string,\n // headers: { [key: string]: string },\n // connection: { remoteAddress: string },\n}\n\nexport class uWebSocketsTransport extends Transport {\n public bunServer: Bun.Server;\n\n protected clients: ServerWebSocket<WebSocketData>[] = [];\n protected clientWrappers = new WeakMap<ServerWebSocket<WebSocketData>, WebSocketWrapper>();\n\n constructor(private options: TransportOptions = {}) {\n super();\n\n // Adding a mock object for Transport.server\n if (!this.server) {\n this.server = new DummyServer();\n }\n }\n\n public listen(port: number | string, hostname?: string, backlog?: number, listeningListener?: () => void) {\n const handleMatchMakeRequest = this.handleMatchMakeRequest;\n\n this.bunServer = Bun.serve<WebSocketData>({\n port,\n hostname,\n\n async fetch(req, server) {\n const url = new URL(req.url);\n\n if (url.pathname.startsWith(`/${matchMaker.controller.matchmakeRoute}`)) {\n try {\n const [code, response, headers] = await handleMatchMakeRequest(req, server, url);\n //\n // success response\n //\n return new Response(response, {\n status: code,\n headers: Object.assign(\n headers,\n matchMaker.controller.DEFAULT_CORS_HEADERS,\n matchMaker.controller.getCorsHeaders.call(undefined, req)\n )\n });\n\n } catch (e) {\n //\n // error response\n //\n return new Response(JSON.stringify({ code: e.code, error: e.message }), {\n status: e.code || ErrorCode.MATCHMAKE_UNHANDLED,\n headers: Object.assign(\n { 'Content-Type': 'application/json' },\n matchMaker.controller.DEFAULT_CORS_HEADERS,\n matchMaker.controller.getCorsHeaders.call(undefined, req)\n )\n });\n }\n\n\n } else {\n // req.headers.get(\"Cookie\");\n server.upgrade(req, { data: { url } });\n\n return undefined;\n }\n },\n\n websocket: {\n ...this.options,\n\n async open(ws) {\n await this.onConnection(ws);\n },\n\n message(ws, message) {\n // this.clientWrappers.get(ws)?.emit('message', Buffer.from(message.slice(0)));\n this.clientWrappers.get(ws)?.emit('message', message);\n },\n\n close(ws, code, reason) {\n // remove from client list\n spliceOne(this.clients, this.clients.indexOf(ws));\n\n const clientWrapper = this.clientWrappers.get(ws);\n if (clientWrapper) {\n this.clientWrappers.delete(ws);\n\n // emit 'close' on wrapper\n clientWrapper.emit('close', code);\n }\n },\n\n }\n });\n\n listeningListener?.();\n this.server.emit(\"listening\"); // Mocking Transport.server behaviour, https://github.com/colyseus/colyseus/issues/458\n\n return this;\n }\n\n public shutdown() {\n if (this.bunServer) {\n this.bunServer.stop(true);\n this.server.emit(\"close\"); // Mocking Transport.server behaviour, https://github.com/colyseus/colyseus/issues/458\n }\n }\n\n public simulateLatency(milliseconds: number) {\n const originalRawSend = WebSocketClient.prototype.raw;\n WebSocketClient.prototype.raw = function () {\n setTimeout(() => originalRawSend.apply(this, arguments), milliseconds);\n }\n }\n\n protected async onConnection(rawClient: ServerWebSocket<WebSocketData>) {\n const wrapper = new WebSocketWrapper(rawClient);\n // keep reference to client and its wrapper\n this.clients.push(rawClient);\n this.clientWrappers.set(rawClient, wrapper);\n\n const parsedURL = new URL(rawClient.data.url);\n\n const sessionId = parsedURL.searchParams.get(\"sessionId\");\n const processAndRoomId = parsedURL.pathname.match(/\\/[a-zA-Z0-9_\\-]+\\/([a-zA-Z0-9_\\-]+)$/);\n const roomId = processAndRoomId && processAndRoomId[1];\n\n const room = matchMaker.getRoomById(roomId);\n const client = new WebSocketClient(sessionId, wrapper);\n\n //\n // TODO: DRY code below with all transports\n //\n\n try {\n if (!room || !room.hasReservedSeat(sessionId, parsedURL.searchParams.get(\"reconnectionToken\") as string)) {\n throw new Error('seat reservation expired.');\n }\n\n await room._onJoin(client, rawClient as unknown as http.IncomingMessage);\n\n } catch (e) {\n debugAndPrintError(e);\n\n // send error code to client then terminate\n client.error(e.code, e.message, () => rawClient.close());\n }\n }\n\n protected async handleMatchMakeRequest (req: Request, server: Server, url: URL): Promise<[number, string, { [key: string]: string }]> {\n switch (req.method) {\n case 'OPTIONS': return [200, undefined, {}];\n\n case 'GET': {\n const matchedParams = url.pathname.match(matchMaker.controller.allowedRoomNameChars);\n const roomName = matchedParams.length > 1 ? matchedParams[matchedParams.length - 1] : \"\";\n\n return [\n 200,\n JSON.stringify(await matchMaker.controller.getAvailableRooms(roomName || '')), {\n 'Content-Type': 'application/json'\n }\n ];\n }\n\n case 'POST': {\n // do not accept matchmaking requests if already shutting down\n if (matchMaker.isGracefullyShuttingDown) {\n throw new ServerError(503, \"server is shutting down\");\n }\n\n const matchedParams = url.pathname.match(matchMaker.controller.allowedRoomNameChars);\n const matchmakeIndex = matchedParams.indexOf(matchMaker.controller.matchmakeRoute);\n\n const clientOptions = Bun.readableStreamToJSON(req.body);\n\n if (clientOptions === undefined) {\n throw new Error(\"invalid JSON input\");\n }\n\n const method = matchedParams[matchmakeIndex + 1];\n const roomName = matchedParams[matchmakeIndex + 2] || '';\n\n return [\n 200,\n JSON.stringify(await matchMaker.controller.invokeMethod(method, roomName, clientOptions)), {\n 'Content-Type': 'application/json'\n }\n ];\n }\n\n default: return undefined;\n }\n }\n\n}\n"],
|
|
5
|
-
"mappings": "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",
|
|
6
|
-
"names": []
|
|
7
|
-
}
|