@eleven-am/pondsocket 0.1.210 → 0.1.212
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 +129 -428
- package/engines/channelEngine.js +0 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -14,60 +14,6 @@ npm install @eleven-am/pondsocket
|
|
|
14
14
|
|
|
15
15
|
PondSocket simplifies the complexity of handling WebSocket connections by abstracting the communication process into individual requests rather than dealing with intricate callbacks within the connection event. It offers a lightweight yet powerful solution for managing bidirectional communication channels, enabling real-time updates and collaboration between server and client components.
|
|
16
16
|
|
|
17
|
-
## Server-side Usage
|
|
18
|
-
|
|
19
|
-
When setting up the server, PondSocket allows you to create multiple endpoints, each serving as a gateway for sockets to connect and communicate. Each endpoint operates independently, ensuring that sockets from one endpoint cannot interact with sockets from another. This isolation enhances security and simplifies resource management.
|
|
20
|
-
|
|
21
|
-
```javascript
|
|
22
|
-
import PondSocket from "@eleven-am/pondsocket";
|
|
23
|
-
|
|
24
|
-
const pond = new PondSocket();
|
|
25
|
-
|
|
26
|
-
// Create an endpoint for handling socket connections
|
|
27
|
-
const endpoint = pond.createEndpoint('/api/socket', (req, res) => {
|
|
28
|
-
// Handle socket connection and authentication
|
|
29
|
-
});
|
|
30
|
-
|
|
31
|
-
// Start the server
|
|
32
|
-
pond.listen(3000);
|
|
33
|
-
```
|
|
34
|
-
|
|
35
|
-
Within each endpoint, sockets interact through channels. Channels provide an organized way to group users and manage efficient communication among them. When users join a channel, they can participate in real-time events and exchange information with other users in the same channel.
|
|
36
|
-
|
|
37
|
-
```javascript
|
|
38
|
-
const channel = endpoint.createChannel('/channel/:id', (req, res) => {
|
|
39
|
-
// Handle the join request, which is sent when a user attempts to join the channel
|
|
40
|
-
});
|
|
41
|
-
```
|
|
42
|
-
|
|
43
|
-
## Client-side Usage
|
|
44
|
-
|
|
45
|
-
On the client-side, PondSocket provides the PondClient class to establish connections with the server. Clients can easily initiate connections, join channels, and participate in real-time interactions.
|
|
46
|
-
|
|
47
|
-
```javascript
|
|
48
|
-
import PondClient from "@eleven-am/pondsocket-client";
|
|
49
|
-
|
|
50
|
-
const socket = new PondClient('/api/socket', {});
|
|
51
|
-
socket.connect();
|
|
52
|
-
```
|
|
53
|
-
|
|
54
|
-
Once connected, clients can create and join channels to engage in real-time communication with other users and the server.
|
|
55
|
-
|
|
56
|
-
```javascript
|
|
57
|
-
const channel = socket.createChannel('/channel/123');
|
|
58
|
-
channel.join();
|
|
59
|
-
```
|
|
60
|
-
|
|
61
|
-
### Node Client
|
|
62
|
-
|
|
63
|
-
PondSocket also offers a Node.js client, which can be imported using:
|
|
64
|
-
|
|
65
|
-
```javascript
|
|
66
|
-
import PondClient from "@eleven-am/pondsocket-client";
|
|
67
|
-
```
|
|
68
|
-
|
|
69
|
-
This node client allows you to turn another server into a client, enabling easy communication between different server instances.
|
|
70
|
-
|
|
71
17
|
## Key Features
|
|
72
18
|
|
|
73
19
|
- **Simple and Efficient API**: PondSocket offers an easy-to-use API, making WebSocket communication straightforward and hassle-free.
|
|
@@ -75,437 +21,192 @@ This node client allows you to turn another server into a client, enabling easy
|
|
|
75
21
|
- **Assigns**: PondSocket allows the storage of private information for users and channels, enhancing data security.
|
|
76
22
|
- **Presence**: The presence feature keeps track of users' current states and notifies other users about any changes.
|
|
77
23
|
- **Broadcasting**: PondSocket enables broadcasting messages to all users or specific groups within a channel, facilitating real-time updates.
|
|
78
|
-
- **
|
|
24
|
+
- **Type Safety**: The codebase is thoroughly typed with TypeScript, providing a seamless development experience with improved IDE suggestions.
|
|
25
|
+
- **Middleware Support**: Extensible middleware system for request processing and validation.
|
|
26
|
+
- **Distributed Support**: Built-in support for distributed deployment with state synchronization.
|
|
79
27
|
|
|
80
|
-
##
|
|
81
|
-
|
|
82
|
-
### Client-side Example with Authentication
|
|
83
|
-
|
|
84
|
-
To connect to the PondSocket server and send messages while associating a username with the client connection, follow the steps below:
|
|
85
|
-
|
|
86
|
-
```javascript
|
|
87
|
-
import PondClient from "@eleven-am/pondsocket-client";
|
|
88
|
-
|
|
89
|
-
// Your server URL
|
|
90
|
-
const serverUrl = 'ws://your-server-url/api/socket';
|
|
91
|
-
|
|
92
|
-
// Your authenticated user's token (replace with actual token)
|
|
93
|
-
const authToken = 'your-auth-token';
|
|
94
|
-
|
|
95
|
-
// Your username (replace with actual username)
|
|
96
|
-
const username = 'user123';
|
|
97
|
-
|
|
98
|
-
// Create a new PondClient instance
|
|
99
|
-
const socket = new PondClient(serverUrl, { token: authToken });
|
|
100
|
-
|
|
101
|
-
// Connect to the server
|
|
102
|
-
socket.connect();
|
|
103
|
-
|
|
104
|
-
// Add event listeners to handle various scenarios
|
|
105
|
-
socket.onConnectionChange((connected) => {
|
|
106
|
-
if (connected) {
|
|
107
|
-
console.log('Connected to the server.');
|
|
108
|
-
} else {
|
|
109
|
-
console.log('Disconnected from the server.');
|
|
110
|
-
}
|
|
111
|
-
});
|
|
112
|
-
|
|
113
|
-
// Create a channel and join it
|
|
114
|
-
const channel = socket.createChannel('/channel/123', { username });
|
|
115
|
-
channel.join();
|
|
116
|
-
|
|
117
|
-
// Send a message to the server
|
|
118
|
-
const message = "Hello, PondSocket!";
|
|
119
|
-
channel.broadcast('message', { text: message });
|
|
120
|
-
|
|
121
|
-
// Handle received messages
|
|
122
|
-
// Certain methods in the channel instance returns a subscription function, which can be used to unsubscribe from the event
|
|
123
|
-
const subscription = channel.onMessage((event, message) => {
|
|
124
|
-
console.log(`Received message from server: ${message.text}`);
|
|
125
|
-
});
|
|
126
|
-
|
|
127
|
-
// Unsubscribe from the event
|
|
128
|
-
subscription();
|
|
129
|
-
```
|
|
130
|
-
|
|
131
|
-
The client will now connect to the server, and the server will receive the necessary headers automatically, including any authentication tokens or cookies, as required by the browser.
|
|
132
|
-
|
|
133
|
-
### Server-side Example with Authentication and check for profanity before broadcasting
|
|
28
|
+
## Server-side Usage
|
|
134
29
|
|
|
135
|
-
|
|
30
|
+
When setting up the server, PondSocket allows you to create multiple endpoints, each serving as a gateway for sockets to connect and communicate. Each endpoint operates independently, ensuring that sockets from one endpoint cannot interact with sockets from another. This isolation enhances security and simplifies resource management.
|
|
136
31
|
|
|
137
|
-
```
|
|
32
|
+
```typescript
|
|
138
33
|
import PondSocket from "@eleven-am/pondsocket";
|
|
139
34
|
|
|
140
|
-
// Helper functions for token validation
|
|
141
|
-
function isValidToken(token) {
|
|
142
|
-
// Implement your token validation logic here
|
|
143
|
-
// Return true if the token is valid, false otherwise
|
|
144
|
-
return true;
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
function getRoleFromToken(token) {
|
|
148
|
-
// Implement the logic to extract the user's role from the token
|
|
149
|
-
// Return the user's role
|
|
150
|
-
return 'user';
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
function isTextProfane(text) {
|
|
154
|
-
// Implement your profanity check logic here
|
|
155
|
-
// Return true if the text is profane, false otherwise
|
|
156
|
-
return false;
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
function getMessagesFromDatabase(channelId) {
|
|
160
|
-
// Implement your logic to retrieve messages from the database
|
|
161
|
-
// Return an array of messages
|
|
162
|
-
return [];
|
|
163
|
-
}
|
|
164
|
-
|
|
165
35
|
const pond = new PondSocket();
|
|
166
36
|
|
|
167
37
|
// Create an endpoint for handling socket connections
|
|
168
|
-
const endpoint = pond.createEndpoint('/api/socket', (
|
|
169
|
-
//
|
|
170
|
-
const token =
|
|
171
|
-
|
|
172
|
-
// Perform token validation here
|
|
38
|
+
const endpoint = pond.createEndpoint('/api/socket', (ctx, next) => {
|
|
39
|
+
// Handle socket connection and authentication
|
|
40
|
+
const token = ctx.request.query.token;
|
|
41
|
+
|
|
173
42
|
if (isValidToken(token)) {
|
|
174
|
-
// Extract the authenticated user's username
|
|
175
43
|
const role = getRoleFromToken(token);
|
|
176
|
-
|
|
177
|
-
// Handle socket connection and authentication for valid users
|
|
178
|
-
res.accept({role}); // Assign the user's role to the socket
|
|
44
|
+
ctx.accept({ role }); // Assign the user's role to the socket
|
|
179
45
|
} else {
|
|
180
|
-
|
|
181
|
-
res.reject('Invalid token', 401);
|
|
46
|
+
ctx.reject('Invalid token', 401);
|
|
182
47
|
}
|
|
183
48
|
});
|
|
184
49
|
|
|
185
|
-
// Create a channel
|
|
186
|
-
const
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
const {
|
|
190
|
-
const {username} = req.joinParams;
|
|
191
|
-
const {id} = req.event.params;
|
|
192
|
-
|
|
193
|
-
// maybe retrieve the previous messages from the database
|
|
194
|
-
const messages = await getMessagesFromDatabase(id);
|
|
50
|
+
// Create a channel with path parameters
|
|
51
|
+
const channel = endpoint.createChannel('/channel/:id', (ctx, next) => {
|
|
52
|
+
const { role } = ctx.user.assigns;
|
|
53
|
+
const { username } = ctx.joinParams;
|
|
54
|
+
const { id } = ctx.event.params;
|
|
195
55
|
|
|
196
|
-
// Check if the user has the required role to join the channel
|
|
197
56
|
if (role === 'admin') {
|
|
198
|
-
|
|
199
|
-
res.accept({username, profanityCount: 0})
|
|
200
|
-
// optionally you can track the presence of the user in the channel
|
|
57
|
+
ctx.accept({ username })
|
|
201
58
|
.trackPresence({
|
|
202
59
|
username,
|
|
203
60
|
role,
|
|
204
61
|
status: 'online',
|
|
205
62
|
onlineSince: Date.now(),
|
|
206
|
-
})
|
|
207
|
-
// and send the user the channel history
|
|
208
|
-
.sendToUsers('history', {messages}, [req.user.id]);
|
|
209
|
-
|
|
210
|
-
// Alternatively, you can also send messages to the user, NOTE that the user would be automatically subscribed to the channel.
|
|
211
|
-
// res.send('history', { messages }, { username, profanityCount: 0 })
|
|
212
|
-
// .trackPresence({
|
|
213
|
-
// username,
|
|
214
|
-
// role,
|
|
215
|
-
// status: 'online',
|
|
216
|
-
// onlineSince: Date.now(),
|
|
217
|
-
// });
|
|
63
|
+
});
|
|
218
64
|
} else {
|
|
219
|
-
|
|
220
|
-
res.decline('You do not have the required role to join this channel', 403);
|
|
65
|
+
ctx.decline('Insufficient permissions', 403);
|
|
221
66
|
}
|
|
222
67
|
});
|
|
223
68
|
|
|
224
|
-
//
|
|
225
|
-
|
|
226
|
-
const {text} =
|
|
227
|
-
|
|
228
|
-
//
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
if (req.user.assigns.profanityCount >= 3) {
|
|
237
|
-
// Kick the user from the channel if they have used profanity more than 3 times
|
|
238
|
-
res.evictUser('You have been kicked from the channel for using profanity');
|
|
239
|
-
} else {
|
|
240
|
-
// you can broadcast a message to all users or In the channel that profanity is not allowed
|
|
241
|
-
res.broadcast('profanity-warning', {message: 'Profanity is not allowed'})
|
|
242
|
-
// or you can send a message to the user that profanity is not allowed
|
|
243
|
-
.sendToUsers('profanity-warning', {message: `You have used profanity ${profanityCount} times. You will be kicked from the channel if you use profanity more than 3 times.`}, [req.user.id]);
|
|
244
|
-
}
|
|
245
|
-
} else {
|
|
246
|
-
// Accept the message to allow broadcasting to other clients in the channel
|
|
247
|
-
res.accept();
|
|
248
|
-
}
|
|
249
|
-
|
|
250
|
-
// for more complete access to the channel, you can use the channel instance
|
|
251
|
-
// const channel = req.channel;
|
|
252
|
-
});
|
|
253
|
-
|
|
254
|
-
profanityChannel.onEvent('presence/:presence', (req, res) => {
|
|
255
|
-
const {presence} = req.event.params;
|
|
256
|
-
const {username} = req.user.assigns;
|
|
257
|
-
|
|
258
|
-
// Handle presence events
|
|
259
|
-
res.updatePresence({
|
|
260
|
-
username,
|
|
261
|
-
role,
|
|
262
|
-
onlineSince: Date.now(),
|
|
263
|
-
status: presence,
|
|
264
|
-
});
|
|
265
|
-
});
|
|
266
|
-
|
|
267
|
-
profanityChannel.onLeave((event) => {
|
|
268
|
-
const {username} = event.assigns;
|
|
269
|
-
|
|
270
|
-
// When a user leaves the channel, PondSocket will automatically remove the user from the presence list and inform other users in the channel
|
|
271
|
-
|
|
272
|
-
// perform a cleanup operation here
|
|
69
|
+
// Handle channel events
|
|
70
|
+
channel.onEvent('message', (ctx, next) => {
|
|
71
|
+
const { text } = ctx.event.payload;
|
|
72
|
+
|
|
73
|
+
// Broadcast to all users in the channel
|
|
74
|
+
ctx.broadcast('message', { text });
|
|
75
|
+
|
|
76
|
+
// Or broadcast to specific users
|
|
77
|
+
ctx.broadcastTo(['user1', 'user2'], 'message', { text });
|
|
78
|
+
|
|
79
|
+
// Or broadcast to all except sender
|
|
80
|
+
ctx.broadcastFrom('message', { text });
|
|
273
81
|
});
|
|
274
82
|
|
|
275
83
|
// Start the server
|
|
276
|
-
pond.listen(3000
|
|
277
|
-
console.log('PondSocket server listening on port 3000');
|
|
278
|
-
});
|
|
84
|
+
pond.listen(3000);
|
|
279
85
|
```
|
|
280
86
|
|
|
281
|
-
##
|
|
282
|
-
|
|
283
|
-
### PondSocket
|
|
284
|
-
|
|
285
|
-
The `PondSocket` class is the core class that represents the socket server.
|
|
286
|
-
|
|
287
|
-
**Constructor:**
|
|
288
|
-
|
|
289
|
-
- `constructor(server?: HTTPServer, socketServer?: WebSocketServer)`: Creates a new instance of the PondSocket with an optional HTTP server and WebSocket server.
|
|
290
|
-
|
|
291
|
-
**Methods:**
|
|
292
|
-
|
|
293
|
-
- `listen(...args: any[]): HTTPServer`: Specifies the port to listen on with the provided arguments.
|
|
294
|
-
|
|
295
|
-
- `close(callback?: () => void): HTTPServer`: Closes the server, and an optional callback can be provided.
|
|
296
|
-
|
|
297
|
-
- `createEndpoint<Path extends string>(path: PondPath<Path>, handler: (request: IncomingConnection<Path>, response: ConnectionResponse) => void | Promise<void>): Endpoint`: Accepts a new socket upgrade request on the provided endpoint using the handler function to authenticate the socket.
|
|
298
|
-
|
|
299
|
-
### ConnectionResponse
|
|
300
|
-
|
|
301
|
-
The `ConnectionResponse` class represents the response object for the incoming connection.
|
|
302
|
-
|
|
303
|
-
**Methods:**
|
|
304
|
-
|
|
305
|
-
- `accept(assigns?: PondAssigns): void`: Accepts the request and optionally assigns data to the client.
|
|
306
|
-
|
|
307
|
-
- `reject(message?: string, errorCode?: number): void`: Rejects the request with the given error message and optional error code.
|
|
308
|
-
|
|
309
|
-
- `send(event: string, payload: PondMessage, assigns?: PondAssigns): void`: Emits a direct message to the client with the specified event and payload.
|
|
310
|
-
|
|
311
|
-
### Endpoint
|
|
312
|
-
|
|
313
|
-
The `Endpoint` class represents an endpoint in the PondSocket server where channels can be created.
|
|
314
|
-
|
|
315
|
-
**Methods:**
|
|
316
|
-
|
|
317
|
-
- `createChannel<Path extends string>(path: PondPath<Path>, handler: (request: JoinRequest<Path>, response: JoinResponse) => void | Promise<void>): PondChannel`: Adds a new PondChannel to this path on this endpoint with the provided handler function to authenticate the client.
|
|
318
|
-
|
|
319
|
-
- `broadcast(event: string, payload: PondMessage): void`: Broadcasts a message to all clients connected to this endpoint with the specified event and payload.
|
|
320
|
-
|
|
321
|
-
- `closeConnection(clientIds: string | string[]): void`: Closes specific clients connected to this endpoint identified by the provided clientIds.
|
|
322
|
-
|
|
323
|
-
### JoinRequest
|
|
324
|
-
|
|
325
|
-
The `JoinRequest` class represents the request object when a client joins a channel.
|
|
326
|
-
|
|
327
|
-
**Properties:**
|
|
328
|
-
|
|
329
|
-
- `event: PondEvent<Path>`: The event associated with the request.
|
|
330
|
-
|
|
331
|
-
- `channelName: string`: The name of the channel.
|
|
332
|
-
|
|
333
|
-
- `assigns: UserAssigns`: The assigns data for the client.
|
|
334
|
-
|
|
335
|
-
- `presence: UserPresences`: The presence data for the client.
|
|
336
|
-
|
|
337
|
-
- `joinParams: JoinParams`: The join parameters for the client.
|
|
338
|
-
|
|
339
|
-
- `user: UserData`: The user data associated with the client.
|
|
340
|
-
|
|
341
|
-
- `channel: Channel`: The Channel instance associated with the request.
|
|
342
|
-
|
|
343
|
-
### JoinResponse
|
|
344
|
-
|
|
345
|
-
The `JoinResponse` class represents the response object for the join request.
|
|
346
|
-
|
|
347
|
-
**Methods:**
|
|
348
|
-
|
|
349
|
-
- `accept(assigns?: PondAssigns): JoinResponse`: Accepts the join request and optionally assigns data to the client.
|
|
350
|
-
|
|
351
|
-
- `reject(message?: string, errorCode?: number): JoinResponse`: Rejects the join request with the given error message and optional error code.
|
|
352
|
-
|
|
353
|
-
- `send(event: string, payload: PondMessage, assigns?: PondAssigns): JoinResponse`: Emits a direct message to the client with the specified event, payload, and optional assigns data.
|
|
354
|
-
|
|
355
|
-
- `broadcast(event: string, payload: PondMessage): JoinResponse`: Emits a message to all clients in the channel with the specified event and payload.
|
|
356
|
-
|
|
357
|
-
- `broadcastFromUser(event: string, payload: PondMessage): JoinResponse`: Emits a message to all clients in the channel except the sender with the specified event and payload.
|
|
358
|
-
|
|
359
|
-
- `sendToUsers(event: string, payload: PondMessage, userIds: string[]): JoinResponse`: Emits a message to a specific set of clients identified by the provided userIds with the specified event and payload.
|
|
360
|
-
|
|
361
|
-
- `trackPresence(presence: PondPresence): JoinResponse`: Tracks the presence of the client in the channel.
|
|
362
|
-
|
|
363
|
-
### PondChannel
|
|
364
|
-
|
|
365
|
-
The `PondChannel` class represents a Generic channel in the PondSocket server. It is used to create a channel whose path matches the provided PondPath.
|
|
366
|
-
|
|
367
|
-
**Methods:**
|
|
368
|
-
|
|
369
|
-
- `onEvent<Event extends string>(event: PondPath<Event>, handler: (request: EventRequest<Event>, response: EventResponse) => void | Promise<void>): void`: Handles an event request made by a user for the specified event with the provided handler function.
|
|
370
|
-
|
|
371
|
-
- `broadcast(event: string, payload: PondMessage, channelName?: string): void`: Broadcasts a message to all users in the channel with the specified event and payload. Optionally, a specific channel name can be provided to broadcast the message only to users in that channel.
|
|
372
|
-
|
|
373
|
-
- `onLeave(handler: (event: LeaveEvent) => void | Promise<void>): void`: Handles a leave event for the channel with the provided handler function when a user leaves the channel.
|
|
374
|
-
|
|
375
|
-
### EventRequest
|
|
376
|
-
|
|
377
|
-
The `EventRequest` class represents the request object when an event is received from a client.
|
|
378
|
-
|
|
379
|
-
**Properties:**
|
|
380
|
-
|
|
381
|
-
- `event: PondEvent<Path>`: The event associated with the request.
|
|
382
|
-
|
|
383
|
-
- `channelName: string`: The name of the channel.
|
|
384
|
-
|
|
385
|
-
- `assigns: UserAssigns`: The assigns data for the client.
|
|
386
|
-
|
|
387
|
-
- `presence: UserPresences`: The presence data for the client.
|
|
388
|
-
|
|
389
|
-
- `user: UserData`: The user data associated with the client.
|
|
390
|
-
|
|
391
|
-
- `channel: Channel`: The Channel instance associated with the request.
|
|
392
|
-
|
|
393
|
-
### EventResponse
|
|
394
|
-
|
|
395
|
-
The `EventResponse` class represents the response object for handling events from clients.
|
|
396
|
-
|
|
397
|
-
**Methods:**
|
|
398
|
-
|
|
399
|
-
- `accept(assigns?: PondAssigns): EventResponse`: Accepts the request and optionally assigns data to the client.
|
|
400
|
-
|
|
401
|
-
- `reject(message?: string, errorCode?: number, assigns?: PondAssigns): EventResponse`: Rejects the request with the given error message, optional error code, and optional assigns data.
|
|
402
|
-
|
|
403
|
-
- `send(event: string, payload: PondMessage, assigns?: PondAssigns): void`: Emits a direct message to the client with the specified event, payload, and optional assigns data.
|
|
404
|
-
|
|
405
|
-
- `broadcast(event: string, payload: PondMessage): EventResponse`: Sends a message to all clients in the channel with the specified event and payload.
|
|
406
|
-
|
|
407
|
-
- `broadcastFromUser(event: string, payload: PondMessage): EventResponse`: Sends a message to all clients in the channel except the sender with the specified event and payload.
|
|
408
|
-
|
|
409
|
-
- `sendToUsers(event: string, payload: PondMessage, userIds: string[]): EventResponse`: Sends a message to a specific set of clients identified by the provided userIds with the specified event and payload.
|
|
410
|
-
|
|
411
|
-
- `trackPresence(presence: PondPresence, userId?: string): EventResponse`: Tracks a user's presence in the channel.
|
|
412
|
-
|
|
413
|
-
- `updatePresence(presence: PondPresence, userId?: string): EventResponse`: Updates a user's presence in the channel.
|
|
414
|
-
|
|
415
|
-
- `unTrackPresence(userId?: string): EventResponse`: Removes a user's presence from the channel.
|
|
416
|
-
|
|
417
|
-
- `evictUser(reason: string, userId?: string): void`: Evicts a user from the channel.
|
|
418
|
-
|
|
419
|
-
- `closeChannel(reason: string): void`: Closes the channel from the server-side for all clients.
|
|
420
|
-
|
|
421
|
-
### Channel
|
|
422
|
-
|
|
423
|
-
The `Channel` class represents a single Channel created by the PondSocket server. Note that a PondChannel can have multiple channels associated with it.
|
|
424
|
-
|
|
425
|
-
**Methods:**
|
|
426
|
-
|
|
427
|
-
- `name: string`: The name of the channel.
|
|
428
|
-
|
|
429
|
-
- `getAssigns: UserAssigns`: Gets the current assign data for the client.
|
|
430
|
-
|
|
431
|
-
- `getUserData(userId: string): UserData`: Gets the assign data for a specific user identified by the provided `userId`.
|
|
432
|
-
|
|
433
|
-
- `broadcastMessage(event: string, payload: PondMessage): void`: Broadcasts a message to every client in the channel with the specified event and payload.
|
|
434
|
-
|
|
435
|
-
- `sendToUser(userId: string, event: string, payload: PondMessage): void`: Sends a message to a specific client in the channel identified by the provided `userId`, with the specified event and payload.
|
|
436
|
-
|
|
437
|
-
- `sendToUsers(userIdS: string[], event: string, payload: PondMessage): void`: Sends a message to a specific set of clients identified by the provided `userIdS`, with the specified event and payload.
|
|
438
|
-
|
|
439
|
-
- `evictUser(userId: string, reason?: string): void`: Bans a user from the channel identified by the provided `userId`. Optionally, you can provide a `reason` for the ban.
|
|
440
|
-
|
|
441
|
-
- `trackPresence(userId: string, presence: PondPresence): void`: Tracks a user's presence in the channel identified by the provided `userId`.
|
|
442
|
-
|
|
443
|
-
- `removePresence(userId: string): void`: Removes a user's presence from the channel identified by the provided `userId`.
|
|
444
|
-
|
|
445
|
-
- `updatePresence(userId: string, presence: PondPresence): void`: Updates a user's presence in the channel identified by the provided `userId`.
|
|
446
|
-
|
|
447
|
-
### PondClient
|
|
448
|
-
|
|
449
|
-
The `PondClient` class represents a client that connects to the PondSocket server.
|
|
87
|
+
## Client-side Usage
|
|
450
88
|
|
|
451
|
-
|
|
89
|
+
On the client-side, PondSocket provides the PondClient class to establish connections with the server. Clients can easily initiate connections, join channels, and participate in real-time interactions.
|
|
452
90
|
|
|
453
|
-
|
|
91
|
+
```typescript
|
|
92
|
+
import PondClient from "@eleven-am/pondsocket-client";
|
|
454
93
|
|
|
455
|
-
|
|
94
|
+
// Create a new client instance
|
|
95
|
+
const socket = new PondClient('ws://your-server/api/socket', {
|
|
96
|
+
token: 'your-auth-token'
|
|
97
|
+
});
|
|
456
98
|
|
|
457
|
-
|
|
99
|
+
// Connect to the server
|
|
100
|
+
socket.connect();
|
|
458
101
|
|
|
459
|
-
|
|
102
|
+
// Handle connection state changes
|
|
103
|
+
socket.onConnectionChange((connected) => {
|
|
104
|
+
if (connected) {
|
|
105
|
+
console.log('Connected to the server');
|
|
106
|
+
} else {
|
|
107
|
+
console.log('Disconnected from the server');
|
|
108
|
+
}
|
|
109
|
+
});
|
|
460
110
|
|
|
461
|
-
|
|
111
|
+
// Create and join a channel
|
|
112
|
+
const channel = socket.createChannel('/channel/123', {
|
|
113
|
+
username: 'user123'
|
|
114
|
+
});
|
|
462
115
|
|
|
463
|
-
|
|
116
|
+
// Join the channel
|
|
117
|
+
channel.join();
|
|
464
118
|
|
|
465
|
-
|
|
119
|
+
// Handle channel events
|
|
120
|
+
const subscription = channel.onMessage((event, message) => {
|
|
121
|
+
console.log(`Received message: ${message.text}`);
|
|
122
|
+
});
|
|
466
123
|
|
|
467
|
-
|
|
124
|
+
// Send a message
|
|
125
|
+
channel.broadcast('message', { text: 'Hello, PondSocket!' });
|
|
468
126
|
|
|
469
|
-
|
|
127
|
+
// Leave the channel
|
|
128
|
+
channel.leave();
|
|
470
129
|
|
|
471
|
-
|
|
130
|
+
// Unsubscribe from events
|
|
131
|
+
subscription();
|
|
132
|
+
```
|
|
472
133
|
|
|
473
|
-
|
|
134
|
+
## Advanced Features
|
|
474
135
|
|
|
475
|
-
|
|
136
|
+
### Presence Management
|
|
476
137
|
|
|
477
|
-
|
|
138
|
+
```typescript
|
|
139
|
+
// Server-side
|
|
140
|
+
channel.onEvent('presence', (ctx, next) => {
|
|
141
|
+
ctx.trackPresence({
|
|
142
|
+
username: ctx.user.assigns.username,
|
|
143
|
+
status: 'online',
|
|
144
|
+
lastSeen: Date.now()
|
|
145
|
+
});
|
|
146
|
+
});
|
|
478
147
|
|
|
479
|
-
-
|
|
148
|
+
// Client-side
|
|
149
|
+
channel.onPresence((presences) => {
|
|
150
|
+
console.log('Current users:', presences);
|
|
151
|
+
});
|
|
152
|
+
```
|
|
480
153
|
|
|
481
|
-
|
|
154
|
+
### User Assigns
|
|
482
155
|
|
|
483
|
-
|
|
156
|
+
```typescript
|
|
157
|
+
// Server-side
|
|
158
|
+
channel.onEvent('update-profile', (ctx, next) => {
|
|
159
|
+
ctx.assign({
|
|
160
|
+
...ctx.user.assigns,
|
|
161
|
+
profile: ctx.event.payload
|
|
162
|
+
});
|
|
163
|
+
});
|
|
484
164
|
|
|
485
|
-
-
|
|
165
|
+
// Client-side
|
|
166
|
+
channel.onAssigns((assigns) => {
|
|
167
|
+
console.log('User data updated:', assigns);
|
|
168
|
+
});
|
|
169
|
+
```
|
|
486
170
|
|
|
487
|
-
|
|
171
|
+
### Error Handling
|
|
488
172
|
|
|
489
|
-
|
|
173
|
+
```typescript
|
|
174
|
+
// Server-side
|
|
175
|
+
channel.onEvent('message', (ctx, next) => {
|
|
176
|
+
try {
|
|
177
|
+
// Your logic here
|
|
178
|
+
ctx.accept();
|
|
179
|
+
} catch (error) {
|
|
180
|
+
ctx.decline(error.message, 400);
|
|
181
|
+
}
|
|
182
|
+
});
|
|
490
183
|
|
|
491
|
-
-
|
|
184
|
+
// Client-side
|
|
185
|
+
channel.onError((error) => {
|
|
186
|
+
console.error('Channel error:', error);
|
|
187
|
+
});
|
|
188
|
+
```
|
|
492
189
|
|
|
493
|
-
|
|
190
|
+
## Distributed Deployment
|
|
494
191
|
|
|
495
|
-
|
|
192
|
+
PondSocket supports distributed deployment through its distributed backend system. This allows you to scale your application across multiple nodes while maintaining state synchronization.
|
|
496
193
|
|
|
497
|
-
|
|
194
|
+
```typescript
|
|
195
|
+
import PondSocket from "@eleven-am/pondsocket";
|
|
196
|
+
import { RedisBackend } from "@eleven-am/pondsocket";
|
|
498
197
|
|
|
499
|
-
|
|
198
|
+
const pond = new PondSocket({
|
|
199
|
+
backend: new RedisBackend({
|
|
200
|
+
host: 'localhost',
|
|
201
|
+
port: 6379
|
|
202
|
+
})
|
|
203
|
+
});
|
|
204
|
+
```
|
|
500
205
|
|
|
501
|
-
|
|
206
|
+
## Contributing
|
|
502
207
|
|
|
503
|
-
|
|
208
|
+
Contributions are welcome! Please feel free to submit a Pull Request.
|
|
504
209
|
|
|
505
210
|
## License
|
|
506
211
|
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
## Conclusion
|
|
510
|
-
|
|
511
|
-
PondSocket is a powerful and versatile solution for building real-time applications that require efficient bidirectional communication between server and client components. Its minimalist design and comprehensive feature set make it an excellent choice for WebSocket-based projects, providing developers with a straightforward and reliable tool for building real-time communication systems. With the Node.js client, it also allows for easy communication between multiple server instances, expanding its capabilities even further.
|
|
212
|
+
This project is licensed under the GPL-3.0 License - see the LICENSE file for details.
|
package/engines/channelEngine.js
CHANGED
|
@@ -430,7 +430,6 @@ _ChannelEngine_endpointId = new WeakMap(), _ChannelEngine_backend = new WeakMap(
|
|
|
430
430
|
__classPrivateFieldGet(this, _ChannelEngine_instances, "m", _ChannelEngine_handleDistributedMessage).call(this, message);
|
|
431
431
|
}), "f");
|
|
432
432
|
}, _ChannelEngine_handleDistributedMessage = function _ChannelEngine_handleDistributedMessage(message) {
|
|
433
|
-
console.log(message);
|
|
434
433
|
switch (message.type) {
|
|
435
434
|
case types_1.DistributedMessageType.STATE_REQUEST:
|
|
436
435
|
__classPrivateFieldGet(this, _ChannelEngine_instances, "m", _ChannelEngine_handleStateRequest).call(this, message);
|