ci
ci/woodpecker/push/base Pipeline failed Details

lanparty
gapodo 2023-11-19 23:00:03 +01:00
parent feb564d4a0
commit 3ec3db37e0
9 changed files with 322 additions and 126 deletions

4
.npmrc Normal file
View File

@ -0,0 +1,4 @@
audit=false
fund=false
update-notifier=false
package-lock=true

42
.woodpecker/base.yaml Normal file
View File

@ -0,0 +1,42 @@
when:
event: [push, deployment, manual, cron]
labels:
platform: linux/amd64
variables:
- &node_image 'node:14-bullseye'
- &buildx_image 'woodpeckerci/plugin-docker-buildx:2.2.1'
steps:
prepare-npm:
image: *node_image
secrets:
- npmconf
commands:
- git config --add safe.directory '*'
- if [ "$${NPMCONF:-}" != "" ]; then echo "$${NPMCONF}" >> "$${HOME}/.npmrc"; fi
- npm ci
- npx browserslist@latest --update-db
build-npm:
image: *node_image
commands:
- bash ./scripts/build.sh web rel
build-docker:
image: *buildx_image
pull: true
settings:
platforms: linux/amd64
dockerfile: docker/Dockerfile.ci
context: .
registry:
from_secret: registry_domain
tag: latest
repo:
from_secret: target_image_name
password:
from_secret: registry_token
username:
from_secret: registry_user

17
docker/Dockerfile.base Normal file
View File

@ -0,0 +1,17 @@
FROM nginx:mainline-alpine
COPY ./files/default.conf /etc/nginx/conf.d/default.conf
COPY ./files/nginx.conf /etc/nginx/nginx.conf
COPY ./files/entrypoint.sh /
RUN apk update --no-cache && apk upgrade --no-cache \
&& apk add --no-cache openssl tzdata \
&& mkdir -p /var/www/TeaWeb /etc/ssl/certs \
&& chmod +x /entrypoint.sh
ENV TZ="Europe/Berlin"
EXPOSE 80 443
ENTRYPOINT ["/entrypoint.sh"]
CMD ["nginx", "-g", "daemon off;"]

19
docker/Dockerfile.ci Normal file
View File

@ -0,0 +1,19 @@
FROM nginx:mainline-alpine
COPY ./docker/files/default.conf /etc/nginx/conf.d/default.conf
COPY ./docker/files/nginx.conf /etc/nginx/nginx.conf
COPY ./docker/files/entrypoint.sh /
RUN apk update --no-cache && apk upgrade --no-cache \
&& apk add --no-cache openssl tzdata \
&& mkdir -p /var/www/TeaWeb /etc/ssl/certs \
&& chmod +x /entrypoint.sh
ENV TZ="Europe/Berlin"
EXPOSE 80 443
ENTRYPOINT ["/entrypoint.sh"]
CMD ["nginx", "-g", "daemon off;"]
COPY ./dist/ /var/www/TeaWeb/

36
docker/default.conf Normal file
View File

@ -0,0 +1,36 @@
server {
listen 80;
server_name _;
return 301 https://$host$request_uri;
}
server {
listen 443 default_server ssl http2;
server_name _;
ssl_ciphers EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-GCM-SHA256:TLS-CHACHA20-POLY1305-SHA256:TLS-AES-256-GCM-SHA384:TLS-AES-128-GCM-SHA256;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_dhparam /etc/ssl/certs/dhparam.pem;
ssl_ecdh_curve secp384r1;
ssl_certificate /etc/ssl/certs/tea_bundle.crt;
ssl_certificate_key /etc/ssl/certs/tea.key;
ssl_session_cache shared:MozSSL:10m;
ssl_session_timeout 1d;
ssl_prefer_server_ciphers on;
location / {
root /var/www/TeaWeb;
index index.html;
}
#error_page 404 /404.html;
# redirect server error pages to the static page /50x.html
#
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
gzip off;
}

29
docker/entrypoint.sh Executable file
View File

