@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 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, { Router } from "@wxn0brp/falcon-frame";
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, Rooms } from "./room.js";
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
- createServer(server: http.Server): void;
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 { Room } from "./room.js";
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
- createServer(server) {
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
- this.saveSocketStatus(socketSelfId, pathname, 404);
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
- this.saveSocketStatus(socketSelfId, pathname, authResult?.status || 401, authResult?.msg || "Unauthorized");
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.namespace = pathname;
65
- namespace.room.join(glSocket);
66
- namespace.onConnectHandler(glSocket, authData, authResult);
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?.disconnect?.();
69
- namespace.room.leave(glSocket);
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
- this.saveSocketStatus(socketSelfId, "/", 500);
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.rooms.get(name) || this.rooms.set(name, new Room()).get(name);
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(this.statusRouter());
157
+ router.use(statusRouter());
197
158
  if (clientDir !== false)
198
- router.use(this.clientRouter(clientDir));
159
+ router.use(clientRouter(clientDir));
199
160
  }
200
161
  }
201
162
  export { GLSocket, Namespace };
@@ -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
- private onConnectEvent;
11
+ _onConnectHandler: OnConnect;
12
12
  authFn: AuthFn;
13
- room: Room;
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
- onConnectEvent = () => { };
8
+ _onConnectHandler = () => { };
8
9
  authFn = async () => ({ status: 200 });
9
- room;
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.onConnectEvent = handler;
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.room.emit(event, ...args);
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.room.emitWithoutSelf(socket, event, ...args);
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.room.sockets.forEach(socket => socket.user?._id && socket.user._id === userId && socket.emit(event, ...args));
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
- * Adds a socket to a room by name, creating the room if it doesn't exist
70
- * @param socket - The socket to add to the room
71
- * @param name - The name of the room to join
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 joinSocketToRoom(socket: GLSocket, name: string): void;
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
- * Adds a socket to a room by name, creating the room if it doesn't exist
97
- * @param socket - The socket to add to the room
98
- * @param name - The name of the room to join
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 joinSocketToRoom(socket, name) {
101
- const rooms = socket.server.rooms;
102
- const room = rooms.get(name) || rooms.set(name, new Room()).get(name);
103
- room.join(socket);
104
- }
105
- /**
106
- * Removes a socket from a room by name
107
- * @param socket - The socket to remove from the room
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
- namespace: string;
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
- close(): void;
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(roomName: string): void;
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(roomName: string): void;
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 the namespace associated with this socket
77
- * @returns The namespace object or undefined if not found
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
- serverRooms(): import("./room.js").Rooms;
96
- disconnect(): void;
81
+ room(name: string): Room;
97
82
  }
package/dist/socket.js CHANGED
@@ -1,5 +1,5 @@
1
- import { joinSocketToRoom, leaveSocketFromRoom } from "./room.js";
2
- const DELIMITER = process.env.GLOVES_LINK_DELIMITER || "\b";
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[evt] = handler;
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
- close() {
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(roomName) {
125
- joinSocketToRoom(this, roomName);
126
- this.rooms.add(roomName);
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(roomName) {
133
- leaveSocketFromRoom(this, roomName);
134
- this.rooms.delete(roomName);
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 roomName of this.rooms) {
141
- leaveSocketFromRoom(this, roomName);
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 the room associated with this socket's namespace
154
- * @returns The room object or undefined if namespace is not found
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
- namespaceRoom() {
157
- return this.getNamespace()?.room;
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,3 @@
1
+ import { Server_AckEvent, Server_DataEvent } from "./types.js";
2
+ export declare function parse(type: string, raw: string): Server_DataEvent | Server_AckEvent;
3
+ export declare function stringify(type: "json" | "bin", data: any): string;
@@ -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
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wxn0brp/gloves-link-server",
3
- "version": "0.0.14",
3
+ "version": "0.1.0-beta.0",
4
4
  "main": "dist/index.js",
5
5
  "types": "dist/index.d.ts",
6
6
  "author": "wxn0brP",