@honeybbq/teamspeak 1.0.0-beta.22 → 1.0.0-beta.23
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/client/discovery/resolver.d.ts +35 -2
- package/dist/client/discovery/resolver.d.ts.map +1 -1
- package/dist/client/discovery/resolver.js +122 -41
- package/dist/client/discovery/resolver.js.map +1 -1
- package/dist/client/index.d.ts +2 -0
- package/dist/client/index.d.ts.map +1 -1
- package/dist/client/index.js +1 -0
- package/dist/client/index.js.map +1 -1
- package/package.json +1 -1
- package/src/client/discovery/resolver.ts +154 -49
- package/src/client/index.ts +3 -0
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { ResolvedAddr } from "../types.js";
|
|
1
|
+
import type { AddrResolver, ResolvedAddr } from "../types.js";
|
|
2
2
|
/**
|
|
3
3
|
* The most a TSDNS server or the nickname service is read for. Either answers
|
|
4
4
|
* with one short line; without a bound, one that kept sending would be held in
|
|
@@ -9,8 +9,23 @@ export declare const MAX_DISCOVERY_RESPONSE: number;
|
|
|
9
9
|
export interface ResolverOptions {
|
|
10
10
|
/** Look dot-less names up at named.myteamspeak.com; off by default. */
|
|
11
11
|
readonly nicknameLookup?: boolean | undefined;
|
|
12
|
+
/**
|
|
13
|
+
* The nickname lookup endpoint, an http: or https: URL; the default is
|
|
14
|
+
* `https://named.myteamspeak.com/lookup`. Used only with `nicknameLookup`:
|
|
15
|
+
* setting it does not turn the lookup on. For a test double or a mirror of
|
|
16
|
+
* the service. The name is sent as the `name` query parameter, and the first
|
|
17
|
+
* line of the answer is the address. A URL that is not http: or https: throws
|
|
18
|
+
* a TypeError.
|
|
19
|
+
*/
|
|
20
|
+
readonly nicknameService?: string | URL | undefined;
|
|
12
21
|
}
|
|
13
|
-
|
|
22
|
+
/**
|
|
23
|
+
* The resolver a Client uses unless it is given another. It resolves as the
|
|
24
|
+
* TeamSpeak application does, so on its own it shows where an address leads:
|
|
25
|
+
* `await new Resolver().resolve("ts.example.com")`. Answers are kept for ten
|
|
26
|
+
* minutes.
|
|
27
|
+
*/
|
|
28
|
+
export declare class Resolver implements AddrResolver {
|
|
14
29
|
#private;
|
|
15
30
|
constructor(options?: ResolverOptions);
|
|
16
31
|
/**
|
|
@@ -23,4 +38,22 @@ export declare class Resolver {
|
|
|
23
38
|
readonly signal?: AbortSignal | undefined;
|
|
24
39
|
}): Promise<ResolvedAddr[]>;
|
|
25
40
|
}
|
|
41
|
+
/**
|
|
42
|
+
* Ask a TSDNS server where `host` is. The answer is the server's targets in
|
|
43
|
+
* its order and as it sent them: an entry may have no port, which TeamSpeak
|
|
44
|
+
* takes as 9987, or the literal port `$PORT`, the port the user gave (9987 by
|
|
45
|
+
* default). {@link Resolver} applies both. A name the server has no record for
|
|
46
|
+
* gives an empty list.
|
|
47
|
+
*
|
|
48
|
+
* The answer ends at its first line break or when the server closes the
|
|
49
|
+
* connection, whichever comes first. It rejects when the connection fails,
|
|
50
|
+
* when no answer completes within three seconds or grows past 8 KiB, and with
|
|
51
|
+
* the signal's reason when it aborts.
|
|
52
|
+
*
|
|
53
|
+
* @param server - The TSDNS server, `host` or `host:port`; the port defaults to 41144.
|
|
54
|
+
* @param host - The name to look up; it is sent without a port.
|
|
55
|
+
*/
|
|
56
|
+
export declare function lookupTSDNS(server: string, host: string, options?: {
|
|
57
|
+
readonly signal?: AbortSignal | undefined;
|
|
58
|
+
}): Promise<string[]>;
|
|
26
59
|
//# sourceMappingURL=resolver.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"resolver.d.ts","sourceRoot":"","sources":["../../../src/client/discovery/resolver.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"resolver.d.ts","sourceRoot":"","sources":["../../../src/client/discovery/resolver.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAqB9D;;;;GAIG;AACH,eAAO,MAAM,sBAAsB,EAAE,MAAiB,CAAC;AAEvD,yCAAyC;AACzC,MAAM,WAAW,eAAe;IAC9B,uEAAuE;IACvE,QAAQ,CAAC,cAAc,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IAC9C;;;;;;;OAOG;IACH,QAAQ,CAAC,eAAe,CAAC,EAAE,MAAM,GAAG,GAAG,GAAG,SAAS,CAAC;CACrD;AAED;;;;;GAKG;AACH,qBAAa,QAAS,YAAW,YAAY;;IAK3C,YAAY,OAAO,GAAE,eAAoB,EAGxC;IAED;;;;;OAKG;IACG,OAAO,CACX,SAAS,EAAE,MAAM,EACjB,OAAO,GAAE;QAAE,QAAQ,CAAC,MAAM,CAAC,EAAE,WAAW,GAAG,SAAS,CAAA;KAAO,GAC1D,OAAO,CAAC,YAAY,EAAE,CAAC,CAYzB;CA0HF;AAgJD;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,WAAW,CACzB,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,MAAM,EACZ,OAAO,GAAE;IAAE,QAAQ,CAAC,MAAM,CAAC,EAAE,WAAW,GAAG,SAAS,CAAA;CAAO,GAC1D,OAAO,CAAC,MAAM,EAAE,CAAC,CAuDnB"}
|
|
@@ -3,8 +3,11 @@ import { createConnection } from "node:net";
|
|
|
3
3
|
import { ResolveSource } from "../types.js";
|
|
4
4
|
import { isIpAddress, joinHostPort, splitHostPort } from "../address.js";
|
|
5
5
|
import { abortable } from "../abort.js";
|
|
6
|
+
import { TeamspeakError } from "@honeybbq/teamspeak";
|
|
6
7
|
import { InvalidAddressError } from "../errors.js";
|
|
7
8
|
const TS_DNS_DEFAULT_PORT = 41144;
|
|
9
|
+
/** What a TSDNS entry has for a port to say: the one the user gave. */
|
|
10
|
+
const PORT_PLACEHOLDER = ":$PORT";
|
|
8
11
|
const NICKNAME_LOOKUP_URL = "https://named.myteamspeak.com/lookup";
|
|
9
12
|
const CACHE_TTL_MS = 10 * 60 * 1000;
|
|
10
13
|
/**
|
|
@@ -22,11 +25,19 @@ const TSDNS_TIMEOUT_MS = 3_000;
|
|
|
22
25
|
* memory until the resolution budget ran out.
|
|
23
26
|
*/
|
|
24
27
|
export const MAX_DISCOVERY_RESPONSE = 8 * 1024;
|
|
28
|
+
/**
|
|
29
|
+
* The resolver a Client uses unless it is given another. It resolves as the
|
|
30
|
+
* TeamSpeak application does, so on its own it shows where an address leads:
|
|
31
|
+
* `await new Resolver().resolve("ts.example.com")`. Answers are kept for ten
|
|
32
|
+
* minutes.
|
|
33
|
+
*/
|
|
25
34
|
export class Resolver {
|
|
26
35
|
#cache = new Map();
|
|
27
36
|
#nicknameLookup;
|
|
37
|
+
#nicknameService;
|
|
28
38
|
constructor(options = {}) {
|
|
29
39
|
this.#nicknameLookup = options.nicknameLookup ?? false;
|
|
40
|
+
this.#nicknameService = parseNicknameService(options.nicknameService ?? NICKNAME_LOOKUP_URL);
|
|
30
41
|
}
|
|
31
42
|
/**
|
|
32
43
|
* Resolve as the TeamSpeak application does: a server nickname (only with
|
|
@@ -62,7 +73,7 @@ export class Resolver {
|
|
|
62
73
|
// service can answer: asking it sends the name to a third party, so it is
|
|
63
74
|
// opt-in. Otherwise the name is resolved like any host.
|
|
64
75
|
if (nicknames && this.#nicknameLookup && !host.includes(".") && host !== "localhost") {
|
|
65
|
-
const nickAddr = await resolveNickname(host, signal);
|
|
76
|
+
const nickAddr = await resolveNickname(host, this.#nicknameService, signal);
|
|
66
77
|
signal.throwIfAborted();
|
|
67
78
|
if (nickAddr)
|
|
68
79
|
return this.#resolve(nickAddr, signal, false);
|
|
@@ -73,14 +84,14 @@ export class Resolver {
|
|
|
73
84
|
return this.#setCache(inputAddr, srvResults);
|
|
74
85
|
const domainList = getDomainList(host);
|
|
75
86
|
// TSDNS via SRV _tsdns._tcp.<domain>
|
|
76
|
-
const tsdnsSrv = await this.#resolveTSDNSSRV(domainList, host, signal);
|
|
77
|
-
if (tsdnsSrv) {
|
|
78
|
-
return this.#setCache(inputAddr,
|
|
87
|
+
const tsdnsSrv = await this.#resolveTSDNSSRV(domainList, host, port, signal);
|
|
88
|
+
if (tsdnsSrv.length > 0) {
|
|
89
|
+
return this.#setCache(inputAddr, tsdnsSrv.map((addr) => ({ addr, source: ResolveSource.TSDNSSRV })));
|
|
79
90
|
}
|
|
80
91
|
// TSDNS direct :41144
|
|
81
|
-
const tsdnsDirect = await this.#resolveTSDNSDirect(domainList, host, signal);
|
|
82
|
-
if (tsdnsDirect) {
|
|
83
|
-
return this.#setCache(inputAddr,
|
|
92
|
+
const tsdnsDirect = await this.#resolveTSDNSDirect(domainList, host, port, signal);
|
|
93
|
+
if (tsdnsDirect.length > 0) {
|
|
94
|
+
return this.#setCache(inputAddr, tsdnsDirect.map((addr) => ({ addr, source: ResolveSource.TSDNSDirect })));
|
|
84
95
|
}
|
|
85
96
|
signal.throwIfAborted();
|
|
86
97
|
// Plain DNS fallback
|
|
@@ -118,7 +129,7 @@ export class Resolver {
|
|
|
118
129
|
return null;
|
|
119
130
|
}
|
|
120
131
|
}
|
|
121
|
-
async #resolveTSDNSSRV(domains, queryHost, signal) {
|
|
132
|
+
async #resolveTSDNSSRV(domains, queryHost, port, signal) {
|
|
122
133
|
for (const domain of domains) {
|
|
123
134
|
try {
|
|
124
135
|
const srvs = await abortable(resolveSrv(`_tsdns._tcp.${domain}`), signal);
|
|
@@ -126,8 +137,8 @@ export class Resolver {
|
|
|
126
137
|
continue;
|
|
127
138
|
for (const srv of orderSrvRecords(srvs)) {
|
|
128
139
|
const tsdnsAddr = joinHostPort(srv.name.replace(/\.$/, ""), String(srv.port));
|
|
129
|
-
const result = await
|
|
130
|
-
if (result)
|
|
140
|
+
const result = await askTSDNS(tsdnsAddr, queryHost, port, signal);
|
|
141
|
+
if (result.length > 0)
|
|
131
142
|
return result;
|
|
132
143
|
}
|
|
133
144
|
}
|
|
@@ -135,14 +146,43 @@ export class Resolver {
|
|
|
135
146
|
continue;
|
|
136
147
|
}
|
|
137
148
|
}
|
|
138
|
-
return
|
|
149
|
+
return [];
|
|
139
150
|
}
|
|
140
|
-
async #resolveTSDNSDirect(domains, queryHost, signal) {
|
|
151
|
+
async #resolveTSDNSDirect(domains, queryHost, port, signal) {
|
|
141
152
|
// Asked at once rather than in turn, so the probes cost one timeout in
|
|
142
153
|
// all; the most specific domain's answer wins.
|
|
143
|
-
const answers = await Promise.all(domains.map((domain) =>
|
|
144
|
-
return answers.find((answer) => answer
|
|
154
|
+
const answers = await Promise.all(domains.map((domain) => askTSDNS(joinHostPort(domain, String(TS_DNS_DEFAULT_PORT)), queryHost, port, signal)));
|
|
155
|
+
return answers.find((answer) => answer.length > 0) ?? [];
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
159
|
+
* Ask one TSDNS server; a server that fails to answer is one with no answer,
|
|
160
|
+
* so it never fails the resolution.
|
|
161
|
+
*/
|
|
162
|
+
async function askTSDNS(server, host, port, signal) {
|
|
163
|
+
try {
|
|
164
|
+
return normalizeTSDNSEntries(await lookupTSDNS(server, host, { signal }), port);
|
|
145
165
|
}
|
|
166
|
+
catch {
|
|
167
|
+
return [];
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* Make each entry of a TSDNS answer a `host:port`, as TeamSpeak reads it: an
|
|
172
|
+
* entry without a port means 9987, and the port `$PORT` means `port`, the one
|
|
173
|
+
* the address being resolved had.
|
|
174
|
+
*
|
|
175
|
+
* @internal
|
|
176
|
+
*/
|
|
177
|
+
export function normalizeTSDNSEntries(entries, port) {
|
|
178
|
+
return entries.map((entry) => {
|
|
179
|
+
if (entry.endsWith(PORT_PLACEHOLDER)) {
|
|
180
|
+
const host = splitHostPort(entry.slice(0, -PORT_PLACEHOLDER.length)).host;
|
|
181
|
+
return joinHostPort(host, port);
|
|
182
|
+
}
|
|
183
|
+
const target = splitHostPort(entry, "9987");
|
|
184
|
+
return joinHostPort(target.host, target.port);
|
|
185
|
+
});
|
|
146
186
|
}
|
|
147
187
|
/**
|
|
148
188
|
* Put SRV records in the order RFC 2782 has a client try them: by priority,
|
|
@@ -188,10 +228,23 @@ export function orderSrvRecords(records, random = Math.random) {
|
|
|
188
228
|
}
|
|
189
229
|
return ordered;
|
|
190
230
|
}
|
|
231
|
+
function parseNicknameService(service) {
|
|
232
|
+
let url;
|
|
233
|
+
try {
|
|
234
|
+
url = new URL(service);
|
|
235
|
+
}
|
|
236
|
+
catch {
|
|
237
|
+
throw new TypeError(`nicknameService is not a URL: ${String(service)}`);
|
|
238
|
+
}
|
|
239
|
+
if (url.protocol !== "http:" && url.protocol !== "https:") {
|
|
240
|
+
throw new TypeError(`nicknameService is an http: or https: URL, not ${url.protocol}`);
|
|
241
|
+
}
|
|
242
|
+
return url;
|
|
243
|
+
}
|
|
191
244
|
/** @internal Ask the nickname service for `nickname`'s address. */
|
|
192
|
-
export async function resolveNickname(nickname, signal) {
|
|
245
|
+
export async function resolveNickname(nickname, service, signal) {
|
|
193
246
|
try {
|
|
194
|
-
const url = new URL(
|
|
247
|
+
const url = new URL(service);
|
|
195
248
|
url.searchParams.set("name", nickname);
|
|
196
249
|
const init = signal ? { signal } : {};
|
|
197
250
|
const resp = await fetch(url.toString(), init);
|
|
@@ -227,46 +280,74 @@ async function readLimited(resp, limit) {
|
|
|
227
280
|
}
|
|
228
281
|
return Buffer.concat(chunks).toString("utf8");
|
|
229
282
|
}
|
|
230
|
-
/**
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
283
|
+
/**
|
|
284
|
+
* Ask a TSDNS server where `host` is. The answer is the server's targets in
|
|
285
|
+
* its order and as it sent them: an entry may have no port, which TeamSpeak
|
|
286
|
+
* takes as 9987, or the literal port `$PORT`, the port the user gave (9987 by
|
|
287
|
+
* default). {@link Resolver} applies both. A name the server has no record for
|
|
288
|
+
* gives an empty list.
|
|
289
|
+
*
|
|
290
|
+
* The answer ends at its first line break or when the server closes the
|
|
291
|
+
* connection, whichever comes first. It rejects when the connection fails,
|
|
292
|
+
* when no answer completes within three seconds or grows past 8 KiB, and with
|
|
293
|
+
* the signal's reason when it aborts.
|
|
294
|
+
*
|
|
295
|
+
* @param server - The TSDNS server, `host` or `host:port`; the port defaults to 41144.
|
|
296
|
+
* @param host - The name to look up; it is sent without a port.
|
|
297
|
+
*/
|
|
298
|
+
export function lookupTSDNS(server, host, options = {}) {
|
|
299
|
+
const { signal } = options;
|
|
300
|
+
const target = splitHostPort(server, String(TS_DNS_DEFAULT_PORT));
|
|
301
|
+
const port = parseInt(target.port, 10);
|
|
302
|
+
return new Promise((resolve, reject) => {
|
|
235
303
|
if (signal?.aborted)
|
|
236
|
-
return
|
|
237
|
-
const
|
|
304
|
+
return reject(signal.reason);
|
|
305
|
+
const chunks = [];
|
|
306
|
+
let size = 0;
|
|
307
|
+
let done = false;
|
|
308
|
+
const finish = (error, answer) => {
|
|
309
|
+
if (done)
|
|
310
|
+
return;
|
|
311
|
+
done = true;
|
|
238
312
|
clearTimeout(timeout);
|
|
239
313
|
signal?.removeEventListener("abort", onAbort);
|
|
240
314
|
socket.destroy();
|
|
241
|
-
|
|
315
|
+
if (error !== undefined)
|
|
316
|
+
reject(error);
|
|
317
|
+
else
|
|
318
|
+
resolve(answer ?? []);
|
|
319
|
+
};
|
|
320
|
+
const answerOf = (bytes) => {
|
|
321
|
+
const line = bytes.toString("utf8").trim();
|
|
322
|
+
return !line || line === "404" || line === "errors" ? [] : line.split(/\s+/);
|
|
242
323
|
};
|
|
243
|
-
const
|
|
244
|
-
const
|
|
245
|
-
const
|
|
246
|
-
|
|
324
|
+
const timedOut = () => finish(new TeamspeakError(`the TSDNS server ${server} did not answer in time`));
|
|
325
|
+
const onAbort = () => finish(signal?.reason);
|
|
326
|
+
const timeout = setTimeout(timedOut, TSDNS_TIMEOUT_MS);
|
|
327
|
+
const socket = createConnection({ host: target.host, port, timeout: 2_000 }, () => {
|
|
328
|
+
socket.write(`${host}\n`);
|
|
247
329
|
});
|
|
248
|
-
let buf = "";
|
|
249
330
|
socket.on("data", (chunk) => {
|
|
250
|
-
|
|
251
|
-
|
|
331
|
+
chunks.push(chunk);
|
|
332
|
+
size += chunk.length;
|
|
333
|
+
const all = chunks.length === 1 ? chunks[0] : Buffer.concat(chunks);
|
|
334
|
+
chunks.length = 0;
|
|
335
|
+
chunks.push(all);
|
|
336
|
+
const idx = all.indexOf(0x0a);
|
|
252
337
|
if (idx >= 0 && idx < MAX_DISCOVERY_RESPONSE) {
|
|
253
|
-
|
|
254
|
-
finish(!line || line === "404" || line === "errors" ? null : line);
|
|
338
|
+
finish(undefined, answerOf(all.subarray(0, idx)));
|
|
255
339
|
}
|
|
256
|
-
else if (
|
|
340
|
+
else if (size >= MAX_DISCOVERY_RESPONSE) {
|
|
257
341
|
// No answer is that long.
|
|
258
|
-
finish(
|
|
342
|
+
finish(new TeamspeakError(`the TSDNS server ${server} sent ${MAX_DISCOVERY_RESPONSE} bytes without ending its answer`));
|
|
259
343
|
}
|
|
260
344
|
});
|
|
261
|
-
socket.on("
|
|
262
|
-
socket.on("
|
|
345
|
+
socket.on("end", () => finish(undefined, answerOf(Buffer.concat(chunks))));
|
|
346
|
+
socket.on("error", (error) => finish(error));
|
|
347
|
+
socket.on("timeout", timedOut);
|
|
263
348
|
signal?.addEventListener("abort", onAbort, { once: true });
|
|
264
349
|
});
|
|
265
350
|
}
|
|
266
|
-
function splitHostPortParts(addr) {
|
|
267
|
-
const { host, port } = splitHostPort(addr);
|
|
268
|
-
return [host, port];
|
|
269
|
-
}
|
|
270
351
|
function getDomainList(host) {
|
|
271
352
|
const parts = host.split(".");
|
|
272
353
|
const list = [];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"resolver.js","sourceRoot":"","sources":["../../../src/client/discovery/resolver.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"resolver.js","sourceRoot":"","sources":["../../../src/client/discovery/resolver.ts"],"names":[],"mappings":"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"}
|
package/dist/client/index.d.ts
CHANGED
|
@@ -9,6 +9,8 @@
|
|
|
9
9
|
*/
|
|
10
10
|
export { Client } from "./client.js";
|
|
11
11
|
export { EventName, GroupWhisperType, GroupWhisperScope, ResolveSource } from "./types.js";
|
|
12
|
+
export { Resolver, lookupTSDNS } from "./discovery/resolver.js";
|
|
13
|
+
export type { ResolverOptions } from "./discovery/resolver.js";
|
|
12
14
|
export { ViewStatus } from "./view.js";
|
|
13
15
|
export type { ServerView, ViewChangedEvent, ViewReadyEvent } from "./view.js";
|
|
14
16
|
export type { EventMap, EventMiddleware, ServerEvent, ServerEventName, VoiceOptions, WhisperTargets, GroupWhisperTarget, AddrResolver, ClientOptions, ResolvedAddr, DatagramSocket, SocketFactory, FileTransferSocketFactory, } from "./types.js";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/client/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAGH,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACrC,OAAO,EAAE,SAAS,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAE3F,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AACvC,YAAY,EAAE,UAAU,EAAE,gBAAgB,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAE9E,YAAY,EACV,QAAQ,EACR,eAAe,EACf,WAAW,EACX,eAAe,EACf,YAAY,EACZ,cAAc,EACd,kBAAkB,EAClB,YAAY,EACZ,aAAa,EACb,YAAY,EACZ,cAAc,EACd,aAAa,EACb,yBAAyB,GAC1B,MAAM,YAAY,CAAC;AAEpB,OAAO,EACL,iBAAiB,EACjB,cAAc,EACd,kBAAkB,EAClB,mBAAmB,EACnB,oBAAoB,EACpB,YAAY,EACZ,sBAAsB,EACtB,sBAAsB,GACvB,MAAM,aAAa,CAAC;AAGrB,cAAc,gBAAgB,CAAC;AAC/B,cAAc,kBAAkB,CAAC;AACjC,cAAc,gBAAgB,CAAC;AAG/B,OAAO,EACL,gBAAgB,EAChB,cAAc,EACd,gBAAgB,EAChB,iBAAiB,GAClB,MAAM,eAAe,CAAC;AACvB,YAAY,EACV,mBAAmB,EACnB,iBAAiB,EACjB,yBAAyB,EACzB,wBAAwB,EACxB,wBAAwB,EACxB,oBAAoB,EACpB,sBAAsB,GACvB,MAAM,eAAe,CAAC;AAGvB,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC1C,YAAY,EACV,WAAW,EACX,gBAAgB,EAChB,eAAe,EACf,gBAAgB,EAChB,eAAe,EACf,iBAAiB,EACjB,gBAAgB,EAChB,eAAe,EACf,iBAAiB,EACjB,sBAAsB,EACtB,mBAAmB,EACnB,kBAAkB,EAClB,cAAc,EACd,oBAAoB,GACrB,MAAM,YAAY,CAAC;AAGpB,OAAO,EAAE,yBAAyB,EAAE,MAAM,mBAAmB,CAAC;AAC9D,YAAY,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AAG5D,OAAO,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AACnE,YAAY,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAGpE,OAAO,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AAGpD,OAAO,EACL,QAAQ,EACR,aAAa,EACb,gBAAgB,EAChB,oBAAoB,EACpB,gBAAgB,EAChB,sBAAsB,EACtB,kBAAkB,GACnB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/client/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAGH,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACrC,OAAO,EAAE,SAAS,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAE3F,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAChE,YAAY,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAE/D,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AACvC,YAAY,EAAE,UAAU,EAAE,gBAAgB,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAE9E,YAAY,EACV,QAAQ,EACR,eAAe,EACf,WAAW,EACX,eAAe,EACf,YAAY,EACZ,cAAc,EACd,kBAAkB,EAClB,YAAY,EACZ,aAAa,EACb,YAAY,EACZ,cAAc,EACd,aAAa,EACb,yBAAyB,GAC1B,MAAM,YAAY,CAAC;AAEpB,OAAO,EACL,iBAAiB,EACjB,cAAc,EACd,kBAAkB,EAClB,mBAAmB,EACnB,oBAAoB,EACpB,YAAY,EACZ,sBAAsB,EACtB,sBAAsB,GACvB,MAAM,aAAa,CAAC;AAGrB,cAAc,gBAAgB,CAAC;AAC/B,cAAc,kBAAkB,CAAC;AACjC,cAAc,gBAAgB,CAAC;AAG/B,OAAO,EACL,gBAAgB,EAChB,cAAc,EACd,gBAAgB,EAChB,iBAAiB,GAClB,MAAM,eAAe,CAAC;AACvB,YAAY,EACV,mBAAmB,EACnB,iBAAiB,EACjB,yBAAyB,EACzB,wBAAwB,EACxB,wBAAwB,EACxB,oBAAoB,EACpB,sBAAsB,GACvB,MAAM,eAAe,CAAC;AAGvB,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC1C,YAAY,EACV,WAAW,EACX,gBAAgB,EAChB,eAAe,EACf,gBAAgB,EAChB,eAAe,EACf,iBAAiB,EACjB,gBAAgB,EAChB,eAAe,EACf,iBAAiB,EACjB,sBAAsB,EACtB,mBAAmB,EACnB,kBAAkB,EAClB,cAAc,EACd,oBAAoB,GACrB,MAAM,YAAY,CAAC;AAGpB,OAAO,EAAE,yBAAyB,EAAE,MAAM,mBAAmB,CAAC;AAC9D,YAAY,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AAG5D,OAAO,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AACnE,YAAY,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAGpE,OAAO,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AAGpD,OAAO,EACL,QAAQ,EACR,aAAa,EACb,gBAAgB,EAChB,oBAAoB,EACpB,gBAAgB,EAChB,sBAAsB,EACtB,kBAAkB,GACnB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC"}
|
package/dist/client/index.js
CHANGED
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
// The client
|
|
11
11
|
export { Client } from "./client.js";
|
|
12
12
|
export { EventName, GroupWhisperType, GroupWhisperScope, ResolveSource } from "./types.js";
|
|
13
|
+
export { Resolver, lookupTSDNS } from "./discovery/resolver.js";
|
|
13
14
|
export { ViewStatus } from "./view.js";
|
|
14
15
|
export { FileTransferError, HandshakeError, PuzzleTooHardError, InvalidAddressError, InvalidIdentityError, RemovedError, ConnectionTimeoutError, ConnectionStalledError, } from "./errors.js";
|
|
15
16
|
// Commands only the voice protocol has.
|
package/dist/client/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/client/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,aAAa;AACb,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACrC,OAAO,EAAE,SAAS,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAE3F,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAmBvC,OAAO,EACL,iBAAiB,EACjB,cAAc,EACd,kBAAkB,EAClB,mBAAmB,EACnB,oBAAoB,EACpB,YAAY,EACZ,sBAAsB,EACtB,sBAAsB,GACvB,MAAM,aAAa,CAAC;AAErB,wCAAwC;AACxC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,kBAAkB,CAAC;AACjC,cAAc,gBAAgB,CAAC;AAE/B,qBAAqB;AACrB,OAAO,EACL,gBAAgB,EAChB,cAAc,EACd,gBAAgB,EAChB,iBAAiB,GAClB,MAAM,eAAe,CAAC;AAWvB,+BAA+B;AAC/B,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAkB1C,+CAA+C;AAC/C,OAAO,EAAE,yBAAyB,EAAE,MAAM,mBAAmB,CAAC;AAG9D,qDAAqD;AACrD,OAAO,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAGnE,sBAAsB;AACtB,OAAO,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AAEpD,WAAW;AACX,OAAO,EACL,QAAQ,EACR,aAAa,EACb,gBAAgB,EAChB,oBAAoB,EACpB,gBAAgB,EAChB,sBAAsB,EACtB,kBAAkB,GACnB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/client/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,aAAa;AACb,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACrC,OAAO,EAAE,SAAS,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAE3F,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAGhE,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAmBvC,OAAO,EACL,iBAAiB,EACjB,cAAc,EACd,kBAAkB,EAClB,mBAAmB,EACnB,oBAAoB,EACpB,YAAY,EACZ,sBAAsB,EACtB,sBAAsB,GACvB,MAAM,aAAa,CAAC;AAErB,wCAAwC;AACxC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,kBAAkB,CAAC;AACjC,cAAc,gBAAgB,CAAC;AAE/B,qBAAqB;AACrB,OAAO,EACL,gBAAgB,EAChB,cAAc,EACd,gBAAgB,EAChB,iBAAiB,GAClB,MAAM,eAAe,CAAC;AAWvB,+BAA+B;AAC/B,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAkB1C,+CAA+C;AAC/C,OAAO,EAAE,yBAAyB,EAAE,MAAM,mBAAmB,CAAC;AAG9D,qDAAqD;AACrD,OAAO,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAGnE,sBAAsB;AACtB,OAAO,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AAEpD,WAAW;AACX,OAAO,EACL,QAAQ,EACR,aAAa,EACb,gBAAgB,EAChB,oBAAoB,EACpB,gBAAgB,EAChB,sBAAsB,EACtB,kBAAkB,GACnB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@honeybbq/teamspeak",
|
|
3
|
-
"version": "1.0.0-beta.
|
|
3
|
+
"version": "1.0.0-beta.23",
|
|
4
4
|
"description": "TeamSpeak SDK for TypeScript: an independent voice client for Node.js, and the typed commands, ids and errors every connection shares",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"client",
|
|
@@ -1,12 +1,15 @@
|
|
|
1
1
|
import { resolveSrv } from "node:dns/promises";
|
|
2
2
|
import { createConnection } from "node:net";
|
|
3
3
|
import { ResolveSource } from "../types.js";
|
|
4
|
-
import type { ResolvedAddr } from "../types.js";
|
|
4
|
+
import type { AddrResolver, ResolvedAddr } from "../types.js";
|
|
5
5
|
import { isIpAddress, joinHostPort, splitHostPort } from "../address.js";
|
|
6
6
|
import { abortable } from "../abort.js";
|
|
7
|
+
import { TeamspeakError } from "@honeybbq/teamspeak";
|
|
7
8
|
import { InvalidAddressError } from "../errors.js";
|
|
8
9
|
|
|
9
10
|
const TS_DNS_DEFAULT_PORT = 41144;
|
|
11
|
+
/** What a TSDNS entry has for a port to say: the one the user gave. */
|
|
12
|
+
const PORT_PLACEHOLDER = ":$PORT";
|
|
10
13
|
const NICKNAME_LOOKUP_URL = "https://named.myteamspeak.com/lookup";
|
|
11
14
|
const CACHE_TTL_MS = 10 * 60 * 1000;
|
|
12
15
|
/**
|
|
@@ -30,14 +33,31 @@ export const MAX_DISCOVERY_RESPONSE: number = 8 * 1024;
|
|
|
30
33
|
export interface ResolverOptions {
|
|
31
34
|
/** Look dot-less names up at named.myteamspeak.com; off by default. */
|
|
32
35
|
readonly nicknameLookup?: boolean | undefined;
|
|
36
|
+
/**
|
|
37
|
+
* The nickname lookup endpoint, an http: or https: URL; the default is
|
|
38
|
+
* `https://named.myteamspeak.com/lookup`. Used only with `nicknameLookup`:
|
|
39
|
+
* setting it does not turn the lookup on. For a test double or a mirror of
|
|
40
|
+
* the service. The name is sent as the `name` query parameter, and the first
|
|
41
|
+
* line of the answer is the address. A URL that is not http: or https: throws
|
|
42
|
+
* a TypeError.
|
|
43
|
+
*/
|
|
44
|
+
readonly nicknameService?: string | URL | undefined;
|
|
33
45
|
}
|
|
34
46
|
|
|
35
|
-
|
|
47
|
+
/**
|
|
48
|
+
* The resolver a Client uses unless it is given another. It resolves as the
|
|
49
|
+
* TeamSpeak application does, so on its own it shows where an address leads:
|
|
50
|
+
* `await new Resolver().resolve("ts.example.com")`. Answers are kept for ten
|
|
51
|
+
* minutes.
|
|
52
|
+
*/
|
|
53
|
+
export class Resolver implements AddrResolver {
|
|
36
54
|
readonly #cache = new Map<string, ResolvedAddr[]>();
|
|
37
55
|
readonly #nicknameLookup: boolean;
|
|
56
|
+
readonly #nicknameService: URL;
|
|
38
57
|
|
|
39
58
|
constructor(options: ResolverOptions = {}) {
|
|
40
59
|
this.#nicknameLookup = options.nicknameLookup ?? false;
|
|
60
|
+
this.#nicknameService = parseNicknameService(options.nicknameService ?? NICKNAME_LOOKUP_URL);
|
|
41
61
|
}
|
|
42
62
|
|
|
43
63
|
/**
|
|
@@ -81,7 +101,7 @@ export class Resolver {
|
|
|
81
101
|
// service can answer: asking it sends the name to a third party, so it is
|
|
82
102
|
// opt-in. Otherwise the name is resolved like any host.
|
|
83
103
|
if (nicknames && this.#nicknameLookup && !host.includes(".") && host !== "localhost") {
|
|
84
|
-
const nickAddr = await resolveNickname(host, signal);
|
|
104
|
+
const nickAddr = await resolveNickname(host, this.#nicknameService, signal);
|
|
85
105
|
signal.throwIfAborted();
|
|
86
106
|
if (nickAddr) return this.#resolve(nickAddr, signal, false);
|
|
87
107
|
}
|
|
@@ -93,15 +113,21 @@ export class Resolver {
|
|
|
93
113
|
const domainList = getDomainList(host);
|
|
94
114
|
|
|
95
115
|
// TSDNS via SRV _tsdns._tcp.<domain>
|
|
96
|
-
const tsdnsSrv = await this.#resolveTSDNSSRV(domainList, host, signal);
|
|
97
|
-
if (tsdnsSrv) {
|
|
98
|
-
return this.#setCache(
|
|
116
|
+
const tsdnsSrv = await this.#resolveTSDNSSRV(domainList, host, port, signal);
|
|
117
|
+
if (tsdnsSrv.length > 0) {
|
|
118
|
+
return this.#setCache(
|
|
119
|
+
inputAddr,
|
|
120
|
+
tsdnsSrv.map((addr) => ({ addr, source: ResolveSource.TSDNSSRV })),
|
|
121
|
+
);
|
|
99
122
|
}
|
|
100
123
|
|
|
101
124
|
// TSDNS direct :41144
|
|
102
|
-
const tsdnsDirect = await this.#resolveTSDNSDirect(domainList, host, signal);
|
|
103
|
-
if (tsdnsDirect) {
|
|
104
|
-
return this.#setCache(
|
|
125
|
+
const tsdnsDirect = await this.#resolveTSDNSDirect(domainList, host, port, signal);
|
|
126
|
+
if (tsdnsDirect.length > 0) {
|
|
127
|
+
return this.#setCache(
|
|
128
|
+
inputAddr,
|
|
129
|
+
tsdnsDirect.map((addr) => ({ addr, source: ResolveSource.TSDNSDirect })),
|
|
130
|
+
);
|
|
105
131
|
}
|
|
106
132
|
|
|
107
133
|
signal.throwIfAborted();
|
|
@@ -143,40 +169,77 @@ export class Resolver {
|
|
|
143
169
|
async #resolveTSDNSSRV(
|
|
144
170
|
domains: string[],
|
|
145
171
|
queryHost: string,
|
|
172
|
+
port: string,
|
|
146
173
|
signal?: AbortSignal,
|
|
147
|
-
): Promise<string
|
|
174
|
+
): Promise<string[]> {
|
|
148
175
|
for (const domain of domains) {
|
|
149
176
|
try {
|
|
150
177
|
const srvs = await abortable(resolveSrv(`_tsdns._tcp.${domain}`), signal);
|
|
151
178
|
if (!srvs || srvs.length === 0) continue;
|
|
152
179
|
for (const srv of orderSrvRecords(srvs)) {
|
|
153
180
|
const tsdnsAddr = joinHostPort(srv.name.replace(/\.$/, ""), String(srv.port));
|
|
154
|
-
const result = await
|
|
155
|
-
if (result) return result;
|
|
181
|
+
const result = await askTSDNS(tsdnsAddr, queryHost, port, signal);
|
|
182
|
+
if (result.length > 0) return result;
|
|
156
183
|
}
|
|
157
184
|
} catch {
|
|
158
185
|
continue;
|
|
159
186
|
}
|
|
160
187
|
}
|
|
161
|
-
return
|
|
188
|
+
return [];
|
|
162
189
|
}
|
|
163
190
|
|
|
164
191
|
async #resolveTSDNSDirect(
|
|
165
192
|
domains: string[],
|
|
166
193
|
queryHost: string,
|
|
194
|
+
port: string,
|
|
167
195
|
signal?: AbortSignal,
|
|
168
|
-
): Promise<string
|
|
196
|
+
): Promise<string[]> {
|
|
169
197
|
// Asked at once rather than in turn, so the probes cost one timeout in
|
|
170
198
|
// all; the most specific domain's answer wins.
|
|
171
199
|
const answers = await Promise.all(
|
|
172
200
|
domains.map((domain) =>
|
|
173
|
-
|
|
201
|
+
askTSDNS(joinHostPort(domain, String(TS_DNS_DEFAULT_PORT)), queryHost, port, signal),
|
|
174
202
|
),
|
|
175
203
|
);
|
|
176
|
-
return answers.find((answer) => answer
|
|
204
|
+
return answers.find((answer) => answer.length > 0) ?? [];
|
|
177
205
|
}
|
|
178
206
|
}
|
|
179
207
|
|
|
208
|
+
/**
|
|
209
|
+
* Ask one TSDNS server; a server that fails to answer is one with no answer,
|
|
210
|
+
* so it never fails the resolution.
|
|
211
|
+
*/
|
|
212
|
+
async function askTSDNS(
|
|
213
|
+
server: string,
|
|
214
|
+
host: string,
|
|
215
|
+
port: string,
|
|
216
|
+
signal?: AbortSignal,
|
|
217
|
+
): Promise<string[]> {
|
|
218
|
+
try {
|
|
219
|
+
return normalizeTSDNSEntries(await lookupTSDNS(server, host, { signal }), port);
|
|
220
|
+
} catch {
|
|
221
|
+
return [];
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
/**
|
|
226
|
+
* Make each entry of a TSDNS answer a `host:port`, as TeamSpeak reads it: an
|
|
227
|
+
* entry without a port means 9987, and the port `$PORT` means `port`, the one
|
|
228
|
+
* the address being resolved had.
|
|
229
|
+
*
|
|
230
|
+
* @internal
|
|
231
|
+
*/
|
|
232
|
+
export function normalizeTSDNSEntries(entries: readonly string[], port: string): string[] {
|
|
233
|
+
return entries.map((entry) => {
|
|
234
|
+
if (entry.endsWith(PORT_PLACEHOLDER)) {
|
|
235
|
+
const host = splitHostPort(entry.slice(0, -PORT_PLACEHOLDER.length)).host;
|
|
236
|
+
return joinHostPort(host, port);
|
|
237
|
+
}
|
|
238
|
+
const target = splitHostPort(entry, "9987");
|
|
239
|
+
return joinHostPort(target.host, target.port);
|
|
240
|
+
});
|
|
241
|
+
}
|
|
242
|
+
|
|
180
243
|
// ---- Helpers ----------------------------------------------------------------
|
|
181
244
|
|
|
182
245
|
/** The part of an SRV record that decides the order they are tried in. */
|
|
@@ -231,13 +294,27 @@ export function orderSrvRecords<T extends SrvRecord>(
|
|
|
231
294
|
return ordered;
|
|
232
295
|
}
|
|
233
296
|
|
|
297
|
+
function parseNicknameService(service: string | URL): URL {
|
|
298
|
+
let url: URL;
|
|
299
|
+
try {
|
|
300
|
+
url = new URL(service);
|
|
301
|
+
} catch {
|
|
302
|
+
throw new TypeError(`nicknameService is not a URL: ${String(service)}`);
|
|
303
|
+
}
|
|
304
|
+
if (url.protocol !== "http:" && url.protocol !== "https:") {
|
|
305
|
+
throw new TypeError(`nicknameService is an http: or https: URL, not ${url.protocol}`);
|
|
306
|
+
}
|
|
307
|
+
return url;
|
|
308
|
+
}
|
|
309
|
+
|
|
234
310
|
/** @internal Ask the nickname service for `nickname`'s address. */
|
|
235
311
|
export async function resolveNickname(
|
|
236
312
|
nickname: string,
|
|
313
|
+
service: URL,
|
|
237
314
|
signal?: AbortSignal,
|
|
238
315
|
): Promise<string | null> {
|
|
239
316
|
try {
|
|
240
|
-
const url = new URL(
|
|
317
|
+
const url = new URL(service);
|
|
241
318
|
url.searchParams.set("name", nickname);
|
|
242
319
|
const init: RequestInit = signal ? { signal } : {};
|
|
243
320
|
const resp = await fetch(url.toString(), init);
|
|
@@ -270,54 +347,82 @@ async function readLimited(resp: Response, limit: number): Promise<string> {
|
|
|
270
347
|
return Buffer.concat(chunks).toString("utf8");
|
|
271
348
|
}
|
|
272
349
|
|
|
273
|
-
/**
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
350
|
+
/**
|
|
351
|
+
* Ask a TSDNS server where `host` is. The answer is the server's targets in
|
|
352
|
+
* its order and as it sent them: an entry may have no port, which TeamSpeak
|
|
353
|
+
* takes as 9987, or the literal port `$PORT`, the port the user gave (9987 by
|
|
354
|
+
* default). {@link Resolver} applies both. A name the server has no record for
|
|
355
|
+
* gives an empty list.
|
|
356
|
+
*
|
|
357
|
+
* The answer ends at its first line break or when the server closes the
|
|
358
|
+
* connection, whichever comes first. It rejects when the connection fails,
|
|
359
|
+
* when no answer completes within three seconds or grows past 8 KiB, and with
|
|
360
|
+
* the signal's reason when it aborts.
|
|
361
|
+
*
|
|
362
|
+
* @param server - The TSDNS server, `host` or `host:port`; the port defaults to 41144.
|
|
363
|
+
* @param host - The name to look up; it is sent without a port.
|
|
364
|
+
*/
|
|
365
|
+
export function lookupTSDNS(
|
|
366
|
+
server: string,
|
|
367
|
+
host: string,
|
|
368
|
+
options: { readonly signal?: AbortSignal | undefined } = {},
|
|
369
|
+
): Promise<string[]> {
|
|
370
|
+
const { signal } = options;
|
|
371
|
+
const target = splitHostPort(server, String(TS_DNS_DEFAULT_PORT));
|
|
372
|
+
const port = parseInt(target.port, 10);
|
|
373
|
+
|
|
374
|
+
return new Promise((resolve, reject) => {
|
|
375
|
+
if (signal?.aborted) return reject(signal.reason);
|
|
376
|
+
const chunks: Buffer[] = [];
|
|
377
|
+
let size = 0;
|
|
378
|
+
let done = false;
|
|
379
|
+
const finish = (error: unknown, answer?: string[]): void => {
|
|
380
|
+
if (done) return;
|
|
381
|
+
done = true;
|
|
285
382
|
clearTimeout(timeout);
|
|
286
383
|
signal?.removeEventListener("abort", onAbort);
|
|
287
384
|
socket.destroy();
|
|
288
|
-
|
|
385
|
+
if (error !== undefined) reject(error);
|
|
386
|
+
else resolve(answer ?? []);
|
|
289
387
|
};
|
|
290
|
-
const
|
|
291
|
-
|
|
388
|
+
const answerOf = (bytes: Buffer): string[] => {
|
|
389
|
+
const line = bytes.toString("utf8").trim();
|
|
390
|
+
return !line || line === "404" || line === "errors" ? [] : line.split(/\s+/);
|
|
391
|
+
};
|
|
392
|
+
const timedOut = (): void =>
|
|
393
|
+
finish(new TeamspeakError(`the TSDNS server ${server} did not answer in time`));
|
|
394
|
+
const onAbort = (): void => finish(signal?.reason);
|
|
395
|
+
const timeout = setTimeout(timedOut, TSDNS_TIMEOUT_MS);
|
|
292
396
|
|
|
293
|
-
const socket = createConnection({ host, port, timeout: 2_000 }, () => {
|
|
294
|
-
socket.write(`${
|
|
397
|
+
const socket = createConnection({ host: target.host, port, timeout: 2_000 }, () => {
|
|
398
|
+
socket.write(`${host}\n`);
|
|
295
399
|
});
|
|
296
400
|
|
|
297
|
-
let buf = "";
|
|
298
401
|
socket.on("data", (chunk: Buffer) => {
|
|
299
|
-
|
|
300
|
-
|
|
402
|
+
chunks.push(chunk);
|
|
403
|
+
size += chunk.length;
|
|
404
|
+
const all = chunks.length === 1 ? chunks[0]! : Buffer.concat(chunks);
|
|
405
|
+
chunks.length = 0;
|
|
406
|
+
chunks.push(all);
|
|
407
|
+
const idx = all.indexOf(0x0a);
|
|
301
408
|
if (idx >= 0 && idx < MAX_DISCOVERY_RESPONSE) {
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
} else if (buf.length >= MAX_DISCOVERY_RESPONSE) {
|
|
409
|
+
finish(undefined, answerOf(all.subarray(0, idx)));
|
|
410
|
+
} else if (size >= MAX_DISCOVERY_RESPONSE) {
|
|
305
411
|
// No answer is that long.
|
|
306
|
-
finish(
|
|
412
|
+
finish(
|
|
413
|
+
new TeamspeakError(
|
|
414
|
+
`the TSDNS server ${server} sent ${MAX_DISCOVERY_RESPONSE} bytes without ending its answer`,
|
|
415
|
+
),
|
|
416
|
+
);
|
|
307
417
|
}
|
|
308
418
|
});
|
|
309
|
-
|
|
310
|
-
socket.on("error", () => finish(
|
|
311
|
-
socket.on("timeout",
|
|
419
|
+
socket.on("end", () => finish(undefined, answerOf(Buffer.concat(chunks))));
|
|
420
|
+
socket.on("error", (error) => finish(error));
|
|
421
|
+
socket.on("timeout", timedOut);
|
|
312
422
|
signal?.addEventListener("abort", onAbort, { once: true });
|
|
313
423
|
});
|
|
314
424
|
}
|
|
315
425
|
|
|
316
|
-
function splitHostPortParts(addr: string): [string, string] {
|
|
317
|
-
const { host, port } = splitHostPort(addr);
|
|
318
|
-
return [host, port];
|
|
319
|
-
}
|
|
320
|
-
|
|
321
426
|
function getDomainList(host: string): string[] {
|
|
322
427
|
const parts = host.split(".");
|
|
323
428
|
const list: string[] = [];
|
package/src/client/index.ts
CHANGED
|
@@ -12,6 +12,9 @@
|
|
|
12
12
|
export { Client } from "./client.js";
|
|
13
13
|
export { EventName, GroupWhisperType, GroupWhisperScope, ResolveSource } from "./types.js";
|
|
14
14
|
|
|
15
|
+
export { Resolver, lookupTSDNS } from "./discovery/resolver.js";
|
|
16
|
+
export type { ResolverOptions } from "./discovery/resolver.js";
|
|
17
|
+
|
|
15
18
|
export { ViewStatus } from "./view.js";
|
|
16
19
|
export type { ServerView, ViewChangedEvent, ViewReadyEvent } from "./view.js";
|
|
17
20
|
|