@ -0,0 +1,29 @@
#!/usr/bin/env sh
set -e
gen_self_signed() {
echo "[WRN] No certificates found, generating self signed cert with key"
openssl req -x509 -nodes -days 1780 -newkey rsa:4096 \
-keyout /etc/ssl/certs/tea.key \
-out /etc/ssl/certs/tea_bundle.crt \
-subj "/C=DE/ST=Berlin/L=Germany/O=TeaSpeak/OU=TeaWeb/CN=localhost/emailAddress=noreply@teaspeak.de"
}
gen_diffie_hellman() {
echo "[INF] No Diffie-Hellman pem found, generating new with 2048 byte"
openssl dhparam -out /etc/ssl/certs/dhparam.pem 2048
}
if [ "$1" = "nginx" ]; then
if [ ! -f /etc/ssl/certs/tea.key ] && [ ! -f /etc/ssl/certs/tea_bundle.crt ]; then
gen_self_signed
elif [ ! -f /etc/ssl/certs/tea.key ] || [ ! -f /etc/ssl/certs/tea_bundle.crt ]; then
echo "[ERR] Only found a key or crt-bundle file but both files are REQUIRED!"
exit 1
fi
if [ ! -f /etc/ssl/certs/dhparam.pem ]; then
gen_diffie_hellman
fi
fi
exec "$@"

32
docker/nginx.conf Normal file
View File

