@quakejs/master 1.0.17 → 1.0.18

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/master-client.js CHANGED
@@ -2,40 +2,36 @@ import MasterBase from './master-base.js';
2
2
 
3
3
  class MasterClient extends MasterBase {
4
4
  #onserver;
5
- #master;
6
5
 
7
6
  constructor (onserver) {
8
7
  super();
9
8
 
10
9
  this.#onserver = onserver;
11
- this.#master = null;
12
10
  }
13
11
 
14
12
  subscribe (host, port) {
15
- let resendTimeout;
16
-
17
- if (this.#master) {
18
- try {
19
- this.#master.close();
20
- } catch (e) {
21
- console.error(e);
22
- } finally {
23
- this.#master = null;
24
- }
25
- }
13
+ const session = new WebTransport(`${host}:${port}`);
26
14
 
27
- this.#master = new WebTransport(`${host}:${port}`);
15
+ /* prevent unhandled rejections before main loop */
16
+ session.ready.catch(() => {});
17
+ session.closed.catch(() => {});
28
18
 
29
19
  (async () => {
30
20
  try {
31
- await this.#master.ready;
21
+ const sessionClosed = session.closed.then(
22
+ () => ({ done: true, value: null }),
23
+ (err) => { throw err; }
24
+ );
32
25
 
33
- const writer = this.#master.datagrams.writable.getWriter();
34
- const reader = this.#master.datagrams.readable.getReader();
26
+ await session.ready;
27
+
28
+ const writer = session.datagrams.writable.getWriter();
29
+ const reader = session.datagrams.readable.getReader();
30
+ let resendTimeout;
35
31
 
36
32
  /* send until a response is received */
37
33
  const send = () => {
38
- writer.write(this.encode('subscribe'));
34
+ writer.write(this.encode('subscribe')).catch(() => {});
39
35
 
40
36
  resendTimeout = setTimeout(send, 1000);
41
37
  };
@@ -44,7 +40,10 @@ class MasterClient extends MasterBase {
44
40
 
45
41
  /* read responses */
46
42
  while (true) {
47
- const { done, value } = await reader.read();
43
+ const { done, value } = await Promise.race([
44
+ reader.read(),
45
+ sessionClosed
46
+ ]);
48
47
 
49
48
  clearTimeout(resendTimeout);
50
49
 
@@ -62,100 +61,146 @@ class MasterClient extends MasterBase {
62
61
  }
63
62
  }
64
63
  }
64
+
65
+ console.log(`Disconnected from master server`);
65
66
  } catch (e) {
66
- console.error(`Stream error, connection to ${host}:${port} lost`, e);
67
+ console.error('Disconnected from master server due to error', e);
67
68
  } finally {
68
- this.#master = null;
69
+ clearTimeout(resendTimeout);
69
70
  }
70
71
  })();
71
72
  }
72
73
 
73
74
  async getinfo (addr, port) {
74
75
  const session = new WebTransport(`https://${addr}:${port}`);
75
- const writer = session.datagrams.writable.getWriter();
76
- const reader = session.datagrams.readable.getReader();
77
76
  let resendTimeout;
78
- let begin;
77
+ let res;
79
78
 
80
- await session.ready;
79
+ session.ready.catch(() => {});
80
+ session.closed.catch(() => {});
81
81
 
82
- /* send request multiple times until something is read back */
83
- const send = () => {
84
- begin = performance.now();
82
+ try {
83
+ const sessionClosed = session.closed.then(
84
+ () => ({ done: true, value: null }),
85
+ (err) => { throw err; }
86
+ );
85
87
 
86
- writer.write(this.encode('getinfo'));
88
+ await session.ready;
87
89
 
88
- resendTimeout = setTimeout(send, 3000);
89
- };
90
+ const writer = session.datagrams.writable.getWriter();
91
+ const reader = session.datagrams.readable.getReader();
92
+ let begin;
90
93
 
91
- send();
94
+ /* send request multiple times until something is read back */
95
+ const send = () => {
96
+ begin = performance.now();
92
97
 
93
- /* read response */
94
- const { done, value } = await reader.read();
98
+ writer.write(this.encode('getinfo')).catch(() => {});
95
99
 
96
- clearTimeout(resendTimeout);
100
+ resendTimeout = setTimeout(send, 3000);
101
+ };
97
102
 
98
- if (done) {
99
- throw new Error('getinfo failed, no response received');
100
- }
103
+ send();
101
104
 
102
- console.log(`${addr}:${port} ---> ${this.pretty(value)}`);
105
+ /* read response */
106
+ const { done, value } = await Promise.race([
107
+ reader.read(),
108
+ sessionClosed
109
+ ]);
103
110
 
104
- const msg = this.decode(value);
111
+ clearTimeout(resendTimeout);
105
112
 
106
- if (!msg || msg.type !== 'infoResponse') {
107
- throw new Error('getinfo failed, didn\'t receive infoResponse');
108
- }
113
+ if (done) {
114
+ throw new Error('stream closed');
115
+ }
116
+
117
+ console.log(`${addr}:${port} ---> ${this.pretty(value)}`);
109
118
 
110
- msg.info.ping = Math.min((performance.now() - begin) >>> 0, 999);
119
+ const msg = this.decode(value);
111
120
 
112
- session.close();
121
+ if (!msg || msg.type !== 'infoResponse') {
122
+ throw new Error('invalid response type');
123
+ }
113
124
 
114
- return msg.info;
125
+ msg.info.ping = Math.min((performance.now() - begin) >>> 0, 999);
126
+
127
+ res = msg.info;
128
+ } catch (e) {
129
+ console.error('getinfo failed', e);
130
+ throw e;
131
+ } finally {
132
+ clearTimeout(resendTimeout);
133
+
134
+ session.close();
135
+ }
136
+
137
+ return res;
115
138
  }
116
139
 
117
140
  async getstatus (addr, port) {
118
141
  const session = new WebTransport(`https://${addr}:${port}`);
119
- const writer = session.datagrams.writable.getWriter();
120
- const reader = session.datagrams.readable.getReader();
121
142
  let resendTimeout;
122
- let begin;
143
+ let res;
123
144
 
124
- await session.ready;
145
+ session.ready.catch(() => {});
146
+ session.closed.catch(() => {});
125
147
 
126
- /* send request multiple times until something is read back */
127
- const send = () => {
128
- begin = performance.now();
148
+ try {
149
+ const sessionClosed = session.closed.then(
150
+ () => ({ done: true, value: null }),
151
+ (err) => { throw err; }
152
+ );
129
153
 
130
- writer.write(this.encode('getstatus'));
154
+ await session.ready;
131
155
 
132
- resendTimeout = setTimeout(send, 3000);
133
- };
156
+ const writer = session.datagrams.writable.getWriter();
157
+ const reader = session.datagrams.readable.getReader();
158
+ let begin;
134
159
 
135
- send();
160
+ /* send request multiple times until something is read back */
161
+ const send = () => {
162
+ begin = performance.now();
136
163
 
137
- /* read response */
138
- const { done, value } = await reader.read();
164
+ writer.write(this.encode('getstatus')).catch(() => {});
139
165
 
140
- clearTimeout(resendTimeout);
166
+ resendTimeout = setTimeout(send, 3000);
167
+ };
141
168
 
142
- if (done) {
143
- throw new Error('getstatus failed, no response received');
144
- }
169
+ send();
145
170
 
146
- console.log(`${addr}:${port} ---> ${this.pretty(value)}`);
171
+ /* read response */
172
+ const { done, value } = await Promise.race([
173
+ reader.read(),
174
+ sessionClosed
175
+ ]);
147
176
 
148
- const msg = this.decode(value);
177
+ clearTimeout(resendTimeout);
149
178
 
150
- if (!msg || msg.type !== 'statusResponse') {
151
- throw new Error('getstatus failed, didn\'t receive statusResponse');
152
- }
179
+ if (done) {
180
+ throw new Error('stream closed');
181
+ }
153
182
 
154
- msg.info.ping = Math.min((performance.now() - begin) >>> 0, 999);
183
+ console.log(`${addr}:${port} ---> ${this.pretty(value)}`);
155
184
 
156
- session.close();
185
+ const msg = this.decode(value);
186
+
187
+ if (!msg || msg.type !== 'statusResponse') {
188
+ throw new Error('invalid response type');
189
+ }
190
+
191
+ msg.info.ping = Math.min((performance.now() - begin) >>> 0, 999);
192
+
193
+ res = { info: msg.info, players: msg.players };
194
+ } catch (e) {
195
+ console.error('getstatus failed', e);
196
+ throw e;
197
+ } finally {
198
+ clearTimeout(resendTimeout);
199
+
200
+ session.close();
201
+ }
157
202
 
158
- return { info: msg.info, players: msg.players };
203
+ return res;
159
204
  }
160
205
  }
