@wxn0brp/gloves-link-server 0.0.14 → 0.1.0-beta.0
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/dist/http.d.ts +18 -0
- package/dist/http.js +60 -0
- package/dist/index.d.ts +4 -25
- package/dist/index.js +38 -77
- package/dist/namespace.d.ts +11 -8
- package/dist/namespace.js +17 -15
- package/dist/room.d.ts +5 -15
- package/dist/room.js +19 -31
- package/dist/socket.d.ts +14 -29
- package/dist/socket.js +20 -92
- package/dist/transport.d.ts +3 -0
- package/dist/transport.js +47 -0
- package/dist/types.d.ts +7 -0
- package/package.json +1 -1
package/dist/http.d.ts
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { Router } from "@wxn0brp/falcon-frame";
|
|
2
|
+
import { SocketStatus } from "./types.js";
|
|
3
|
+
import { GlovesLinkServer } from "./index.js";
|
|
4
|
+
/**
|
|
5
|
+
* Saves the status of a socket connection for temporary tracking
|
|
6
|
+
*/
|
|
7
|
+
export declare function saveSocketStatus(wss: GlovesLinkServer, socketStatus: SocketStatus): void;
|
|
8
|
+
/**
|
|
9
|
+
* Creates a router for handling status requests
|
|
10
|
+
* @returns A router instance for status endpoints
|
|
11
|
+
*/
|
|
12
|
+
export declare function statusRouter(): Router;
|
|
13
|
+
/**
|
|
14
|
+
* Creates a router for serving client files
|
|
15
|
+
* @param clientDir - Optional directory path for client files, defaults to node_modules/@wxn0brp/gloves-link-client/dist/
|
|
16
|
+
* @returns A router instance for client file serving
|
|
17
|
+
*/
|
|
18
|
+
export declare function clientRouter(clientDir?: string): Router;
|
package/dist/http.js
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { Router } from "@wxn0brp/falcon-frame";
|
|
2
|
+
/**
|
|
3
|
+
* Saves the status of a socket connection for temporary tracking
|
|
4
|
+
*/
|
|
5
|
+
export function saveSocketStatus(wss, socketStatus) {
|
|
6
|
+
const { namespace, socketSelfId, status, msg } = socketStatus;
|
|
7
|
+
if (!socketSelfId)
|
|
8
|
+
return;
|
|
9
|
+
const id = namespace + "-" + socketSelfId;
|
|
10
|
+
wss.initStatusTemp[id] = {
|
|
11
|
+
status,
|
|
12
|
+
msg
|
|
13
|
+
};
|
|
14
|
+
setTimeout(() => {
|
|
15
|
+
delete wss.initStatusTemp[id];
|
|
16
|
+
}, wss.opts.statusTimeout);
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Creates a router for handling status requests
|
|
20
|
+
* @returns A router instance for status endpoints
|
|
21
|
+
*/
|
|
22
|
+
export function statusRouter() {
|
|
23
|
+
const router = new Router();
|
|
24
|
+
router.get("/status", (req, res) => {
|
|
25
|
+
const id = req.query.id;
|
|
26
|
+
if (!id) {
|
|
27
|
+
res.status(400).json({ err: true, msg: "No id provided" });
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
const path = req.query.path;
|
|
31
|
+
if (!path) {
|
|
32
|
+
res.status(400).json({ err: true, msg: "No path provided" });
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
const statusKey = path + "-" + id;
|
|
36
|
+
const status = this.initStatusTemp[statusKey];
|
|
37
|
+
if (status === undefined) {
|
|
38
|
+
res.status(404).json({ err: true, msg: "Socket not found" });
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
res.json({ err: false, status });
|
|
42
|
+
delete this.initStatusTemp[statusKey];
|
|
43
|
+
});
|
|
44
|
+
return router;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Creates a router for serving client files
|
|
48
|
+
* @param clientDir - Optional directory path for client files, defaults to node_modules/@wxn0brp/gloves-link-client/dist/
|
|
49
|
+
* @returns A router instance for client file serving
|
|
50
|
+
*/
|
|
51
|
+
export function clientRouter(clientDir) {
|
|
52
|
+
const router = new Router();
|
|
53
|
+
clientDir = clientDir || "node_modules/@wxn0brp/gloves-link-client/dist/";
|
|
54
|
+
router.static("/", clientDir);
|
|
55
|
+
router.get("/*", (req, res) => {
|
|
56
|
+
res.redirect("/gloves-link/GlovesLinkClient.js");
|
|
57
|
+
res.end();
|
|
58
|
+
});
|
|
59
|
+
return router;
|
|
60
|
+
}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import FalconFrame
|
|
1
|
+
import FalconFrame from "@wxn0brp/falcon-frame";
|
|
2
2
|
import http from "http";
|
|
3
3
|
import { WebSocketServer } from "ws";
|
|
4
4
|
import { Namespace } from "./namespace.js";
|
|
5
|
-
import { Room
|
|
5
|
+
import { Room } from "./room.js";
|
|
6
6
|
import { GLSocket } from "./socket.js";
|
|
7
7
|
import { Server_Opts } from "./types.js";
|
|
8
8
|
/**
|
|
@@ -15,23 +15,13 @@ export declare class GlovesLinkServer {
|
|
|
15
15
|
status: number;
|
|
16
16
|
msg?: string;
|
|
17
17
|
}>;
|
|
18
|
-
rooms: Rooms;
|
|
19
18
|
namespaces: Map<string, Namespace>;
|
|
20
19
|
/**
|
|
21
20
|
* Creates a new GlovesLinkServer instance
|
|
22
21
|
* @param opts - Server options including the HTTP server instance
|
|
23
22
|
*/
|
|
24
23
|
constructor(opts: Partial<Server_Opts>);
|
|
25
|
-
|
|
26
|
-
/**
|
|
27
|
-
* Saves the status of a socket connection for temporary tracking
|
|
28
|
-
* @param socketSelfId - The ID of the socket
|
|
29
|
-
* @param namespace - The namespace of the socket
|
|
30
|
-
* @param status - The status code to save
|
|
31
|
-
* @param msg - Optional message to save with the status
|
|
32
|
-
* @private
|
|
33
|
-
*/
|
|
34
|
-
private saveSocketStatus;
|
|
24
|
+
attachToHttpServer(server: http.Server): void;
|
|
35
25
|
/**
|
|
36
26
|
* Gets or creates a namespace by path
|
|
37
27
|
* @param path - The path for the namespace
|
|
@@ -46,7 +36,7 @@ export declare class GlovesLinkServer {
|
|
|
46
36
|
*/
|
|
47
37
|
broadcastRoom(roomName: string, event: string, ...args: any[]): void;
|
|
48
38
|
/**
|
|
49
|
-
* Gets or creates a room by name
|
|
39
|
+
* Gets or creates a room by name (from the root namespace)
|
|
50
40
|
* @param name - The name of the room
|
|
51
41
|
* @returns The room instance
|
|
52
42
|
*/
|
|
@@ -58,17 +48,6 @@ export declare class GlovesLinkServer {
|
|
|
58
48
|
* @param args - The arguments to pass with the event
|
|
59
49
|
*/
|
|
60
50
|
emitToUserId(userId: string, event: string, ...args: any[]): void;
|
|
61
|
-
/**
|
|
62
|
-
* Creates a router for handling status requests
|
|
63
|
-
* @returns A router instance for status endpoints
|
|
64
|
-
*/
|
|
65
|
-
statusRouter(): Router;
|
|
66
|
-
/**
|
|
67
|
-
* Creates a router for serving client files
|
|
68
|
-
* @param clientDir - Optional directory path for client files, defaults to node_modules/@wxn0brp/gloves-link-client/dist/
|
|
69
|
-
* @returns A router instance for client file serving
|
|
70
|
-
*/
|
|
71
|
-
clientRouter(clientDir?: string): Router;
|
|
72
51
|
/**
|
|
73
52
|
* Integrates the GlovesLink server with a FalconFrame application
|
|
74
53
|
* @param app - The FalconFrame application instance
|
package/dist/index.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { Router } from "@wxn0brp/falcon-frame";
|
|
2
2
|
import { WebSocketServer } from "ws";
|
|
3
|
+
import { clientRouter, saveSocketStatus, statusRouter } from "./http.js";
|
|
3
4
|
import { Namespace } from "./namespace.js";
|
|
4
|
-
import {
|
|
5
|
+
import { getRoom } from "./room.js";
|
|
5
6
|
import { GLSocket } from "./socket.js";
|
|
6
7
|
/**
|
|
7
8
|
* GlovesLinkServer class provides a WebSocket server with namespace and room functionality
|
|
@@ -10,7 +11,6 @@ export class GlovesLinkServer {
|
|
|
10
11
|
wss;
|
|
11
12
|
opts;
|
|
12
13
|
initStatusTemp = {};
|
|
13
|
-
rooms = new Map();
|
|
14
14
|
namespaces = new Map();
|
|
15
15
|
/**
|
|
16
16
|
* Creates a new GlovesLinkServer instance
|
|
@@ -19,11 +19,12 @@ export class GlovesLinkServer {
|
|
|
19
19
|
constructor(opts) {
|
|
20
20
|
this.opts = {
|
|
21
21
|
logs: false,
|
|
22
|
+
statusTimeout: 10_000,
|
|
22
23
|
...opts
|
|
23
24
|
};
|
|
24
25
|
this.wss = new WebSocketServer({ noServer: true });
|
|
25
26
|
}
|
|
26
|
-
|
|
27
|
+
attachToHttpServer(server) {
|
|
27
28
|
server.on("upgrade", async (request, socket, head) => {
|
|
28
29
|
const headers = request.headers;
|
|
29
30
|
let socketSelfId;
|
|
@@ -35,7 +36,11 @@ export class GlovesLinkServer {
|
|
|
35
36
|
const { pathname } = url;
|
|
36
37
|
const namespace = this.namespaces.get(pathname);
|
|
37
38
|
if (!namespace) {
|
|
38
|
-
|
|
39
|
+
saveSocketStatus(this, {
|
|
40
|
+
socketSelfId,
|
|
41
|
+
namespace: pathname,
|
|
42
|
+
status: 404
|
|
43
|
+
});
|
|
39
44
|
socket.write("HTTP/1.1 404 Not Found\r\n\r\n");
|
|
40
45
|
socket.destroy();
|
|
41
46
|
return;
|
|
@@ -48,7 +53,12 @@ export class GlovesLinkServer {
|
|
|
48
53
|
};
|
|
49
54
|
const authResult = await namespace.authFn(authData);
|
|
50
55
|
if (!authResult || authResult.status !== 200) {
|
|
51
|
-
|
|
56
|
+
saveSocketStatus(this, {
|
|
57
|
+
socketSelfId,
|
|
58
|
+
namespace: pathname,
|
|
59
|
+
status: authResult?.status || 401,
|
|
60
|
+
msg: authResult?.msg || "Unauthorized"
|
|
61
|
+
});
|
|
52
62
|
socket.write("HTTP/1.1 401 Unauthorized\r\n\r\n");
|
|
53
63
|
socket.destroy();
|
|
54
64
|
return;
|
|
@@ -61,12 +71,21 @@ export class GlovesLinkServer {
|
|
|
61
71
|
glSocket.dataFormatType = type && ["json", "bin"].includes(type) ? type : "json";
|
|
62
72
|
if (typeof authResult.user === "object" && authResult.user !== null)
|
|
63
73
|
glSocket.user = authResult.user;
|
|
64
|
-
glSocket.
|
|
65
|
-
namespace
|
|
66
|
-
namespace.
|
|
74
|
+
glSocket.namespacePath = pathname;
|
|
75
|
+
glSocket.namespace = namespace;
|
|
76
|
+
namespace._room.join(glSocket);
|
|
77
|
+
const userId = authResult?.user?._id;
|
|
78
|
+
if (userId)
|
|
79
|
+
getRoom(namespace.users, userId).join(glSocket);
|
|
80
|
+
namespace._onConnectHandler(glSocket, authData, authResult);
|
|
67
81
|
ws.on("close", () => {
|
|
68
|
-
glSocket.handlers
|
|
69
|
-
namespace.
|
|
82
|
+
glSocket.handlers.emit("disconnect");
|
|
83
|
+
namespace._room.leave(glSocket);
|
|
84
|
+
glSocket.leaveAllRooms();
|
|
85
|
+
if (userId) {
|
|
86
|
+
const room = getRoom(namespace.users, userId);
|
|
87
|
+
room.leave(glSocket);
|
|
88
|
+
}
|
|
70
89
|
});
|
|
71
90
|
});
|
|
72
91
|
}
|
|
@@ -75,32 +94,16 @@ export class GlovesLinkServer {
|
|
|
75
94
|
console.error("[GlovesLinkServer]", err);
|
|
76
95
|
if (this.opts.logs)
|
|
77
96
|
console.warn("[ws auth] Error during authentication:", err);
|
|
78
|
-
|
|
97
|
+
saveSocketStatus(this, {
|
|
98
|
+
socketSelfId,
|
|
99
|
+
namespace: "/",
|
|
100
|
+
status: 500
|
|
101
|
+
});
|
|
79
102
|
socket.write("HTTP/1.1 500 Internal Server Error\r\n\r\n");
|
|
80
103
|
socket.destroy();
|
|
81
104
|
}
|
|
82
105
|
});
|
|
83
106
|
}
|
|
84
|
-
/**
|
|
85
|
-
* Saves the status of a socket connection for temporary tracking
|
|
86
|
-
* @param socketSelfId - The ID of the socket
|
|
87
|
-
* @param namespace - The namespace of the socket
|
|
88
|
-
* @param status - The status code to save
|
|
89
|
-
* @param msg - Optional message to save with the status
|
|
90
|
-
* @private
|
|
91
|
-
*/
|
|
92
|
-
saveSocketStatus(socketSelfId, namespace, status, msg) {
|
|
93
|
-
if (!socketSelfId)
|
|
94
|
-
return;
|
|
95
|
-
const id = namespace + "-" + socketSelfId;
|
|
96
|
-
this.initStatusTemp[id] = {
|
|
97
|
-
status,
|
|
98
|
-
msg
|
|
99
|
-
};
|
|
100
|
-
setTimeout(() => {
|
|
101
|
-
delete this.initStatusTemp[id];
|
|
102
|
-
}, 10_000);
|
|
103
|
-
}
|
|
104
107
|
/**
|
|
105
108
|
* Gets or creates a namespace by path
|
|
106
109
|
* @param path - The path for the namespace
|
|
@@ -127,12 +130,12 @@ export class GlovesLinkServer {
|
|
|
127
130
|
room.emit(event, ...args);
|
|
128
131
|
}
|
|
129
132
|
/**
|
|
130
|
-
* Gets or creates a room by name
|
|
133
|
+
* Gets or creates a room by name (from the root namespace)
|
|
131
134
|
* @param name - The name of the room
|
|
132
135
|
* @returns The room instance
|
|
133
136
|
*/
|
|
134
137
|
room(name) {
|
|
135
|
-
return this.
|
|
138
|
+
return this.of("/").room(name);
|
|
136
139
|
}
|
|
137
140
|
/**
|
|
138
141
|
* Emits an event to the socket associated with the specified user ID
|
|
@@ -143,48 +146,6 @@ export class GlovesLinkServer {
|
|
|
143
146
|
emitToUserId(userId, event, ...args) {
|
|
144
147
|
this.namespaces.forEach((ns) => ns.emitToUserId(userId, event, ...args));
|
|
145
148
|
}
|
|
146
|
-
/**
|
|
147
|
-
* Creates a router for handling status requests
|
|
148
|
-
* @returns A router instance for status endpoints
|
|
149
|
-
*/
|
|
150
|
-
statusRouter() {
|
|
151
|
-
const router = new Router();
|
|
152
|
-
router.get("/status", (req, res) => {
|
|
153
|
-
const id = req.query.id;
|
|
154
|
-
if (!id) {
|
|
155
|
-
res.status(400).json({ err: true, msg: "No id provided" });
|
|
156
|
-
return;
|
|
157
|
-
}
|
|
158
|
-
const path = req.query.path;
|
|
159
|
-
if (!path) {
|
|
160
|
-
res.status(400).json({ err: true, msg: "No path provided" });
|
|
161
|
-
return;
|
|
162
|
-
}
|
|
163
|
-
const status = this.initStatusTemp[path + "-" + id];
|
|
164
|
-
if (status === undefined) {
|
|
165
|
-
res.status(404).json({ err: true, msg: "Socket not found" });
|
|
166
|
-
return;
|
|
167
|
-
}
|
|
168
|
-
res.json({ status });
|
|
169
|
-
delete this.initStatusTemp[id];
|
|
170
|
-
});
|
|
171
|
-
return router;
|
|
172
|
-
}
|
|
173
|
-
/**
|
|
174
|
-
* Creates a router for serving client files
|
|
175
|
-
* @param clientDir - Optional directory path for client files, defaults to node_modules/@wxn0brp/gloves-link-client/dist/
|
|
176
|
-
* @returns A router instance for client file serving
|
|
177
|
-
*/
|
|
178
|
-
clientRouter(clientDir) {
|
|
179
|
-
const router = new Router();
|
|
180
|
-
clientDir = clientDir || "node_modules/@wxn0brp/gloves-link-client/dist/";
|
|
181
|
-
router.static("/", clientDir);
|
|
182
|
-
router.get("/*", (req, res) => {
|
|
183
|
-
res.redirect("/gloves-link/GlovesLinkClient.js");
|
|
184
|
-
res.end();
|
|
185
|
-
});
|
|
186
|
-
return router;
|
|
187
|
-
}
|
|
188
149
|
/**
|
|
189
150
|
* Integrates the GlovesLink server with a FalconFrame application
|
|
190
151
|
* @param app - The FalconFrame application instance
|
|
@@ -193,9 +154,9 @@ export class GlovesLinkServer {
|
|
|
193
154
|
falconFrame(app, clientDir) {
|
|
194
155
|
const router = new Router();
|
|
195
156
|
app.use("/gloves-link", router);
|
|
196
|
-
router.use(
|
|
157
|
+
router.use(statusRouter());
|
|
197
158
|
if (clientDir !== false)
|
|
198
|
-
router.use(
|
|
159
|
+
router.use(clientRouter(clientDir));
|
|
199
160
|
}
|
|
200
161
|
}
|
|
201
162
|
export { GLSocket, Namespace };
|
package/dist/namespace.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { GlovesLinkServer } from "./index.js";
|
|
2
|
-
import { Room } from "./room.js";
|
|
2
|
+
import { Room, Rooms } from "./room.js";
|
|
3
3
|
import { GLSocket } from "./socket.js";
|
|
4
4
|
import { AuthFn, OnConnect } from "./types.js";
|
|
5
5
|
/**
|
|
@@ -8,9 +8,11 @@ import { AuthFn, OnConnect } from "./types.js";
|
|
|
8
8
|
export declare class Namespace {
|
|
9
9
|
name: string;
|
|
10
10
|
private server;
|
|
11
|
-
|
|
11
|
+
_onConnectHandler: OnConnect;
|
|
12
12
|
authFn: AuthFn;
|
|
13
|
-
|
|
13
|
+
_room: Room;
|
|
14
|
+
rooms: Rooms;
|
|
15
|
+
users: Rooms;
|
|
14
16
|
/**
|
|
15
17
|
* Creates a new Namespace instance
|
|
16
18
|
* @param name - The name of the namespace
|
|
@@ -29,17 +31,18 @@ export declare class Namespace {
|
|
|
29
31
|
* @returns The current Namespace instance for chaining
|
|
30
32
|
*/
|
|
31
33
|
auth(authFn: AuthFn): this;
|
|
32
|
-
/**
|
|
33
|
-
* Gets the connection event handler for this namespace
|
|
34
|
-
* @returns The connection event handler function
|
|
35
|
-
*/
|
|
36
|
-
get onConnectHandler(): OnConnect;
|
|
37
34
|
/**
|
|
38
35
|
* Emits an event to all sockets in the namespace's room
|
|
39
36
|
* @param event - The event name to emit
|
|
40
37
|
* @param args - The arguments to pass with the event
|
|
41
38
|
*/
|
|
42
39
|
emit(event: string, ...args: any[]): void;
|
|
40
|
+
/**
|
|
41
|
+
* Gets or creates a room by name
|
|
42
|
+
* @param name - The name of the room to get or create
|
|
43
|
+
* @returns The Room instance
|
|
44
|
+
*/
|
|
45
|
+
room(name: string): Room;
|
|
43
46
|
/**
|
|
44
47
|
* Emits an event to all sockets in the namespace's room except the specified socket
|
|
45
48
|
* @param socket - The socket to exclude from the emission
|
package/dist/namespace.js
CHANGED
|
@@ -1,12 +1,15 @@
|
|
|
1
|
+
import { getRoom, Room } from "./room.js";
|
|
1
2
|
/**
|
|
2
3
|
* Namespace class represents a logical grouping of sockets that can communicate with each other
|
|
3
4
|
*/
|
|
4
5
|
export class Namespace {
|
|
5
6
|
name;
|
|
6
7
|
server;
|
|
7
|
-
|
|
8
|
+
_onConnectHandler = () => { };
|
|
8
9
|
authFn = async () => ({ status: 200 });
|
|
9
|
-
|
|
10
|
+
_room = new Room();
|
|
11
|
+
rooms = new Map();
|
|
12
|
+
users = new Map();
|
|
10
13
|
/**
|
|
11
14
|
* Creates a new Namespace instance
|
|
12
15
|
* @param name - The name of the namespace
|
|
@@ -15,8 +18,6 @@ export class Namespace {
|
|
|
15
18
|
constructor(name, server) {
|
|
16
19
|
this.name = name;
|
|
17
20
|
this.server = server;
|
|
18
|
-
const roomName = `gls-namespace-${name}`;
|
|
19
|
-
this.room = this.server.room(roomName);
|
|
20
21
|
}
|
|
21
22
|
/**
|
|
22
23
|
* Sets the connection event handler for this namespace
|
|
@@ -24,7 +25,7 @@ export class Namespace {
|
|
|
24
25
|
* @returns The current Namespace instance for chaining
|
|
25
26
|
*/
|
|
26
27
|
onConnect(handler) {
|
|
27
|
-
this.
|
|
28
|
+
this._onConnectHandler = handler;
|
|
28
29
|
return this;
|
|
29
30
|
}
|
|
30
31
|
/**
|
|
@@ -36,20 +37,21 @@ export class Namespace {
|
|
|
36
37
|
this.authFn = authFn;
|
|
37
38
|
return this;
|
|
38
39
|
}
|
|
39
|
-
/**
|
|
40
|
-
* Gets the connection event handler for this namespace
|
|
41
|
-
* @returns The connection event handler function
|
|
42
|
-
*/
|
|
43
|
-
get onConnectHandler() {
|
|
44
|
-
return this.onConnectEvent;
|
|
45
|
-
}
|
|
46
40
|
/**
|
|
47
41
|
* Emits an event to all sockets in the namespace's room
|
|
48
42
|
* @param event - The event name to emit
|
|
49
43
|
* @param args - The arguments to pass with the event
|
|
50
44
|
*/
|
|
51
45
|
emit(event, ...args) {
|
|
52
|
-
this.
|
|
46
|
+
this._room.emit(event, ...args);
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Gets or creates a room by name
|
|
50
|
+
* @param name - The name of the room to get or create
|
|
51
|
+
* @returns The Room instance
|
|
52
|
+
*/
|
|
53
|
+
room(name) {
|
|
54
|
+
return getRoom(this.rooms, name);
|
|
53
55
|
}
|
|
54
56
|
/**
|
|
55
57
|
* Emits an event to all sockets in the namespace's room except the specified socket
|
|
@@ -58,7 +60,7 @@ export class Namespace {
|
|
|
58
60
|
* @param args - The arguments to pass with the event
|
|
59
61
|
*/
|
|
60
62
|
emitWithoutSelf(socket, event, ...args) {
|
|
61
|
-
this.
|
|
63
|
+
this._room.emitWithoutSelf(socket, event, ...args);
|
|
62
64
|
}
|
|
63
65
|
/**
|
|
64
66
|
* Emits an event to the socket associated with the specified user ID
|
|
@@ -67,6 +69,6 @@ export class Namespace {
|
|
|
67
69
|
* @param args - The arguments to pass with the event
|
|
68
70
|
*/
|
|
69
71
|
emitToUserId(userId, event, ...args) {
|
|
70
|
-
this.
|
|
72
|
+
this.users.get(userId)?.emit(event, ...args);
|
|
71
73
|
}
|
|
72
74
|
}
|
package/dist/room.d.ts
CHANGED
|
@@ -66,19 +66,9 @@ export declare class Room {
|
|
|
66
66
|
has(socket: GLSocket): boolean;
|
|
67
67
|
}
|
|
68
68
|
/**
|
|
69
|
-
*
|
|
70
|
-
* @param
|
|
71
|
-
* @param name - The name of the room to
|
|
69
|
+
* Gets or creates a room by name
|
|
70
|
+
* @param rooms - The map of rooms to search in
|
|
71
|
+
* @param name - The name of the room to get or create
|
|
72
|
+
* @returns The Room instance
|
|
72
73
|
*/
|
|
73
|
-
export declare function
|
|
74
|
-
/**
|
|
75
|
-
* Removes a socket from a room by name
|
|
76
|
-
* @param socket - The socket to remove from the room
|
|
77
|
-
* @param roomName - The name of the room to leave
|
|
78
|
-
*/
|
|
79
|
-
export declare function leaveSocketFromRoom(socket: GLSocket, roomName: string): void;
|
|
80
|
-
/**
|
|
81
|
-
* Removes a socket from all rooms it has joined
|
|
82
|
-
* @param socket - The socket to remove from all rooms
|
|
83
|
-
*/
|
|
84
|
-
export declare function leaveAllSocketFromRoom(socket: GLSocket): void;
|
|
74
|
+
export declare function getRoom(rooms: Rooms, name: string): Room;
|
package/dist/room.js
CHANGED
|
@@ -11,6 +11,7 @@ export class Room {
|
|
|
11
11
|
*/
|
|
12
12
|
join(socket) {
|
|
13
13
|
this._clients.add(socket);
|
|
14
|
+
socket.rooms.add(this);
|
|
14
15
|
this.eventEmitter.emit("join", socket, this);
|
|
15
16
|
}
|
|
16
17
|
/**
|
|
@@ -19,14 +20,20 @@ export class Room {
|
|
|
19
20
|
*/
|
|
20
21
|
leave(socket) {
|
|
21
22
|
this._clients.delete(socket);
|
|
23
|
+
socket.rooms.delete(this);
|
|
22
24
|
this.eventEmitter.emit("leave", socket, this);
|
|
25
|
+
if (this._clients.size === 0)
|
|
26
|
+
this.eventEmitter.emit("empty", this);
|
|
23
27
|
}
|
|
24
28
|
/**
|
|
25
29
|
* Removes all sockets from the room
|
|
26
30
|
*/
|
|
27
31
|
leaveAll() {
|
|
32
|
+
for (const socket of this._clients)
|
|
33
|
+
socket.rooms.delete(this);
|
|
28
34
|
this._clients.clear();
|
|
29
35
|
this.eventEmitter.emit("leaveAll", this);
|
|
36
|
+
this.eventEmitter.emit("empty", this);
|
|
30
37
|
}
|
|
31
38
|
/**
|
|
32
39
|
* Registers a handler for when a socket joins the room
|
|
@@ -93,36 +100,17 @@ export class Room {
|
|
|
93
100
|
}
|
|
94
101
|
}
|
|
95
102
|
/**
|
|
96
|
-
*
|
|
97
|
-
* @param
|
|
98
|
-
* @param name - The name of the room to
|
|
103
|
+
* Gets or creates a room by name
|
|
104
|
+
* @param rooms - The map of rooms to search in
|
|
105
|
+
* @param name - The name of the room to get or create
|
|
106
|
+
* @returns The Room instance
|
|
99
107
|
*/
|
|
100
|
-
export function
|
|
101
|
-
const
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
* @param roomName - The name of the room to leave
|
|
109
|
-
*/
|
|
110
|
-
export function leaveSocketFromRoom(socket, roomName) {
|
|
111
|
-
const rooms = socket.server.rooms;
|
|
112
|
-
const room = rooms.get(roomName);
|
|
113
|
-
if (!room)
|
|
114
|
-
return;
|
|
115
|
-
room.leave(socket);
|
|
116
|
-
if (room.size > 0)
|
|
117
|
-
return;
|
|
118
|
-
rooms.delete(roomName);
|
|
119
|
-
}
|
|
120
|
-
/**
|
|
121
|
-
* Removes a socket from all rooms it has joined
|
|
122
|
-
* @param socket - The socket to remove from all rooms
|
|
123
|
-
*/
|
|
124
|
-
export function leaveAllSocketFromRoom(socket) {
|
|
125
|
-
const rooms = socket.server.rooms;
|
|
126
|
-
for (const room of rooms.values())
|
|
127
|
-
room.leave(socket);
|
|
108
|
+
export function getRoom(rooms, name) {
|
|
109
|
+
const existedRoom = rooms.get(name);
|
|
110
|
+
if (existedRoom)
|
|
111
|
+
return existedRoom;
|
|
112
|
+
const createdRoom = new Room();
|
|
113
|
+
rooms.set(name, createdRoom);
|
|
114
|
+
createdRoom.eventEmitter.on("empty", () => rooms.delete(name));
|
|
115
|
+
return createdRoom;
|
|
128
116
|
}
|
package/dist/socket.d.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { WebSocket } from "ws";
|
|
2
|
-
import { GlovesLinkServer } from "./index.js";
|
|
2
|
+
import { GlovesLinkServer, Namespace } from "./index.js";
|
|
3
|
+
import { Room } from "./room.js";
|
|
3
4
|
import { AuthFnResult, Server_Auth_Opts } from "./types.js";
|
|
5
|
+
import EventEmitter from "events";
|
|
4
6
|
/**
|
|
5
7
|
* GLSocket class represents a WebSocket connection with additional functionality
|
|
6
8
|
* @template T - The type of user data associated with the socket
|
|
@@ -12,14 +14,13 @@ export declare class GLSocket<T = {
|
|
|
12
14
|
server: GlovesLinkServer;
|
|
13
15
|
id: string;
|
|
14
16
|
user: T;
|
|
15
|
-
|
|
17
|
+
namespacePath: string;
|
|
18
|
+
namespace: Namespace;
|
|
19
|
+
rooms: Set<Room>;
|
|
16
20
|
ackIdCounter: number;
|
|
17
21
|
ackCallbacks: Map<number, Function>;
|
|
18
22
|
logs: boolean;
|
|
19
|
-
handlers:
|
|
20
|
-
[key: string]: Function;
|
|
21
|
-
};
|
|
22
|
-
rooms: Set<string>;
|
|
23
|
+
handlers: EventEmitter<any>;
|
|
23
24
|
authData: Server_Auth_Opts;
|
|
24
25
|
authResult: AuthFnResult;
|
|
25
26
|
dataFormatType: "json" | "bin";
|
|
@@ -57,41 +58,25 @@ export declare class GLSocket<T = {
|
|
|
57
58
|
/**
|
|
58
59
|
* Closes the WebSocket connection
|
|
59
60
|
*/
|
|
60
|
-
|
|
61
|
+
disconnect(): void;
|
|
61
62
|
/**
|
|
62
63
|
* Joins the socket to a room
|
|
63
64
|
* @param roomName - The name of the room to join
|
|
64
65
|
*/
|
|
65
|
-
joinRoom(
|
|
66
|
+
joinRoom(roomOrName: Room | string): void;
|
|
66
67
|
/**
|
|
67
68
|
* Removes the socket from a room
|
|
68
69
|
* @param roomName - The name of the room to leave
|
|
69
70
|
*/
|
|
70
|
-
leaveRoom(
|
|
71
|
+
leaveRoom(roomOrName: Room | string): void;
|
|
71
72
|
/**
|
|
72
73
|
* Removes the socket from all rooms it has joined
|
|
73
74
|
*/
|
|
74
75
|
leaveAllRooms(): void;
|
|
75
76
|
/**
|
|
76
|
-
* Gets
|
|
77
|
-
* @
|
|
78
|
-
|
|
79
|
-
getNamespace(): import("./namespace.js").Namespace;
|
|
80
|
-
/**
|
|
81
|
-
* Gets the room associated with this socket's namespace
|
|
82
|
-
* @returns The room object or undefined if namespace is not found
|
|
83
|
-
*/
|
|
84
|
-
namespaceRoom(): import("./room.js").Room;
|
|
85
|
-
/**
|
|
86
|
-
* Gets a room from the server by name
|
|
87
|
-
* @param roomName - The name of the room to retrieve
|
|
88
|
-
* @returns The room object
|
|
89
|
-
*/
|
|
90
|
-
serverRoom(roomName: string): import("./room.js").Room;
|
|
91
|
-
/**
|
|
92
|
-
* Gets all rooms from the server
|
|
93
|
-
* @returns A map of all rooms on the server
|
|
77
|
+
* Gets a room by name
|
|
78
|
+
* @param name - The name of the room to get
|
|
79
|
+
* @returns The room object or undefined if not found
|
|
94
80
|
*/
|
|
95
|
-
|
|
96
|
-
disconnect(): void;
|
|
81
|
+
room(name: string): Room;
|
|
97
82
|
}
|
package/dist/socket.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
1
|
+
import { parse, stringify } from "./transport.js";
|
|
2
|
+
import EventEmitter from "events";
|
|
3
3
|
/**
|
|
4
4
|
* GLSocket class represents a WebSocket connection with additional functionality
|
|
5
5
|
* @template T - The type of user data associated with the socket
|
|
@@ -9,12 +9,13 @@ export class GLSocket {
|
|
|
9
9
|
server;
|
|
10
10
|
id;
|
|
11
11
|
user;
|
|
12
|
+
namespacePath;
|
|
12
13
|
namespace;
|
|
14
|
+
rooms = new Set();
|
|
13
15
|
ackIdCounter = 1;
|
|
14
16
|
ackCallbacks = new Map();
|
|
15
17
|
logs = false;
|
|
16
|
-
handlers;
|
|
17
|
-
rooms = new Set();
|
|
18
|
+
handlers = new EventEmitter();
|
|
18
19
|
authData;
|
|
19
20
|
authResult;
|
|
20
21
|
dataFormatType = "json";
|
|
@@ -29,7 +30,6 @@ export class GLSocket {
|
|
|
29
30
|
this.server = server;
|
|
30
31
|
this.id = id || Date.now().toString(36) + Math.random().toString(36).substring(2, 10);
|
|
31
32
|
this.user = { _id: this.id };
|
|
32
|
-
this.handlers = {};
|
|
33
33
|
this.ws.on("message", (raw) => this._handle(raw.toString()));
|
|
34
34
|
}
|
|
35
35
|
/**
|
|
@@ -78,7 +78,7 @@ export class GLSocket {
|
|
|
78
78
|
* @param handler - The function to be called when the event is received
|
|
79
79
|
*/
|
|
80
80
|
on(evt, handler) {
|
|
81
|
-
this.handlers
|
|
81
|
+
this.handlers.on(evt, handler);
|
|
82
82
|
}
|
|
83
83
|
/**
|
|
84
84
|
* Sends an event to the connected WebSocket client
|
|
@@ -114,110 +114,38 @@ export class GLSocket {
|
|
|
114
114
|
/**
|
|
115
115
|
* Closes the WebSocket connection
|
|
116
116
|
*/
|
|
117
|
-
|
|
117
|
+
disconnect() {
|
|
118
118
|
this.ws.close();
|
|
119
119
|
}
|
|
120
120
|
/**
|
|
121
121
|
* Joins the socket to a room
|
|
122
122
|
* @param roomName - The name of the room to join
|
|
123
123
|
*/
|
|
124
|
-
joinRoom(
|
|
125
|
-
|
|
126
|
-
|
|
124
|
+
joinRoom(roomOrName) {
|
|
125
|
+
const room = typeof roomOrName === "string" ? this.room(roomOrName) : roomOrName;
|
|
126
|
+
room.join(this);
|
|
127
127
|
}
|
|
128
128
|
/**
|
|
129
129
|
* Removes the socket from a room
|
|
130
130
|
* @param roomName - The name of the room to leave
|
|
131
131
|
*/
|
|
132
|
-
leaveRoom(
|
|
133
|
-
|
|
134
|
-
|
|
132
|
+
leaveRoom(roomOrName) {
|
|
133
|
+
const room = typeof roomOrName === "string" ? this.room(roomOrName) : roomOrName;
|
|
134
|
+
room.leave(this);
|
|
135
135
|
}
|
|
136
136
|
/**
|
|
137
137
|
* Removes the socket from all rooms it has joined
|
|
138
138
|
*/
|
|
139
139
|
leaveAllRooms() {
|
|
140
|
-
for (const
|
|
141
|
-
|
|
142
|
-
}
|
|
143
|
-
this.rooms.clear();
|
|
144
|
-
}
|
|
145
|
-
/**
|
|
146
|
-
* Gets the namespace associated with this socket
|
|
147
|
-
* @returns The namespace object or undefined if not found
|
|
148
|
-
*/
|
|
149
|
-
getNamespace() {
|
|
150
|
-
return this.server.namespaces.get(this.namespace);
|
|
140
|
+
for (const room of this.rooms.values())
|
|
141
|
+
room.leave(this);
|
|
151
142
|
}
|
|
152
143
|
/**
|
|
153
|
-
* Gets
|
|
154
|
-
* @
|
|
144
|
+
* Gets a room by name
|
|
145
|
+
* @param name - The name of the room to get
|
|
146
|
+
* @returns The room object or undefined if not found
|
|
155
147
|
*/
|
|
156
|
-
|
|
157
|
-
return this.
|
|
148
|
+
room(name) {
|
|
149
|
+
return this.namespace.room(name);
|
|
158
150
|
}
|
|
159
|
-
/**
|
|
160
|
-
* Gets a room from the server by name
|
|
161
|
-
* @param roomName - The name of the room to retrieve
|
|
162
|
-
* @returns The room object
|
|
163
|
-
*/
|
|
164
|
-
serverRoom(roomName) {
|
|
165
|
-
return this.server.room(roomName);
|
|
166
|
-
}
|
|
167
|
-
/**
|
|
168
|
-
* Gets all rooms from the server
|
|
169
|
-
* @returns A map of all rooms on the server
|
|
170
|
-
*/
|
|
171
|
-
serverRooms() {
|
|
172
|
-
return this.server.rooms;
|
|
173
|
-
}
|
|
174
|
-
disconnect() {
|
|
175
|
-
this.ws.close();
|
|
176
|
-
}
|
|
177
|
-
}
|
|
178
|
-
function parse(type, raw) {
|
|
179
|
-
if (type === "json") {
|
|
180
|
-
try {
|
|
181
|
-
return JSON.parse(raw);
|
|
182
|
-
}
|
|
183
|
-
catch {
|
|
184
|
-
return null;
|
|
185
|
-
}
|
|
186
|
-
}
|
|
187
|
-
try {
|
|
188
|
-
const [evt, ack, ackIdsString, ...contentString] = raw.split(DELIMITER);
|
|
189
|
-
const contents = contentString.map(value => {
|
|
190
|
-
try {
|
|
191
|
-
return JSON.parse(value);
|
|
192
|
-
}
|
|
193
|
-
catch {
|
|
194
|
-
return value;
|
|
195
|
-
}
|
|
196
|
-
});
|
|
197
|
-
if (ack) {
|
|
198
|
-
return {
|
|
199
|
-
ack: Number(ack),
|
|
200
|
-
data: contents,
|
|
201
|
-
};
|
|
202
|
-
}
|
|
203
|
-
const ackIds = ackIdsString.split(",").filter(Boolean).map(Number);
|
|
204
|
-
return {
|
|
205
|
-
evt,
|
|
206
|
-
ackI: ackIds,
|
|
207
|
-
data: contents,
|
|
208
|
-
};
|
|
209
|
-
}
|
|
210
|
-
catch {
|
|
211
|
-
return null;
|
|
212
|
-
}
|
|
213
|
-
}
|
|
214
|
-
function stringify(type, data) {
|
|
215
|
-
if (type === "json")
|
|
216
|
-
return JSON.stringify(data);
|
|
217
|
-
return [
|
|
218
|
-
data.evt ?? "",
|
|
219
|
-
(data.ack ?? ""),
|
|
220
|
-
(data.ackI || []).join(","),
|
|
221
|
-
...data.data.map(JSON.stringify)
|
|
222
|
-
].join(DELIMITER);
|
|
223
151
|
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
const DELIMITER = process.env.GLOVES_LINK_DELIMITER || "\b";
|
|
2
|
+
export function parse(type, raw) {
|
|
3
|
+
if (type === "json") {
|
|
4
|
+
try {
|
|
5
|
+
return JSON.parse(raw);
|
|
6
|
+
}
|
|
7
|
+
catch {
|
|
8
|
+
return null;
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
try {
|
|
12
|
+
const [evt, ack, ackIdsString, ...contentString] = raw.split(DELIMITER);
|
|
13
|
+
const contents = contentString.map(value => {
|
|
14
|
+
try {
|
|
15
|
+
return JSON.parse(value);
|
|
16
|
+
}
|
|
17
|
+
catch {
|
|
18
|
+
return value;
|
|
19
|
+
}
|
|
20
|
+
});
|
|
21
|
+
if (ack) {
|
|
22
|
+
return {
|
|
23
|
+
ack: Number(ack),
|
|
24
|
+
data: contents,
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
const ackIds = ackIdsString.split(",").filter(Boolean).map(Number);
|
|
28
|
+
return {
|
|
29
|
+
evt,
|
|
30
|
+
ackI: ackIds,
|
|
31
|
+
data: contents,
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
catch {
|
|
35
|
+
return null;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
export function stringify(type, data) {
|
|
39
|
+
if (type === "json")
|
|
40
|
+
return JSON.stringify(data);
|
|
41
|
+
return [
|
|
42
|
+
data.evt ?? "",
|
|
43
|
+
(data.ack ?? ""),
|
|
44
|
+
(data.ackI || []).join(","),
|
|
45
|
+
...data.data.map(JSON.stringify)
|
|
46
|
+
].join(DELIMITER);
|
|
47
|
+
}
|
package/dist/types.d.ts
CHANGED
|
@@ -3,6 +3,7 @@ import Stream from "stream";
|
|
|
3
3
|
import { GLSocket } from "./socket.js";
|
|
4
4
|
export interface Server_Opts {
|
|
5
5
|
logs: boolean;
|
|
6
|
+
statusTimeout: number;
|
|
6
7
|
}
|
|
7
8
|
export interface Server_DataEvent {
|
|
8
9
|
evt: string;
|
|
@@ -30,3 +31,9 @@ export interface AuthFnResult {
|
|
|
30
31
|
}
|
|
31
32
|
export type AuthFn = (data: Server_Auth_Opts) => Promise<AuthFnResult>;
|
|
32
33
|
export type OnConnect = (socket: GLSocket, auth: Server_Auth_Opts, result: AuthFnResult) => void;
|
|
34
|
+
export interface SocketStatus {
|
|
35
|
+
socketSelfId: string;
|
|
36
|
+
namespace: string;
|
|
37
|
+
status: number;
|
|
38
|
+
msg?: string;
|
|
39
|
+
}
|