playsocketjs 1.4.1 → 2.1.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/README.md +60 -59
- package/dist/playsocket-client.js +15 -17
- package/dist/playsocket-server.js +48 -9
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
|
-
# PlaySocket
|
|
1
|
+
# PlaySocket Client
|
|
2
2
|
|
|
3
|
-
A WebSocket
|
|
3
|
+
A reactive, optimistic WebSocket library that simplifies game & app development by abstracting away complex sync logic.
|
|
4
4
|
|
|
5
5
|
## Why use PlaySocket?
|
|
6
6
|
|
|
7
|
-
PlaySocket eliminates the traditional complexity of
|
|
7
|
+
PlaySocket eliminates the traditional complexity of collaborative experiences:
|
|
8
8
|
|
|
9
|
-
- **Streamlined
|
|
10
|
-
- **State
|
|
11
|
-
- **Resilient &
|
|
12
|
-
- **Lightweight**: Uses WebSockets for efficient, predictable
|
|
9
|
+
- **Streamlined architecture**: No additional backend code is required, but server-authoritative behavior supported
|
|
10
|
+
- **State synchronization**: Built-in storage system keeps the full state synchronized across all clients, always conflict-free and in order
|
|
11
|
+
- **Resilient & secure connections**: Automatic reconnection handling & strict rate-limiting
|
|
12
|
+
- **Lightweight**: Uses WebSockets for efficient, predictable, reliable communication and has little dependencies
|
|
13
13
|
|
|
14
14
|
## Installation
|
|
15
15
|
|
|
@@ -17,58 +17,72 @@ PlaySocket eliminates the traditional complexity of multiplayer implementations:
|
|
|
17
17
|
npm install playsocketjs
|
|
18
18
|
```
|
|
19
19
|
|
|
20
|
-
## Usage
|
|
20
|
+
## Usage examples
|
|
21
21
|
|
|
22
|
-
Note that in production, you should **always try...catch**
|
|
22
|
+
Note that in production, you should **always try...catch** promises, such as socket.init() – they can reject!
|
|
23
23
|
|
|
24
|
+
Initializing the client:
|
|
24
25
|
```javascript
|
|
25
26
|
import PlaySocket from 'playsocketjs';
|
|
26
27
|
|
|
27
28
|
// Create a new instance
|
|
28
|
-
const socket = new PlaySocket('unique-client-id', {
|
|
29
|
+
const socket = new PlaySocket('unique-client-id', { // You can pass no ID to let the server pick one
|
|
29
30
|
endpoint: 'wss://example.com/socket'
|
|
30
31
|
});
|
|
31
32
|
|
|
32
|
-
// Set up event handlers
|
|
33
|
+
// Set up event handlers (optional)
|
|
33
34
|
socket.onEvent('status', status => console.log('Status:', status));
|
|
34
|
-
socket.onEvent('
|
|
35
|
+
socket.onEvent('error', status => console.log('Error:', status));
|
|
35
36
|
|
|
36
|
-
// Initialize the socket
|
|
37
|
-
|
|
37
|
+
const clientId = await socket.init(); // Initialize the socket
|
|
38
|
+
```
|
|
38
39
|
|
|
40
|
+
Creating a room:
|
|
41
|
+
```javascript
|
|
39
42
|
// Create a new room
|
|
40
43
|
const roomId = await socket.createRoom();
|
|
41
44
|
|
|
42
|
-
// Optionally,
|
|
45
|
+
// Optionally, with initial storage
|
|
43
46
|
const roomId = await socket.createRoom({
|
|
44
|
-
players: [],
|
|
45
|
-
moreThings: {},
|
|
47
|
+
players: ["this-player"],
|
|
46
48
|
latestPlayer: null,
|
|
47
49
|
});
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
Joining a room:
|
|
53
|
+
```javascript
|
|
54
|
+
await socket.joinRoom('room-id'); // Join an existing room
|
|
55
|
+
```
|
|
48
56
|
|
|
49
|
-
|
|
50
|
-
|
|
57
|
+
Leaving a room:
|
|
58
|
+
```javascript
|
|
59
|
+
socket.destroy(); // To leave the room, destroy the instance
|
|
60
|
+
```
|
|
51
61
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
socket.
|
|
62
|
+
Using the storage update event for reactivity:
|
|
63
|
+
```javascript
|
|
64
|
+
const reactiveVariable = useState(); // Or $state(), reactive(), depending on your framework
|
|
65
|
+
socket.onEvent('storageUpdated', storage => (reactiveVariable = storage)); // Assign on update
|
|
66
|
+
```
|
|
56
67
|
|
|
57
|
-
|
|
58
|
-
|
|
68
|
+
Interfacing with the synchronized storage (examples):
|
|
69
|
+
```javascript
|
|
70
|
+
const currentState = socket.getStorage; // Synchronous, local access
|
|
71
|
+
socket.updateStorage('players', 'array-add-unique', { username: 'Player4', level: 2 }); // Special method to enable conflict-free additions for arrays
|
|
72
|
+
socket.updateStorage('latestPlayer', 'set', 'Player4'); // Regular synced storage update
|
|
59
73
|
```
|
|
60
74
|
|
|
61
75
|
## API Reference
|
|
62
76
|
|
|
63
77
|
### Constructor
|
|
64
78
|
|
|
79
|
+
Creates a new PlaySocket instance with a specified ID and configuration options.
|
|
80
|
+
The id can be set to `null` to let the server pick a unique one.
|
|
81
|
+
|
|
65
82
|
```javascript
|
|
66
83
|
new PlaySocket(id?: string, options: PlaySocketOptions)
|
|
67
84
|
```
|
|
68
85
|
|
|
69
|
-
Creates a new PlaySocket instance with a specified ID and configuration options.
|
|
70
|
-
Note: With PlaySocket, the id can be set to `null` to let the server pick a unique one.
|
|
71
|
-
|
|
72
86
|
#### Configuration options
|
|
73
87
|
- `endpoint`: WebSocket server endpoint (e.g., 'wss://example.com/socket')
|
|
74
88
|
- `customData`: You can pass arbitrary data to the "clientRegistered" server event (optional)
|
|
@@ -76,39 +90,32 @@ Note: With PlaySocket, the id can be set to `null` to let the server pick a uniq
|
|
|
76
90
|
|
|
77
91
|
### Methods
|
|
78
92
|
|
|
79
|
-
#### Core
|
|
80
|
-
|
|
81
93
|
- `init()`: Initialize the WebSocket connection – Returns Promise (async) which resolves with the client's id
|
|
82
94
|
- `createRoom(initialStorage?: object, maxSize?: number)`: Create a new room and become host – Returns Promise (async) which resolves with the room id (matches the creator's id)
|
|
83
95
|
- `joinRoom(hostId: string)`: Join an existing room – Returns Promise (async)
|
|
84
96
|
- `destroy()`: Use this to leave a room and close the connection
|
|
85
|
-
|
|
86
|
-
#### State management
|
|
87
|
-
|
|
88
|
-
- `updateStorage(key: string, value: any)`: Update a value in the synchronized storage
|
|
89
|
-
- `updateStorageArray(key: string, operation: 'add' | 'add-unique' | 'remove-matching' | 'update-matching', value: any, updateValue?: any)`: Safely update arrays in storage by adding, removing, or updating items. This is necessary for when array updates might be happening simultaneously to ensure changes are being applied and not overwritten. Using add-unique instead of add ensures that this value can only be in the array once.
|
|
97
|
+
- `updateStorage(key: string, type: 'set' | 'array-add' | 'array-add-unique' | 'array-remove-matching' | 'array-update-matching', value: any, updateValue?: any)`: Update the shared storage. Safely update arrays in storage by adding, removing, or updating items. UpdateValue is only required for the 'array-update-matching' operation type
|
|
90
98
|
- `onEvent(event: string, callback: Function)`: Register an event callback
|
|
91
99
|
|
|
92
|
-
|
|
100
|
+
#### Event types
|
|
93
101
|
|
|
94
102
|
- `status`: Connection status updates (returns status `string`)
|
|
95
103
|
- `error`: Error events (returns error `string`)
|
|
96
104
|
- `instanceDestroyed`: Destruction event - triggered by manual .destroy() method invocation or by fatal errors and disconnects
|
|
97
105
|
- `storageUpdated`: Storage state changes (returns storage `object`)
|
|
98
|
-
- `hostMigrated`: Host changes (returns the new host's id `string`)
|
|
106
|
+
- `hostMigrated`: Host changes (returns the new host's id `string`)
|
|
99
107
|
- `clientConnected`: New client connected to the room (returns client-id `string`)
|
|
100
|
-
- `clientDisconnected`: Client disconnected from the room (returns client-id `string`)
|
|
108
|
+
- `clientDisconnected`: Client disconnected from the room (returns client-id `string`, room id (if available) `string`)
|
|
101
109
|
|
|
102
110
|
### Properties (Read-only)
|
|
103
111
|
|
|
104
|
-
|
|
105
|
-
Using a UUID is recommended, but it is also fine to use any other random string. If you're using a public WebSocket server, including your application's name in the `id` can help to prevent overlap (e.g. your-app-012345abcdef).
|
|
106
|
-
|
|
107
|
-
- `id`: Client's unique identifier
|
|
112
|
+
- `id`: Client's unique identifier on the WebSocket server
|
|
108
113
|
- `isHost`: If this user is currently assigned the host role
|
|
109
114
|
- `connectionCount`: Number of active client connections in room (without you)
|
|
110
115
|
- `getStorage`: Retrieve storage object
|
|
111
116
|
|
|
117
|
+
|
|
118
|
+
|
|
112
119
|
# PlaySocket Server
|
|
113
120
|
|
|
114
121
|
PlaySocket includes a server implementation that can be set up in seconds.
|
|
@@ -121,18 +128,16 @@ To use the server component, you'll need to install playsocketjs and the ws pack
|
|
|
121
128
|
npm install playsocketjs ws
|
|
122
129
|
```
|
|
123
130
|
|
|
124
|
-
## Usage
|
|
131
|
+
## Usage examples
|
|
125
132
|
|
|
126
|
-
Here are usage examples for a standalone server and an
|
|
127
|
-
framework agnostic and the Express example can be adapted to any other backend solution.
|
|
133
|
+
Here are usage examples for a standalone server and an Express.js application.
|
|
128
134
|
|
|
129
135
|
### Standalone server
|
|
130
136
|
|
|
131
137
|
```javascript
|
|
132
138
|
const PlaySocketServer = require('playsocketjs/server');
|
|
133
139
|
|
|
134
|
-
// Create and start the server
|
|
135
|
-
const server = new PlaySocketServer();
|
|
140
|
+
const server = new PlaySocketServer(); // Create and start the server (default path is /socket)
|
|
136
141
|
|
|
137
142
|
// Gracefully disconnect all clients and close the server (optional)
|
|
138
143
|
function shutdown() {
|
|
@@ -145,30 +150,28 @@ process.on('SIGINT', shutdown);
|
|
|
145
150
|
process.on('SIGTERM', shutdown);
|
|
146
151
|
```
|
|
147
152
|
|
|
148
|
-
###
|
|
153
|
+
### Together with Express.js (or other Backend frameworks)
|
|
149
154
|
|
|
150
155
|
```javascript
|
|
151
156
|
const express = require('express');
|
|
152
157
|
const http = require('http');
|
|
153
158
|
const PlaySocketServer = require('playsocketjs/server');
|
|
154
|
-
const port = 3000;
|
|
155
159
|
|
|
156
160
|
const app = express();
|
|
157
161
|
const httpServer = http.createServer(app);
|
|
158
162
|
|
|
159
163
|
// Create PlaySocket server with your HTTP server
|
|
160
|
-
// You'll likely want to use a custom path in this scenario
|
|
161
164
|
const playSocketServer = new PlaySocketServer({
|
|
162
165
|
server: httpServer,
|
|
163
166
|
path: '/socket'
|
|
164
167
|
});
|
|
165
168
|
|
|
166
169
|
// Start the server
|
|
167
|
-
httpServer.listen(
|
|
170
|
+
httpServer.listen(3000, () => {
|
|
168
171
|
console.log('Server running on port 3000');
|
|
169
172
|
});
|
|
170
173
|
|
|
171
|
-
// Gracefully disconnect all clients and close the server (
|
|
174
|
+
// Gracefully disconnect all clients and close the server (recommended)
|
|
172
175
|
function shutdown() {
|
|
173
176
|
server.stop();
|
|
174
177
|
process.exit(0);
|
|
@@ -201,15 +204,17 @@ Creates a new PlaySocket Server instance with configuration options.
|
|
|
201
204
|
- `stop`: Closes all active client connections, the websocket server and the underlying http server if it's standalone
|
|
202
205
|
- `kick(clientId: string, reason?: string)`: Kick a client by their clientID – this will close their connection and set an error message
|
|
203
206
|
- `onEvent(event: string, callback: Function)`: Register a server-side event callback
|
|
207
|
+
- `getRoomStorage(roomId: string)`: Get a snapshot of the current room storage (returns storage `object`)
|
|
208
|
+
- `updateRoomStorage(roomId: string, key: string, type: 'set' | 'array-add' | 'array-add-unique' | 'array-remove-matching' | 'array-update-matching', value: any, updateValue?: any)`: Update the shared room storage from the server.
|
|
204
209
|
|
|
205
|
-
|
|
210
|
+
#### Event types
|
|
206
211
|
|
|
207
212
|
- `clientRegistered`: Client registered with the server (returns the client's id `string`, customData `object`)
|
|
208
213
|
- `clientDisconnected`: Client disconnected from the server (returns the client's id `string`)
|
|
209
214
|
- `clientJoinedRoom`: Client joined a room – note that clients can only leave by disconnecting (returns the client's id `string`, room id `string`)
|
|
210
215
|
- `roomCreated`: Client created a room (returns room id `string`)
|
|
211
216
|
- `roomDestroyed`: Room was destroyed, this happens when all participants leave (returns room id `string`)
|
|
212
|
-
- `roomCreationRequested`: Room creation requested by client (returns `object` containing the client's id `string`, room id `string` and the initialStorage `object`) – if you return an object, it will take that as the initial storage instead
|
|
217
|
+
- `roomCreationRequested`: Room creation requested by client (returns `object` containing the client's id `string`, room id `string` and the initialStorage `object`) – if you return an `object` in the callback, it will take that as the initial storage instead
|
|
213
218
|
- `storageUpdateRequested`: Room storage property update requested by client (returns `object` containing the client's id `string`, room id `string` and the update `object`) – if you return `false` in the callback, the update will be blocked
|
|
214
219
|
|
|
215
220
|
### Properties (Read-only)
|
|
@@ -218,8 +223,4 @@ Creates a new PlaySocket Server instance with configuration options.
|
|
|
218
223
|
|
|
219
224
|
# License
|
|
220
225
|
|
|
221
|
-
MIT
|
|
222
|
-
|
|
223
|
-
# Contributing
|
|
224
|
-
|
|
225
|
-
Please feel free to fork the repository and submit a Pull Request.
|
|
226
|
+
MIT
|
|
@@ -2407,7 +2407,7 @@ class PlaySocket {
|
|
|
2407
2407
|
|
|
2408
2408
|
/**
|
|
2409
2409
|
* Update the host in case a new one was chosen
|
|
2410
|
-
* @param {string} hostId - Client
|
|
2410
|
+
* @param {string} hostId - Client ID of new host
|
|
2411
2411
|
* @private
|
|
2412
2412
|
*/
|
|
2413
2413
|
#setHost(hostId) {
|
|
@@ -2492,33 +2492,31 @@ class PlaySocket {
|
|
|
2492
2492
|
/**
|
|
2493
2493
|
* Update a value in the shared storage
|
|
2494
2494
|
* @param {string} key - Storage key
|
|
2495
|
-
* @param {
|
|
2495
|
+
* @param {string} type - Operation type: add, add-unique, remove-matching, update-matching
|
|
2496
|
+
* @param {*} value - New value or value to operate on
|
|
2497
|
+
* @param {*} updateValue - New value for update-matching
|
|
2496
2498
|
*/
|
|
2497
|
-
updateStorage(key, value) {
|
|
2498
|
-
if (this.#debug) console.log(LOG_PREFIX +
|
|
2499
|
-
const propUpdate = this.#crdtManager.updateProperty(key,
|
|
2499
|
+
updateStorage(key, type, value, updateValue) {
|
|
2500
|
+
if (this.#debug) console.log(LOG_PREFIX + `Property update for key ${key}, operation ${type}, value ${value} and updateValue ${updateValue}.`);
|
|
2501
|
+
const propUpdate = this.#crdtManager.updateProperty(key, type, value, updateValue);
|
|
2500
2502
|
this.#sendToServer({
|
|
2501
2503
|
type: 'update_property',
|
|
2502
2504
|
update: propUpdate
|
|
2503
2505
|
});
|
|
2504
|
-
if (this.#crdtManager.didPropertiesChange) this.#triggerEvent("storageUpdated", this.getStorage); // Always trigger callback
|
|
2506
|
+
if (this.#crdtManager.didPropertiesChange) this.#triggerEvent("storageUpdated", this.getStorage); // Always trigger callback AFTER send in case msgs are sent in the callback (which would break the order)
|
|
2505
2507
|
}
|
|
2506
2508
|
|
|
2507
2509
|
/**
|
|
2508
|
-
*
|
|
2509
|
-
* @param {string}
|
|
2510
|
-
* @param {
|
|
2511
|
-
* @param {*} value - Value to operate on
|
|
2512
|
-
* @param {*} updateValue - New value for update-matching
|
|
2510
|
+
* Send a custom request to the server
|
|
2511
|
+
* @param {string} name - Name of the request
|
|
2512
|
+
* @param {*} [data] - Custom data
|
|
2513
2513
|
*/
|
|
2514
|
-
|
|
2515
|
-
if (this.#debug) console.log(LOG_PREFIX + `
|
|
2516
|
-
const propUpdate = this.#crdtManager.updateProperty(key, "array-" + operation, value, updateValue);
|
|
2514
|
+
sendRequest(name, data) {
|
|
2515
|
+
if (this.#debug) console.log(LOG_PREFIX + `Server request with name ${name} and data:`, data);
|
|
2517
2516
|
this.#sendToServer({
|
|
2518
|
-
type: '
|
|
2519
|
-
|
|
2517
|
+
type: 'request',
|
|
2518
|
+
request: { name, data }
|
|
2520
2519
|
});
|
|
2521
|
-
if (this.#crdtManager.didPropertiesChange) this.#triggerEvent("storageUpdated", this.getStorage);
|
|
2522
2520
|
}
|
|
2523
2521
|
|
|
2524
2522
|
/**
|
|
@@ -2341,7 +2341,7 @@ function requireServer () {
|
|
|
2341
2341
|
clearTimeout(pd.timeout);
|
|
2342
2342
|
this.#pendingDisconnects.delete(data.id);
|
|
2343
2343
|
|
|
2344
|
-
// Re-assign old client
|
|
2344
|
+
// Re-assign old client ID to the new ws connection
|
|
2345
2345
|
ws.clientId = data.id;
|
|
2346
2346
|
this.#clients.set(data.id, ws);
|
|
2347
2347
|
|
|
@@ -2372,7 +2372,7 @@ function requireServer () {
|
|
|
2372
2372
|
if (this.#clientRooms.get(ws.clientId) || this.#rooms[newRoomId]) {
|
|
2373
2373
|
ws.send(encode({
|
|
2374
2374
|
type: 'room_creation_failed',
|
|
2375
|
-
reason: this.#clientRooms.get(ws.clientId) ? 'Already in a room' : 'Room
|
|
2375
|
+
reason: this.#clientRooms.get(ws.clientId) ? 'Already in a room' : 'Room ID is taken'
|
|
2376
2376
|
}), { binary: true });
|
|
2377
2377
|
return;
|
|
2378
2378
|
}
|
|
@@ -2491,6 +2491,11 @@ function requireServer () {
|
|
|
2491
2491
|
}
|
|
2492
2492
|
break;
|
|
2493
2493
|
|
|
2494
|
+
case 'request':
|
|
2495
|
+
const requestorRoomId = this.#clientRooms.get(ws.clientId) || null;
|
|
2496
|
+
this.#triggerEvent("requestReceived", { roomId: requestorRoomId, clientId: ws.clientId, name: data.request.name, data: data.request.data });
|
|
2497
|
+
break;
|
|
2498
|
+
|
|
2494
2499
|
case 'disconnect':
|
|
2495
2500
|
// Client signals to server that it will will willfully disconnect soon
|
|
2496
2501
|
ws.willfulDisconnect = true;
|
|
@@ -2622,7 +2627,7 @@ function requireServer () {
|
|
|
2622
2627
|
}
|
|
2623
2628
|
}
|
|
2624
2629
|
|
|
2625
|
-
this.#triggerEvent("clientDisconnected", ws.clientId);
|
|
2630
|
+
this.#triggerEvent("clientDisconnected", ws.clientId, roomId);
|
|
2626
2631
|
}
|
|
2627
2632
|
|
|
2628
2633
|
/**
|
|
@@ -2631,7 +2636,7 @@ function requireServer () {
|
|
|
2631
2636
|
* @param {Function} callback - Callback function
|
|
2632
2637
|
*/
|
|
2633
2638
|
onEvent(event, callback) {
|
|
2634
|
-
const validEvents = ["clientRegistered", "clientDisconnected", "clientJoinedRoom", "roomCreationRequested", "roomCreated", "storageUpdateRequested", "roomDestroyed"];
|
|
2639
|
+
const validEvents = ["clientRegistered", "clientDisconnected", "clientJoinedRoom", "roomCreationRequested", "requestReceived", "roomCreated", "storageUpdateRequested", "roomDestroyed"];
|
|
2635
2640
|
if (!validEvents.includes(event)) return console.warn(`Invalid PlaySocket event type "${event}"`);
|
|
2636
2641
|
if (!this.#callbacks.has(event)) this.#callbacks.set(event, []);
|
|
2637
2642
|
this.#callbacks.get(event).push(callback);
|
|
@@ -2671,6 +2676,44 @@ function requireServer () {
|
|
|
2671
2676
|
return true;
|
|
2672
2677
|
}
|
|
2673
2678
|
|
|
2679
|
+
/**
|
|
2680
|
+
* Get snapshot of a room's storage
|
|
2681
|
+
* @returns {Object} - Storage object
|
|
2682
|
+
*/
|
|
2683
|
+
getRoomStorage(roomId) {
|
|
2684
|
+
const room = this.#rooms[roomId];
|
|
2685
|
+
if (room) return room.crdtManager.getPropertyStore;
|
|
2686
|
+
}
|
|
2687
|
+
|
|
2688
|
+
/**
|
|
2689
|
+
* Update a value in a room's storage
|
|
2690
|
+
* @param {string} roomId - Room ID
|
|
2691
|
+
* @param {string} key - Storage key
|
|
2692
|
+
* @param {string} type - Operation type
|
|
2693
|
+
* @param {*} value - New value or value to operate on
|
|
2694
|
+
* @param {*} updateValue - New value for update-matching
|
|
2695
|
+
*/
|
|
2696
|
+
updateRoomStorage(roomId, key, type, value, updateValue) {
|
|
2697
|
+
if (this.#debug) console.log(`Playsocket server property update for room ${roomId}, key ${key}, operation ${type}, value ${value} and updateValue ${updateValue}.`);
|
|
2698
|
+
const room = this.#rooms[roomId];
|
|
2699
|
+
if (room) {
|
|
2700
|
+
const propertyUpdate = room.crdtManager.updateProperty(key, type, value, updateValue);
|
|
2701
|
+
const currentVersion = this.#roomVersions.get(roomId) + 1;
|
|
2702
|
+
this.#roomVersions.set(roomId, currentVersion); // Increment version for this room
|
|
2703
|
+
|
|
2704
|
+
room.participants?.forEach(p => {
|
|
2705
|
+
const client = this.#clients.get(p);
|
|
2706
|
+
if (client) {
|
|
2707
|
+
client.send(encode({
|
|
2708
|
+
type: 'property_updated',
|
|
2709
|
+
update: propertyUpdate,
|
|
2710
|
+
version: currentVersion
|
|
2711
|
+
}), { binary: true });
|
|
2712
|
+
}
|
|
2713
|
+
});
|
|
2714
|
+
}
|
|
2715
|
+
}
|
|
2716
|
+
|
|
2674
2717
|
/**
|
|
2675
2718
|
* Close all client connections, then close the websocket and http server
|
|
2676
2719
|
*/
|
|
@@ -2683,11 +2726,7 @@ function requireServer () {
|
|
|
2683
2726
|
});
|
|
2684
2727
|
this.#wss.close();
|
|
2685
2728
|
}
|
|
2686
|
-
if (this.#server && this.#ownsServer) {
|
|
2687
|
-
this.#server.close(() => {
|
|
2688
|
-
console.log('PlaySocket server stopped.');
|
|
2689
|
-
});
|
|
2690
|
-
}
|
|
2729
|
+
if (this.#server && this.#ownsServer) this.#server.close(() => { console.log('PlaySocket server stopped.'); });
|
|
2691
2730
|
this.#pendingDisconnects.forEach((data) => {
|
|
2692
2731
|
clearTimeout(data.timeout);
|
|
2693
2732
|
});
|