@ -0,0 +1,32 @@
user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;
events {
worker_connections 1024;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main;
sendfile on;
#tcp_nopush on;
server_tokens off;
keepalive_timeout 75;
#gzip on;
include /etc/nginx/conf.d/*.conf;
}

View File

@ -1,10 +1,10 @@
import {LogCategory, logError, logInfo, logTrace} from "./log";
import { LogCategory, logError, logInfo, logTrace } from "./log";
import * as loader from "tc-loader";
import {Stage} from "tc-loader";
import {Registry} from "./events";
import {tr} from "./i18n/localize";
import {CallOnce, ignorePromise} from "tc-shared/proto";
import {getStorageAdapter} from "tc-shared/StorageAdapter";
import { Stage } from "tc-loader";
import { Registry } from "./events";
import { tr } from "./i18n/localize";
import { CallOnce, ignorePromise } from "tc-shared/proto";
import { getStorageAdapter } from "tc-shared/StorageAdapter";
/*
* TODO: Sync settings across renderer instances
@ -14,17 +14,17 @@ export type RegistryValueType = boolean | number | string | object;
export type RegistryValueTypeNames = "boolean" | "number" | "string" | "object";
export type RegistryValueTypeMapping<T> = T extends boolean ? "boolean" :
T extends number ? "number" :
T extends string ? "string" :
T extends object ? "object" :
never;
T extends number ? "number" :
T extends string ? "string" :
T extends object ? "object" :
never;
export interface RegistryKey<ValueType extends RegistryValueType> {
key: string;
valueType: RegistryValueTypeMapping<ValueType>;
fallbackKeys?: string | string[];
fallbackImports?: {[key: string]:(value: string) => ValueType};
fallbackImports?: { [key: string]: (value: string) => ValueType };
description?: string;
@ -37,7 +37,7 @@ export interface ValuedRegistryKey<ValueType extends RegistryValueType> extends
const UPDATE_DIRECT: boolean = true;
function decodeValueFromString<T extends RegistryValueType>(input: string, type: RegistryValueTypeMapping<T>) : T {
function decodeValueFromString<T extends RegistryValueType>(input: string, type: RegistryValueTypeMapping<T>): T {
switch (type) {
case "string":
return input as any;
@ -60,7 +60,7 @@ function decodeValueFromString<T extends RegistryValueType>(input: string, type:
}
}
export function encodeSettingValueToString<T extends RegistryValueType>(input: T) : string {
export function encodeSettingValueToString<T extends RegistryValueType>(input: T): string {
switch (typeof input) {
case "string":
return input;
@ -83,24 +83,24 @@ export function resolveSettingKey<ValueType extends RegistryValueType, DefaultTy
key: RegistryKey<ValueType>,
resolver: (key: string) => string | undefined | null,
defaultValue: DefaultType
) : ValueType | DefaultType {
): ValueType | DefaultType {
let value = resolver(key.key);
const keys = [key.key];
if(Array.isArray(key.fallbackKeys)) {
if (Array.isArray(key.fallbackKeys)) {
keys.push(...key.fallbackKeys);
}
for(const resolveKey of keys) {
for (const resolveKey of keys) {
value = resolver(resolveKey);
if(typeof value !== "string") {
if (typeof value !== "string") {
continue;
}
switch (key.valueType) {
case "number":
case "boolean":
if(value.length === 0) {
if (value.length === 0) {
continue;
}
break;
@ -109,9 +109,9 @@ export function resolveSettingKey<ValueType extends RegistryValueType, DefaultTy
break;
}
if(key.fallbackImports) {
if (key.fallbackImports) {
const fallbackValueImporter = key.fallbackImports[resolveKey];
if(fallbackValueImporter) {
if (fallbackValueImporter) {
return fallbackValueImporter(value);
}
}
@ -129,21 +129,21 @@ export class UrlParameterParser {
this.url = url;
}
private getParameter(key: string) : string | undefined {
private getParameter(key: string): string | undefined {
const value = this.url.searchParams.get(key);
if(value === null) {
if (value === null) {
return undefined;
}
return decodeURIComponent(value);
}
getValue<V extends RegistryValueType, DV>(key: RegistryKey<V>, defaultValue: DV) : V | DV;
getValue<V extends RegistryValueType>(key: ValuedRegistryKey<V>, defaultValue?: V) : V;
getValue<V extends RegistryValueType, DV>(key: RegistryKey<V> | ValuedRegistryKey<V>, defaultValue: DV) : V | DV {
if(arguments.length > 1) {
getValue<V extends RegistryValueType, DV>(key: RegistryKey<V>, defaultValue: DV): V | DV;
getValue<V extends RegistryValueType>(key: ValuedRegistryKey<V>, defaultValue?: V): V;
getValue<V extends RegistryValueType, DV>(key: RegistryKey<V> | ValuedRegistryKey<V>, defaultValue: DV): V | DV {
if (arguments.length > 1) {
return resolveSettingKey(key, key => this.getParameter(key), defaultValue);
} else if("defaultValue" in key) {
} else if ("defaultValue" in key) {
return resolveSettingKey(key, key => this.getParameter(key), key.defaultValue);
} else {
throw tr("missing value");
@ -155,14 +155,14 @@ export class UrlParameterBuilder {
private parameters = {};
setValue<V extends RegistryValueType>(key: RegistryKey<V>, value: V) {
if(value === undefined) {
if (value === undefined) {
delete this.parameters[key.key];
} else {
this.parameters[key.key] = encodeURIComponent(encodeSettingValueToString(value));
}
}
build() : string {
build(): string {
return Object.keys(this.parameters).map(key => `${key}=${this.parameters[key]}`).join("&");
}
}
@ -174,12 +174,12 @@ export class UrlParameterBuilder {
export namespace AppParameters {
export const Instance = new UrlParameterParser(new URL(window.location.href));
export function getValue<V extends RegistryValueType, DV>(key: RegistryKey<V>, defaultValue: DV) : V | DV;
export function getValue<V extends RegistryValueType>(key: ValuedRegistryKey<V>, defaultValue?: V) : V;
export function getValue<V extends RegistryValueType, DV>(key: RegistryKey<V> | ValuedRegistryKey<V>, defaultValue: DV) : V | DV {
if(arguments.length > 1) {
export function getValue<V extends RegistryValueType, DV>(key: RegistryKey<V>, defaultValue: DV): V | DV;
export function getValue<V extends RegistryValueType>(key: ValuedRegistryKey<V>, defaultValue?: V): V;
export function getValue<V extends RegistryValueType, DV>(key: RegistryKey<V> | ValuedRegistryKey<V>, defaultValue: DV): V | DV {
if (arguments.length > 1) {
return Instance.getValue(key, defaultValue);
} else if("defaultValue" in key) {
} else if ("defaultValue" in key) {
return Instance.getValue(key);
} else {
throw tr("missing value");
@ -408,12 +408,12 @@ export class Settings {
static readonly KEY_FLAG_CONNECT_DEFAULT: ValuedRegistryKey<boolean> = {
key: "connect_default",
valueType: "boolean",
defaultValue: false
defaultValue: true
};
static readonly KEY_CONNECT_ADDRESS: ValuedRegistryKey<string> = {
key: "connect_address",
valueType: "string",
defaultValue: undefined
defaultValue: "tea.lp.kle.li"
};
static readonly KEY_CONNECT_PROFILE: ValuedRegistryKey<string> = {
key: "connect_profile",
@ -448,7 +448,7 @@ export class Settings {
static readonly KEY_CONNECT_NO_DNSPROXY: ValuedRegistryKey<boolean> = {
key: "connect_no_dnsproxy",
defaultValue: false,
defaultValue: true,
valueType: "boolean",
};
@ -616,7 +616,7 @@ export class Settings {
/* defaultValue: <users download directory> */
};
static readonly KEY_IPC_REMOTE_ADDRESS: RegistryKey<string> = {
static readonly KEY_IPC_REMOTE_ADDRESS: RegistryKey<string> = {
key: "ipc-address",
valueType: "string"
};
@ -913,8 +913,8 @@ export class Settings {
static readonly KEYS = (() => {
const result = [];
for(const key of Object.keys(Settings)) {
if(!key.toUpperCase().startsWith("KEY_")) {
for (const key of Object.keys(Settings)) {
if (!key.toUpperCase().startsWith("KEY_")) {
continue;
}
@ -943,13 +943,13 @@ export class Settings {
const json = await getStorageAdapter().get("settings.global");
try {
if(json === null) {
if (json === null) {
logInfo(LogCategory.GENERAL, tr("Found no settings. Creating new client settings."));
this.settingsCache = {};
} else {
this.settingsCache = JSON.parse(json);
}
} catch(error) {
} catch (error) {
this.settingsCache = {};
logError(LogCategory.GENERAL, tr("Failed to load global settings!\nJson: %s\nError: %o"), json, error);
@ -957,7 +957,7 @@ export class Settings {
//FIXME: Readd this
//createErrorModal(tr("Failed to load global settings"), tr("Failed to load global client settings!\nLookup console for more information.")).open();
};
if(!loader.finished()) {
if (!loader.finished()) {
loader.register_task(loader.Stage.LOADED, {
priority: 0,
name: "Settings error",
@ -969,18 +969,18 @@ export class Settings {
}
this.saveWorker = setInterval(() => {
if(this.updated) {
if (this.updated) {
this.save();
}
}, 5 * 1000);
}
getValue<V extends RegistryValueType, DV>(key: RegistryKey<V>, defaultValue: DV) : V | DV;
getValue<V extends RegistryValueType>(key: ValuedRegistryKey<V>, defaultValue?: V) : V;
getValue<V extends RegistryValueType, DV>(key: RegistryKey<V> | ValuedRegistryKey<V>, defaultValue: DV) : V | DV {
if(arguments.length > 1) {
getValue<V extends RegistryValueType, DV>(key: RegistryKey<V>, defaultValue: DV): V | DV;
getValue<V extends RegistryValueType>(key: ValuedRegistryKey<V>, defaultValue?: V): V;
getValue<V extends RegistryValueType, DV>(key: RegistryKey<V> | ValuedRegistryKey<V>, defaultValue: DV): V | DV {
if (arguments.length > 1) {
return resolveSettingKey(key, key => this.settingsCache[key], defaultValue);
} else if("defaultValue" in key) {
} else if ("defaultValue" in key) {
return resolveSettingKey(key, key => this.settingsCache[key], key.defaultValue);
} else {
debugger;
@ -988,17 +988,17 @@ export class Settings {
}
}
setValue<T extends RegistryValueType>(key: RegistryKey<T>, value?: T){
if(value === null) {
setValue<T extends RegistryValueType>(key: RegistryKey<T>, value?: T) {
if (value === null) {
value = undefined;
}
if(this.settingsCache[key.key] === value) {
if (this.settingsCache[key.key] === value) {
return;
}
const oldValue = this.settingsCache[key.key];
if(value === undefined) {
if (value === undefined) {
delete this.settingsCache[key.key];
} else {
this.settingsCache[key.key] = encodeSettingValueToString(value);
@ -1014,21 +1014,21 @@ export class Settings {
});
logTrace(LogCategory.GENERAL, tr("Changing global setting %s to %o"), key.key, value);
if(UPDATE_DIRECT) {
if (UPDATE_DIRECT) {
this.save();
}
}
globalChangeListener<T extends RegistryValueType>(key: RegistryKey<T>, listener: (newValue: T) => void) : () => void {
globalChangeListener<T extends RegistryValueType>(key: RegistryKey<T>, listener: (newValue: T) => void): () => void {
return this.events.on("notify_setting_changed", event => {
if(event.setting === key.key && event.mode === "global") {
if (event.setting === key.key && event.mode === "global") {
listener(event.newCastedValue);
}
})
}
private async doSave() {
if(this.saveState === "none") {
if (this.saveState === "none") {
return;
}
@ -1040,7 +1040,7 @@ export class Settings {
} catch (error) {
logError(LogCategory.GENERAL, tr("Failed to save global settings: %o"), error);
}
} while(this.saveState !== "saving");
} while (this.saveState !== "saving");
this.saveState = "none";
}

View File

@ -1,11 +1,11 @@
import {LogCategory, logError, logTrace, logWarn} from "tc-shared/log";
import {tr} from "tc-shared/i18n/localize";
import {default_options, DNSAddress, DNSResolveResult, ResolveOptions} from "tc-shared/dns";
import {executeDnsRequest, RRType} from "./api";
import { LogCategory, logError, logTrace, logWarn } from "tc-shared/log";
import { tr } from "tc-shared/i18n/localize";
import { default_options, DNSAddress, DNSResolveResult, ResolveOptions } from "tc-shared/dns";
import { executeDnsRequest, RRType } from "./api";
interface DNSResolveMethod {
name() : string;
resolve(address: DNSAddress) : Promise<DNSAddress | undefined>;
name(): string;
resolve(address: DNSAddress): Promise<DNSAddress | undefined>;
}
class LocalhostResolver implements DNSResolveMethod {
@ -14,7 +14,7 @@ class LocalhostResolver implements DNSResolveMethod {
}
async resolve(address: DNSAddress): Promise<DNSAddress | undefined> {
if(address.hostname === "localhost") {
if (address.hostname === "localhost") {
return {
hostname: "127.0.0.1",
port: address.port
@ -26,6 +26,20 @@ class LocalhostResolver implements DNSResolveMethod {
}
class FakeResolver implements DNSResolveMethod {
name(): string {
return "fake resolver";
}
async resolve(address: DNSAddress): Promise<DNSAddress | undefined> {
return {
hostname: "tea.lp.kle.li",
port: address.port
}
}
}
class IPResolveMethod implements DNSResolveMethod {
readonly v6: boolean;
@ -40,7 +54,7 @@ class IPResolveMethod implements DNSResolveMethod {
async resolve(address: DNSAddress): Promise<DNSAddress | undefined> {
const answer = await executeDnsRequest(address.hostname, this.v6 ? RRType.AAAA : RRType.A);
if(!answer.length) {
if (!answer.length) {
return undefined;
}
@ -72,10 +86,10 @@ class SRVResolveMethod implements DNSResolveMethod {
async resolve(address: DNSAddress): Promise<DNSAddress | undefined> {
const answer = await executeDnsRequest((this.application ? this.application + "." : "") + address.hostname, RRType.SRV);
const records: {[key: number]: ParsedSVRRecord[]} = {};
for(const record of answer) {
const records: { [key: number]: ParsedSVRRecord[] } = {};
for (const record of answer) {
const parts = record.data.split(" ");
if(parts.length !== 4) {
if (parts.length !== 4) {
logWarn(LogCategory.DNS, tr("Failed to parse SRV record %s. Invalid split length."), record);
continue;
}
@ -84,7 +98,7 @@ class SRVResolveMethod implements DNSResolveMethod {
const weight = parseInt(parts[1]);
const port = parseInt(parts[2]);
if((priority < 0 || priority > 65535) || (weight < 0 || weight > 65535) || (port < 0 || port > 65535)) {
if ((priority < 0 || priority > 65535) || (weight < 0 || weight > 65535) || (port < 0 || port > 65535)) {
logWarn(LogCategory.DNS, tr("Failed to parse SRV record %s. Malformed data."), record);
continue;
}
@ -99,35 +113,35 @@ class SRVResolveMethod implements DNSResolveMethod {
/* get the record with the highest priority */
const priority_strings = Object.keys(records);
if(!priority_strings.length) {
if (!priority_strings.length) {
return undefined;
}
let highestPriority: ParsedSVRRecord[];
for(const priority_str of priority_strings) {
if(!highestPriority || !highestPriority.length) {
for (const priority_str of priority_strings) {
if (!highestPriority || !highestPriority.length) {
highestPriority = records[priority_str];
}
if(highestPriority[0].priority < parseInt(priority_str)) {
if (highestPriority[0].priority < parseInt(priority_str)) {
highestPriority = records[priority_str];
}
}
if(!highestPriority.length) {
if (!highestPriority.length) {
return undefined;
}
/* select randomly one record */
let record: ParsedSVRRecord;
const max_weight = highestPriority.map(e => e.weight).reduce((a, b) => a + b, 0);
if(max_weight == 0) {
if (max_weight == 0) {
record = highestPriority[Math.floor(Math.random() * highestPriority.length)];
} else {
let rnd = Math.random() * max_weight;
for(let i = 0; i < highestPriority.length; i++) {
for (let i = 0; i < highestPriority.length; i++) {
rnd -= highestPriority[i].weight;
if(rnd > 0) {
if (rnd > 0) {
continue;
}
@ -136,7 +150,7 @@ class SRVResolveMethod implements DNSResolveMethod {
}
}
if(!record) {
if (!record) {
/* shall never happen */
record = highestPriority[0];
}
@ -165,7 +179,7 @@ class SRV_IPResolveMethod implements DNSResolveMethod {
async resolve(address: DNSAddress): Promise<DNSAddress | undefined> {
const srvAddress = await this.srvResolver.resolve(address);
if(!srvAddress) {
if (!srvAddress) {
return undefined;
}
@ -190,7 +204,7 @@ class DomainRootResolveMethod implements DNSResolveMethod {
async resolve(address: DNSAddress): Promise<DNSAddress | undefined> {
const parts = address.hostname.split(".");
if(parts.length < 3) {
if (parts.length < 3) {
return undefined;
}
@ -203,7 +217,7 @@ class DomainRootResolveMethod implements DNSResolveMethod {
class TeaSpeakDNSResolve {
readonly address: DNSAddress;
private resolvers: {[key: string]:{ resolver: DNSResolveMethod, after: string[] }} = {};
private resolvers: { [key: string]: { resolver: DNSResolveMethod, after: string[] } } = {};
private resolving = false;
private timeout;
@ -218,15 +232,15 @@ class TeaSpeakDNSResolve {
}
registerResolver(resolver: DNSResolveMethod, ...after: (string | DNSResolveMethod)[]) {
if(this.resolving) {
if (this.resolving) {
throw tr("resolver is already resolving");
}
this.resolvers[resolver.name()] = { resolver: resolver, after: after.map(e => typeof e === "string" ? e : e.name()) };
}
resolve(timeout: number) : Promise<DNSAddress> {
if(this.resolving) {
resolve(timeout: number): Promise<DNSAddress> {
if (this.resolving) {
throw tr("already resolving");
}
this.resolving = true;
@ -263,52 +277,53 @@ class TeaSpeakDNSResolve {
let invoke_count = 0;
_main_loop:
for(const resolver_name of Object.keys(this.resolvers)) {
if(this.resolving_resolvers.findIndex(e => e === resolver_name) !== -1) continue;
if(this.finished_resolvers.findIndex(e => e === resolver_name) !== -1) continue;
for (const resolver_name of Object.keys(this.resolvers)) {
if (this.resolving_resolvers.findIndex(e => e === resolver_name) !== -1) continue;
if (this.finished_resolvers.findIndex(e => e === resolver_name) !== -1) continue;
const resolver = this.resolvers[resolver_name];
for(const after of resolver.after)
if(this.finished_resolvers.findIndex(e => e === after) === -1) continue _main_loop;
const resolver = this.resolvers[resolver_name];
for (const after of resolver.after)
if (this.finished_resolvers.findIndex(e => e === after) === -1) continue _main_loop;
invoke_count++;
logTrace(LogCategory.DNS, tr(" Executing resolver %s"), resolver_name);
invoke_count++;
logTrace(LogCategory.DNS, tr(" Executing resolver %s"), resolver_name);
this.resolving_resolvers.push(resolver_name);
resolver.resolver.resolve(this.address).then(result => {
if(!this.resolving || !this.callback_success) return; /* resolve has been finished already */
this.finished_resolvers.push(resolver_name);
this.resolving_resolvers.push(resolver_name);
resolver.resolver.resolve(this.address).then(result => {
if (!this.resolving || !this.callback_success) return; /* resolve has been finished already */
this.finished_resolvers.push(resolver_name);
if(!result) {
logTrace(LogCategory.DNS, tr(" Resolver %s returned an empty response."), resolver_name);
this.invoke_resolvers();
return;
}
logTrace(LogCategory.DNS, tr(" Successfully resolved address %s:%d to %s:%d via resolver %s"),
this.address.hostname, this.address.port,
result.hostname, result.port,
resolver_name);
this.callback_success(result);
}).catch(error => {
if(!this.resolving || !this.callback_success) return; /* resolve has been finished already */
this.finished_resolvers.push(resolver_name);
logTrace(LogCategory.DNS, tr(" Resolver %s ran into an error: %o"), resolver_name, error);
if (!result) {
logTrace(LogCategory.DNS, tr(" Resolver %s returned an empty response."), resolver_name);
this.invoke_resolvers();
}).then(() => {
this.resolving_resolvers.remove(resolver_name);
if(!this.resolving_resolvers.length && this.resolving)
this.invoke_resolvers();
});
}
return;
}
if(invoke_count === 0 && !this.resolving_resolvers.length && this.resolving) {
logTrace(LogCategory.DNS, tr(" Successfully resolved address %s:%d to %s:%d via resolver %s"),
this.address.hostname, this.address.port,
result.hostname, result.port,
resolver_name);
this.callback_success(result);
}).catch(error => {
if (!this.resolving || !this.callback_success) return; /* resolve has been finished already */
this.finished_resolvers.push(resolver_name);
logTrace(LogCategory.DNS, tr(" Resolver %s ran into an error: %o"), resolver_name, error);
this.invoke_resolvers();
}).then(() => {
this.resolving_resolvers.remove(resolver_name);
if (!this.resolving_resolvers.length && this.resolving)
this.invoke_resolvers();
});
}
if (invoke_count === 0 && !this.resolving_resolvers.length && this.resolving) {
this.callback_fail("no response");
}
}
}
const kResolverFake = new FakeResolver();
const kResolverLocalhost = new LocalhostResolver();
const kResolverIpV4 = new IPResolveMethod(false);
@ -320,14 +335,16 @@ const resolverSrvTS3 = new SRV_IPResolveMethod(new SRVResolveMethod("_ts3._udp")
const resolverDrSrvTS = new DomainRootResolveMethod(resolverSrvTS);
const resolverDrSrvTS3 = new DomainRootResolveMethod(resolverSrvTS3);
export async function resolveTeaSpeakServerAddress(address: DNSAddress, _options?: ResolveOptions) : Promise<DNSResolveResult> {
export async function resolveTeaSpeakServerAddress(address: DNSAddress, _options?: ResolveOptions): Promise<DNSResolveResult> {
try {
const options = Object.assign({}, default_options);
Object.assign(options, _options);
const resolver = new TeaSpeakDNSResolve(address);
resolver.registerResolver(kResolverLocalhost);
resolver.registerResolver(kResolverFake);
resolver.registerResolver(kResolverLocalhost, kResolverFake);
resolver.registerResolver(resolverSrvTS, kResolverLocalhost);
resolver.registerResolver(resolverSrvTS3, kResolverLocalhost);
@ -340,7 +357,7 @@ export async function resolveTeaSpeakServerAddress(address: DNSAddress, _options
resolver.registerResolver(kResolverIpV6, kResolverIpV4);
const response = await resolver.resolve(options.timeout || 5000);
if(!response) {
if (!response) {
return {
status: "empty-result"
};
@ -352,7 +369,7 @@ export async function resolveTeaSpeakServerAddress(address: DNSAddress, _options
resolvedAddress: response
};
} catch (error) {
if(typeof error !== "string") {
if (typeof error !== "string") {
logError(LogCategory.DNS, tr("Failed to resolve %o: %o"), address, error);
error = tr("lookup the console");
}
@ -364,9 +381,9 @@ export async function resolveTeaSpeakServerAddress(address: DNSAddress, _options
}
}
export async function resolveAddressIpV4(address: string) : Promise<string> {
export async function resolveAddressIpV4(address: string): Promise<string> {
const result = await executeDnsRequest(address, RRType.A);
if(!result.length) return undefined;
if (!result.length) return undefined;
return result[0].data;
}