161
206
 
package/master-server.js CHANGED
@@ -158,11 +158,20 @@ class MasterServer extends MasterBase {
158
158
  break;
159
159
  }
160
160
 
161
+ /* prevent unhandled rejections before main loop */
162
+ session.ready.catch(() => {});
163
+ session.closed.catch(() => {});
164
+
161
165
  (async () => {
162
166
  try {
167
+ const sessionClosed = session.closed.then(
168
+ () => ({ done: true, value: null }),
169
+ (err) => { throw err; }
170
+ );
171
+
163
172
  await session.ready;
164
173
 
165
- const writer = session.datagrams.createWritable().getWriter();
174
+ const writer = session.datagrams.writable.getWriter();
166
175
  const reader = session.datagrams.readable.getReader();
167
176
  const [addr, port] = session.peerAddress.split(':');
168
177
  let first = true;
@@ -171,11 +180,14 @@ class MasterServer extends MasterBase {
171
180
  session.port = port;
172
181
 
173
182
  session.write = (data) => {
174
- writer.write(data);
183
+ writer.write(data).catch(e => {});
175
184
  };
176
185
 
177
186
  while (true) {
178
- const { done, value } = await reader.read();
187
+ const { done, value } = await Promise.race([
188
+ reader.read(),
189
+ sessionClosed
190
+ ]);
179
191
 
180
192
  if (done) {
181
193
  break;
@@ -214,10 +226,8 @@ class MasterServer extends MasterBase {
214
226
  break;
215
227
  }
216
228
  }
217
-
218
- console.log(`Client ${session.addr}:${session.port} disconnected`);
219
229
  } catch (e) {
220
- console.error(`Client ${session.addr}:${session.port} disconnected due to error`, e);
230
+ console.error(`Client ${session.addr}:${session.port} terminated`, e);
221
231
  } finally {
222
232
  this.#removeClient(session);
223
233
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@quakejs/master",
3
- "version": "1.0.17",
3
+ "version": "1.0.18",
4
4
  "type": "module",
5
5
  "main": "index.js",
6
6
  "bin": {