@wxn0brp/gloves-link-server 0.0.3 → 0.0.5

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 ADDED
@@ -0,0 +1,63 @@
1
+ # GlovesLink
2
+
3
+ GlovesLink is a WebSocket communication library designed for seamless interaction between clients and servers.
4
+
5
+ [Main repo](https://github.com/wxn0brP/GlovesLink) |
6
+ [Client repo](https://github.com/wxn0brP/GlovesLink-client) |
7
+ [Server repo](https://github.com/wxn0brP/GlovesLink-server)
8
+
9
+ ## Features
10
+
11
+ ### General
12
+ - **WebSocket Communication**: Establish real-time communication between clients and servers.
13
+ - **Automatic Reconnection**: Automatically reconnects after disconnection.
14
+ - **Authentication Support**: Token-based authentication for secure connections.
15
+ - **Logging**: Optional logging for debugging and monitoring.
16
+ - **Rooms**: Organize communication within specific rooms for better organization and control.
17
+
18
+ ### Communication
19
+ - **Event Emission**: Send events with arbitrary data.
20
+ - **Callbacks**: Handle server/client responses with callback functions.
21
+
22
+ ## Installation
23
+
24
+ ```bash
25
+ npm i @wxn0brp/gloves-link-server @wxn0brp/falcon-frame
26
+ ```
27
+
28
+ ## Usage
29
+
30
+ ```typescript
31
+ import { GlovesLinkServer } from '@wxn0brp/gloves-link-server';
32
+ import { FalconFrame } from '@wxn0brp/falcon-frame';
33
+
34
+ const app = new FalconFrame();
35
+ const httpServer = app.listen(3000);
36
+
37
+ const glovesLink = new GlovesLinkServer({
38
+ server: httpServer,
39
+ logs: true,
40
+ authFn: async ({ headers, url, token }) => {
41
+ // Implement your authentication logic here
42
+ return true;
43
+ }
44
+ });
45
+ glovesLink.falconFrame(app);
46
+
47
+ glovesLink.onConnect((socket) => {
48
+ console.log('New connection:', socket.id);
49
+
50
+ socket.on('exampleEvent', (data) => {
51
+ console.log('Received data:', data);
52
+ socket.emit('response', 'Hello from server');
53
+ });
54
+ });
55
+ ```
56
+
57
+ ## License
58
+
59
+ MIT License
60
+
61
+ ## Contributing
62
+
63
+ Contributions are welcome!
package/dist/index.d.ts CHANGED
@@ -3,23 +3,21 @@ import { Server_Opts } from "./types.js";
3
3
  import { GLSocket } from "./socket.js";
4
4
  import FalconFrame from "@wxn0brp/falcon-frame";
5
5
  import { Room, Rooms } from "./room.js";
6
+ import { Namespace } from "./namespace.js";
6
7
  export declare class GlovesLinkServer {
7
8
  wss: WebSocketServer;
8
- private onConnectEvent;
9
9
  logs: boolean;
10
10
  opts: Server_Opts;
11
11
  initStatusTemp: {
12
12
  [key: string]: number;
13
13
  };
14
14
  rooms: Rooms;
15
- globalRoom: Room;
15
+ private namespaces;
16
16
  constructor(opts: Partial<Server_Opts>);
17
17
  private saveSocketStatus;
18
- onConnect(handler: (ws: GLSocket) => void): void;
19
- broadcast(event: string, ...args: any[]): void;
18
+ of(path: string): Namespace;
20
19
  broadcastRoom(roomName: string, event: string, ...args: any[]): void;
21
- broadcastWithoutSelf(socket: GLSocket, event: string, ...args: any[]): void;
22
20
  room(name: string): Room;
23
- falconFrame(app: FalconFrame, clientDir?: string): void;
21
+ falconFrame(app: FalconFrame, clientDir?: string | false): void;
24
22
  }
25
- export { GLSocket };
23
+ export { GLSocket, Namespace, Server_Opts };
package/dist/index.js CHANGED
@@ -2,19 +2,18 @@ import { WebSocketServer } from "ws";
2
2
  import { GLSocket } from "./socket.js";
3
3
  import { Router } from "@wxn0brp/falcon-frame";
4
4
  import { Room } from "./room.js";
5
+ import { Namespace } from "./namespace.js";
5
6
  export class GlovesLinkServer {
6
7
  wss;
7
- onConnectEvent;
8
8
  logs = false;
9
9
  opts;
10
10
  initStatusTemp = {};
11
11
  rooms = new Map();
12
- globalRoom = new Room();
12
+ namespaces = new Map();
13
13
  constructor(opts) {
14
14
  this.opts = {
15
15
  server: null,
16
16
  logs: false,
17
- authFn: () => true,
18
17
  ...opts
19
18
  };
20
19
  if (!this.opts?.server) {
@@ -29,9 +28,17 @@ export class GlovesLinkServer {
29
28
  const url = new URL(request.url, `http://${request.headers.host}`);
30
29
  const token = url.searchParams.get("token");
31
30
  socketSelfId = url.searchParams.get("id");
32
- const isAuthenticated = await this.opts.authFn({ headers, url, token });
33
- if (!isAuthenticated) {
34
- this.saveSocketStatus(socketSelfId, 401);
31
+ const { pathname } = url;
32
+ const namespace = this.namespaces.get(pathname);
33
+ if (!namespace) {
34
+ this.saveSocketStatus(socketSelfId, pathname, 404);
35
+ socket.write("HTTP/1.1 404 Not Found\r\n\r\n");
36
+ socket.destroy();
37
+ return;
38
+ }
39
+ const authResult = await namespace.authFn({ headers, url, token, request, socket, head });
40
+ if (!authResult) {
41
+ this.saveSocketStatus(socketSelfId, pathname, 401);
35
42
  socket.write("HTTP/1.1 401 Unauthorized\r\n\r\n");
36
43
  socket.destroy();
37
44
  return;
@@ -39,12 +46,14 @@ export class GlovesLinkServer {
39
46
  this.wss.handleUpgrade(request, socket, head, (ws) => {
40
47
  const glSocket = new GLSocket(ws, this);
41
48
  glSocket.logs = this.logs;
42
- this.globalRoom.join(glSocket);
43
- this.onConnectEvent(glSocket);
49
+ if (typeof authResult === "object" && authResult !== null)
50
+ glSocket.user = authResult;
51
+ glSocket.namespace = pathname;
52
+ namespace.room.join(glSocket);
53
+ namespace.onConnectHandler(glSocket);
44
54
  ws.on("close", () => {
45
55
  glSocket.handlers?.disconnect?.();
46
- glSocket.leaveAllRooms();
47
- this.globalRoom.leave(glSocket);
56
+ namespace.room.leave(glSocket);
48
57
  });
49
58
  });
50
59
  }
@@ -53,25 +62,28 @@ export class GlovesLinkServer {
53
62
  console.error("[GlovesLinkServer]", err);
54
63
  if (this.logs)
55
64
  console.warn("[auth] Error during authentication:", err);
56
- this.saveSocketStatus(socketSelfId, 500);
65
+ this.saveSocketStatus(socketSelfId, "/", 500);
57
66
  socket.write("HTTP/1.1 500 Internal Server Error\r\n\r\n");
58
67
  socket.destroy();
59
68
  }
60
69
  });
61
70
  }
62
- saveSocketStatus(socketSelfId, status) {
71
+ saveSocketStatus(socketSelfId, namespace, status) {
63
72
  if (!socketSelfId)
64
73
  return;
65
- this.initStatusTemp[socketSelfId] = status;
74
+ const id = namespace + "-" + socketSelfId;
75
+ this.initStatusTemp[id] = status;
66
76
  setTimeout(() => {
67
- delete this.initStatusTemp[socketSelfId];
77
+ delete this.initStatusTemp[id];
68
78
  }, 10_000);
69
79
  }
70
- onConnect(handler) {
71
- this.onConnectEvent = handler;
72
- }
73
- broadcast(event, ...args) {
74
- this.globalRoom.emit(event, ...args);
80
+ of(path) {
81
+ let namespace = this.namespaces.get(path);
82
+ if (!namespace) {
83
+ namespace = new Namespace(path, this);
84
+ this.namespaces.set(path, namespace);
85
+ }
86
+ return namespace;
75
87
  }
76
88
  broadcastRoom(roomName, event, ...args) {
77
89
  const room = this.room(roomName);
@@ -79,24 +91,24 @@ export class GlovesLinkServer {
79
91
  return;
80
92
  room.emit(event, ...args);
81
93
  }
82
- broadcastWithoutSelf(socket, event, ...args) {
83
- this.globalRoom.emitWithoutSelf(socket, event, ...args);
84
- }
85
94
  room(name) {
86
95
  return this.rooms.get(name) || this.rooms.set(name, new Room()).get(name);
87
96
  }
88
97
  falconFrame(app, clientDir) {
89
- clientDir = clientDir || "node_modules/@wxn0brp/gloves-link-client/dist/";
90
98
  const router = new Router();
91
99
  app.use("/gloves-link", router);
92
- router.static("/", clientDir);
93
100
  router.get("/status", (req, res) => {
94
101
  const id = req.query.id;
95
102
  if (!id) {
96
103
  res.status(400).json({ err: true, msg: "No id provided" });
97
104
  return;
98
105
  }
99
- const status = this.initStatusTemp[id];
106
+ const path = req.query.path;
107
+ if (!path) {
108
+ res.status(400).json({ err: true, msg: "No path provided" });
109
+ return;
110
+ }
111
+ const status = this.initStatusTemp[path + "-" + id];
100
112
  if (status === undefined) {
101
113
  res.status(404).json({ err: true, msg: "Socket not found" });
102
114
  return;
@@ -104,10 +116,14 @@ export class GlovesLinkServer {
104
116
  res.json({ status });
105
117
  delete this.initStatusTemp[id];
106
118
  });
119
+ if (clientDir === false)
120
+ return;
121
+ clientDir = clientDir || "node_modules/@wxn0brp/gloves-link-client/dist/";
122
+ router.static("/", clientDir);
107
123
  router.get("/*", (req, res) => {
108
124
  res.redirect("/gloves-link/GlovesLinkClient.js");
109
125
  res.end();
110
126
  });
111
127
  }
112
128
  }
113
- export { GLSocket };
129
+ export { GLSocket, Namespace };
@@ -0,0 +1,17 @@
1
+ import { AuthFn } from "./types.js";
2
+ import { GLSocket } from "./socket.js";
3
+ import { Room } from "./room.js";
4
+ import { GlovesLinkServer } from "./index.js";
5
+ export declare class Namespace {
6
+ name: string;
7
+ private server;
8
+ private onConnectEvent;
9
+ authFn: AuthFn;
10
+ room: Room;
11
+ constructor(name: string, server: GlovesLinkServer);
12
+ onConnect(handler: (ws: GLSocket) => void): this;
13
+ auth(authFn: AuthFn): this;
14
+ get onConnectHandler(): (ws: GLSocket) => void;
15
+ emit(event: string, ...args: any[]): void;
16
+ emitWithoutSelf(socket: GLSocket, event: string, ...args: any[]): void;
17
+ }
@@ -0,0 +1,30 @@
1
+ export class Namespace {
2
+ name;
3
+ server;
4
+ onConnectEvent = () => { };
5
+ authFn = () => false;
6
+ room;
7
+ constructor(name, server) {
8
+ this.name = name;
9
+ this.server = server;
10
+ const roomName = `gls-namespace-${name}`;
11
+ this.room = this.server.room(roomName);
12
+ }
13
+ onConnect(handler) {
14
+ this.onConnectEvent = handler;
15
+ return this;
16
+ }
17
+ auth(authFn) {
18
+ this.authFn = authFn;
19
+ return this;
20
+ }
21
+ get onConnectHandler() {
22
+ return this.onConnectEvent;
23
+ }
24
+ emit(event, ...args) {
25
+ this.room.emit(event, ...args);
26
+ }
27
+ emitWithoutSelf(socket, event, ...args) {
28
+ this.room.emitWithoutSelf(socket, event, ...args);
29
+ }
30
+ }
package/dist/room.d.ts CHANGED
@@ -3,7 +3,7 @@ import { GLSocket } from "./socket.js";
3
3
  export type Rooms = Map<string, Room>;
4
4
  export declare class Room {
5
5
  clients: Set<GLSocket>;
6
- eventEmitter: EventEmitter<[never]>;
6
+ eventEmitter: EventEmitter<any>;
7
7
  join(socket: GLSocket): void;
8
8
  leave(socket: GLSocket): void;
9
9
  leaveAll(): void;
package/dist/socket.d.ts CHANGED
@@ -4,6 +4,8 @@ export declare class GLSocket {
4
4
  ws: WebSocket;
5
5
  server: GlovesLinkServer;
6
6
  id: string;
7
+ user: any;
8
+ namespace: string;
7
9
  ackIdCounter: number;
8
10
  ackCallbacks: Map<number, Function>;
9
11
  logs: boolean;
package/dist/socket.js CHANGED
@@ -1,8 +1,10 @@
1
- import { joinSocketToRoom, leaveAllSocketFromRoom, leaveSocketFromRoom } from "./room.js";
1
+ import { joinSocketToRoom, leaveSocketFromRoom } from "./room.js";
2
2
  export class GLSocket {
3
3
  ws;
4
4
  server;
5
5
  id;
6
+ user = {};
7
+ namespace;
6
8
  ackIdCounter = 1;
7
9
  ackCallbacks = new Map();
8
10
  logs = false;
@@ -85,7 +87,9 @@ export class GLSocket {
85
87
  this.rooms.delete(roomName);
86
88
  }
87
89
  leaveAllRooms() {
88
- leaveAllSocketFromRoom(this);
90
+ for (const roomName of this.rooms) {
91
+ leaveSocketFromRoom(this, roomName);
92
+ }
89
93
  this.rooms.clear();
90
94
  }
91
95
  }
package/dist/types.d.ts CHANGED
@@ -1,8 +1,8 @@
1
1
  import http from "http";
2
+ import Stream from "stream";
2
3
  export interface Server_Opts {
3
4
  server: http.Server;
4
5
  logs: boolean;
5
- authFn: AuthFn;
6
6
  }
7
7
  export interface Server_DataEvent {
8
8
  evt: string;
@@ -17,5 +17,8 @@ export interface Server_Auth_Opts {
17
17
  headers: http.IncomingHttpHeaders;
18
18
  url: URL;
19
19
  token?: string;
20
+ request: http.IncomingMessage;
21
+ socket: Stream.Duplex;
22
+ head: Buffer<ArrayBufferLike>;
20
23
  }
21
- export type AuthFn = (data: Server_Auth_Opts) => boolean | Promise<boolean>;
24
+ export type AuthFn = (data: Server_Auth_Opts) => (Promise<object | boolean> | object | boolean);
package/package.json CHANGED
@@ -1,50 +1,47 @@
1
1
  {
2
- "name": "@wxn0brp/gloves-link-server",
3
- "version": "0.0.3",
4
- "main": "dist/index.js",
5
- "types": "dist/index.d.ts",
6
- "author": "wxn0brP",
7
- "license": "MIT",
8
- "type": "module",
9
- "repository": {
10
- "type": "git",
11
- "url": "https://github.com/wxn0brP/GlovesLink-server.git"
12
- },
13
- "homepage": "https://github.com/wxn0brP/GlovesLink",
14
- "scripts": {
15
- "build": "tsc && tsc-alias"
16
- },
17
- "devDependencies": {
18
- "@wxn0brp/falcon-frame": "^0.5.3",
19
- "@types/bun": "*",
20
- "@types/ws": "^8.18.1",
21
- "tsc-alias": "*",
22
- "typescript": "*"
23
- },
24
- "peerDependencies": {
25
- "@wxn0brp/falcon-frame": ">=0.5.3"
26
- },
27
- "peerDependenciesMeta": {
28
- "@wxn0brp/falcon-frame": {
29
- "optional": true
30
- }
31
- },
32
- "dependencies": {
33
- "ws": "^8.18.3"
2
+ "name": "@wxn0brp/gloves-link-server",
3
+ "version": "0.0.5",
4
+ "main": "dist/index.js",
5
+ "types": "dist/index.d.ts",
6
+ "author": "wxn0brP",
7
+ "license": "MIT",
8
+ "type": "module",
9
+ "repository": {
10
+ "type": "git",
11
+ "url": "https://github.com/wxn0brP/GlovesLink-server.git"
12
+ },
13
+ "homepage": "https://github.com/wxn0brP/GlovesLink",
14
+ "devDependencies": {
15
+ "@wxn0brp/falcon-frame": "^0.5.3",
16
+ "@types/bun": "*",
17
+ "@types/ws": "^8.18.1",
18
+ "tsc-alias": "*",
19
+ "typescript": "*"
20
+ },
21
+ "peerDependencies": {
22
+ "@wxn0brp/falcon-frame": ">=0.5.3"
23
+ },
24
+ "peerDependenciesMeta": {
25
+ "@wxn0brp/falcon-frame": {
26
+ "optional": true
27
+ }
28
+ },
29
+ "dependencies": {
30
+ "ws": "^8.18.3"
31
+ },
32
+ "files": [
33
+ "dist"
34
+ ],
35
+ "exports": {
36
+ ".": {
37
+ "types": "./dist/index.d.ts",
38
+ "import": "./dist/index.js",
39
+ "default": "./dist/index.js"
34
40
  },
35
- "files": [
36
- "dist"
37
- ],
38
- "exports": {
39
- ".": {
40
- "types": "./dist/index.d.ts",
41
- "import": "./dist/index.js",
42
- "default": "./dist/index.js"
43
- },
44
- "./*": {
45
- "types": "./dist/*.d.ts",
46
- "import": "./dist/*.js",
47
- "default": "./dist/*.js"
48
- }
41
+ "./*": {
42
+ "types": "./dist/*.d.ts",
43
+ "import": "./dist/*.js",
44
+ "default": "./dist/*.js"
49
45
  }
46
+ }
50
47
  }