Skip to content

Commit b93274f

Browse files
committed
Merge remote-tracking branch 'origin/master'
2 parents 0f0d1d6 + 83ff534 commit b93274f

File tree

17 files changed

+237
-106
lines changed

17 files changed

+237
-106
lines changed

src/backend/common/vendor/LastfmApiClient.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@ import LastFm, {
88
} from "lastfm-node-client";
99
import { PlayObject } from "../../../core/Atomic.js";
1010
import { nonEmptyStringOrDefault, splitByFirstFound } from "../../../core/StringUtils.js";
11-
import { joinedUrl, readJson, removeUndefinedKeys, sleep, writeFile } from "../../utils.js";
11+
import { readJson, removeUndefinedKeys, sleep, writeFile } from "../../utils.js";
12+
import { joinedUrl } from "../../utils/NetworkUtils.js";
1213
import { getScrobbleTsSOCDate } from "../../utils/TimeUtils.js";
1314
import { getNodeNetworkException, isNodeNetworkException } from "../errors/NodeErrors.js";
1415
import { UpstreamError } from "../errors/UpstreamError.js";

src/backend/ioc.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@ import { WildcardEmitter } from "./common/WildcardEmitter.js";
88
import { Notifiers } from "./notifier/Notifiers.js";
99
import ScrobbleClients from "./scrobblers/ScrobbleClients.js";
1010
import ScrobbleSources from "./sources/ScrobbleSources.js";
11-
import { generateBaseURL } from "./utils.js";
11+
12+
import { generateBaseURL } from "./utils/NetworkUtils.js";
1213
import { PassThrough } from "stream";
1314

1415
let version: string = 'unknown';

src/backend/notifier/AppriseWebhookNotifier.ts

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ import {
1111
WebhookPayload
1212
} from "../common/infrastructure/config/health/webhooks.js";
1313
import { AbstractWebhookNotifier } from "./AbstractWebhookNotifier.js";
14+
import { URLData } from "../../core/Atomic.js";
15+
import { isPortReachable, joinedUrl, normalizeWebAddress } from "../utils/NetworkUtils.js";
1416

1517
const shortKey = truncateStringToLength(10);
1618

@@ -20,6 +22,8 @@ export class AppriseWebhookNotifier extends AbstractWebhookNotifier {
2022

2123
priorities: PrioritiesConfig;
2224

25+
protected endpoint: URLData;
26+
2327
urls: string[];
2428
keys: string[];
2529

@@ -42,18 +46,24 @@ export class AppriseWebhookNotifier extends AbstractWebhookNotifier {
4246
}
4347

4448
initialize = async () => {
45-
// check url is correct
49+
// check url is correct as a courtesy
50+
this.endpoint = normalizeWebAddress(this.config.host);
51+
this.logger.verbose(`Config URL: '${this.config.host}' => Normalized: '${this.endpoint.normal}'`)
52+
53+
this.initialized = true; // always set as ready to go. Server issues may be transient.
54+
4655
try {
47-
await request.get(this.config.host);
56+
await isPortReachable(this.endpoint.port, { host: this.endpoint.url.hostname });
4857
} catch (e) {
49-
this.logger.error(new Error('Failed to contact Apprise server', {cause: e}));
58+
this.logger.warn(new Error('Unable to detect if server is reachable', { cause: e }));
59+
return;
5060
}
5161

5262
if (this.keys.length > 0) {
5363
let anyOk = false;
5464
for (const key of this.keys) {
5565
try {
56-
const resp = await request.get(`${this.config.host}/json/urls/${key}`);
66+
const resp = await request.get(joinedUrl(this.endpoint.url, `/json/urls/${key}`).toString());
5767
if (resp.statusCode === 204) {
5868
this.logger.warn(`Details for Config ${shortKey(key)} returned no content. Double check the key is set correctly or that the apprise Config is not empty.`);
5969
} else {
@@ -64,9 +74,7 @@ export class AppriseWebhookNotifier extends AbstractWebhookNotifier {
6474
}
6575
}
6676
if (!anyOk) {
67-
this.logger.error('No Apprise Configs were valid!');
68-
this.initialized = false;
69-
return;
77+
this.logger.warn('No Apprise Configs were valid!');
7078
}
7179
}
7280
this.initialized = true;
@@ -83,7 +91,7 @@ export class AppriseWebhookNotifier extends AbstractWebhookNotifier {
8391
if (this.keys.length > 0) {
8492
for (const key of this.keys) {
8593
try {
86-
const resp = await this.callApi(request.post(`${this.config.host}/notify/${key}`)
94+
const resp = await this.callApi(request.post(joinedUrl(this.endpoint.url, `/notify/${key}`).toString())
8795
.type('json')
8896
.send(body));
8997
anyOk = true;
@@ -99,7 +107,7 @@ export class AppriseWebhookNotifier extends AbstractWebhookNotifier {
99107
body.urls = this.urls.join(',')
100108
}
101109
try {
102-
const resp = await this.callApi(request.post(`${this.config.host}/notify`)
110+
const resp = await this.callApi(request.post(joinedUrl(this.endpoint.url, '/notify').toString())
103111
.type('json')
104112
.send(body));
105113
anyOk = true;

src/backend/notifier/GotifyWebhookNotifier.ts

Lines changed: 23 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,17 @@ import { gotify } from 'gotify';
44
import request from 'superagent';
55
import { GotifyConfig, PrioritiesConfig, WebhookPayload } from "../common/infrastructure/config/health/webhooks.js";
66
import { AbstractWebhookNotifier } from "./AbstractWebhookNotifier.js";
7+
import { isPortReachable, normalizeWebAddress } from "../utils/NetworkUtils.js";
8+
import { URLData } from "../../core/Atomic.js";
79

810
export class GotifyWebhookNotifier extends AbstractWebhookNotifier {
911

1012
declare config: GotifyConfig;
1113

1214
priorities: PrioritiesConfig;
1315

16+
protected endpoint: URLData;
17+
1418
constructor(defaultName: string, config: GotifyConfig, logger: Logger) {
1519
super('Gotify', defaultName, config, logger);
1620
this.requiresAuth = true;
@@ -29,14 +33,25 @@ export class GotifyWebhookNotifier extends AbstractWebhookNotifier {
2933
}
3034

3135
initialize = async () => {
32-
// check url is correct
36+
// check url is correct as a courtesy
37+
this.endpoint = normalizeWebAddress(this.config.url);
38+
this.logger.verbose(`Config URL: '${this.config.url}' => Normalized: '${this.endpoint.normal}'`)
39+
40+
this.initialized = true; // always set as ready to go. Server issues may be transient.
41+
42+
try {
43+
await isPortReachable(this.endpoint.port, { host: this.endpoint.url.hostname });
44+
} catch (e) {
45+
this.logger.warn(new Error('Unable to detect if server is reachable', { cause: e }));
46+
return;
47+
}
48+
3349
try {
3450
const url = this.config.url;
3551
const resp = await request.get(`${url}/version`);
36-
this.logger.verbose(`Initialized. Found Server version ${resp.body.version}`);
37-
this.initialized = true;
52+
this.logger.verbose(`Found Server version ${resp.body.version}`);
3853
} catch (e) {
39-
this.logger.error(`Failed to contact server | Error: ${e.message}`);
54+
this.logger.warn(new Error('Server was reachable but could not determine version', { cause: e }));
4055
}
4156
}
4257

@@ -48,19 +63,19 @@ export class GotifyWebhookNotifier extends AbstractWebhookNotifier {
4863
doNotify = async (payload: WebhookPayload) => {
4964
try {
5065
await gotify({
51-
server: this.config.url,
66+
server: this.endpoint.normal,
5267
app: this.config.token,
5368
message: payload.message,
5469
title: payload.title,
5570
priority: this.priorities[payload.priority]
5671
});
5772
this.logger.verbose(`Pushed notification.`);
58-
} catch (e: any) {
73+
} catch (e) {
5974
if(e instanceof HTTPError && e.response.statusCode === 401) {
60-
this.logger.warn(`Unable to push notification. Error returned with 401 which means the TOKEN provided is probably incorrect. Disabling Notifier | Error => ${e.response.body}`);
75+
this.logger.warn(new Error(`Unable to push notification. Error returned with 401 which means the TOKEN provided is probably incorrect. Disabling Notifier \n Response Error => ${e.response.body}`, {cause: e}));
6176
this.authed = false;
6277
} else {
63-
this.logger.warn(`Failed to push notification | Error => ${e.message}`);
78+
this.logger.warn(new Error('Failed to push notification', {cause: e}));
6479
}
6580
}
6681
}

src/backend/notifier/NtfyWebhookNotifier.ts

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,17 @@ import { Config, publish } from 'ntfy';
33
import request from "superagent";
44
import { NtfyConfig, PrioritiesConfig, WebhookPayload } from "../common/infrastructure/config/health/webhooks.js";
55
import { AbstractWebhookNotifier } from "./AbstractWebhookNotifier.js";
6+
import { URLData } from "../../core/Atomic.js";
7+
import { isPortReachable, normalizeWebAddress } from "../utils/NetworkUtils.js";
68

79
export class NtfyWebhookNotifier extends AbstractWebhookNotifier {
810

911
declare config: NtfyConfig;
1012

1113
priorities: PrioritiesConfig;
1214

15+
protected endpoint: URLData;
16+
1317
constructor(defaultName: string, config: NtfyConfig, logger: Logger) {
1418
super('Ntfy', defaultName, config, logger);
1519
const {
@@ -27,24 +31,35 @@ export class NtfyWebhookNotifier extends AbstractWebhookNotifier {
2731
}
2832

2933
initialize = async () => {
30-
// check url is correct
34+
// check url is correct as a courtesy
35+
this.endpoint = normalizeWebAddress(this.config.url);
36+
this.logger.verbose(`Config URL: '${this.config.url}' => Normalized: '${this.endpoint.normal}'`)
37+
38+
this.initialized = true; // always set as ready to go. Server issues may be transient.
39+
40+
try {
41+
await isPortReachable(this.endpoint.port, { host: this.endpoint.url.hostname });
42+
} catch (e) {
43+
this.logger.warn(new Error('Unable to detect if server is reachable', { cause: e }));
44+
return;
45+
}
46+
3147
try {
3248
const url = this.config.url;
3349
const resp = await request.get(`${url}/v1/health`);
3450
if(resp.body !== undefined && typeof resp.body === 'object') {
3551
const {health} = resp.body;
3652
if(health === false) {
37-
this.logger.error('Found Ntfy server but it responded that it was not ready.')
53+
this.logger.warn('Found server but it responded that it was not ready.')
3854
return;
3955
}
4056
} else {
41-
this.logger.error(`Found Ntfy server but expected a response with 'health' in payload. Found => ${resp.body}`);
57+
this.logger.warn(`Found server but expected a response with 'health' in payload. Found => ${resp.body}`);
4258
return;
4359
}
44-
this.logger.info('Initialized. Found Ntfy server');
45-
this.initialized = true;
60+
this.logger.info('Found Ntfy server');
4661
} catch (e) {
47-
this.logger.error(`Failed to contact Ntfy server | Error: ${e.message}`);
62+
this.logger.error(new Error('Failed to contact server', {cause: e}));
4863
}
4964
}
5065

@@ -54,7 +69,7 @@ export class NtfyWebhookNotifier extends AbstractWebhookNotifier {
5469
message: payload.message,
5570
topic: this.config.topic,
5671
title: payload.title,
57-
server: this.config.url,
72+
server: this.endpoint.normal,
5873
priority: this.priorities[payload.priority],
5974
};
6075
if (this.config.username !== undefined) {

src/backend/scrobblers/ScrobbleClients.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,8 @@ import { ListenBrainzClientConfig } from "../common/infrastructure/config/client
1010
import { MalojaClientConfig } from "../common/infrastructure/config/client/maloja.js";
1111
import { WildcardEmitter } from "../common/WildcardEmitter.js";
1212
import { Notifiers } from "../notifier/Notifiers.js";
13-
import { joinedUrl, readJson, thresholdResultSummary } from "../utils.js";
13+
import { readJson, thresholdResultSummary } from "../utils.js";
14+
import { joinedUrl } from "../utils/NetworkUtils.js";
1415
import { getTypeSchemaFromConfigGenerator } from "../utils/SchemaUtils.js";
1516
import { validateJson } from "../utils/ValidationUtils.js";
1617
import AbstractScrobbleClient from "./AbstractScrobbleClient.js";

src/backend/server/index.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,8 @@ import path from "path";
1010
import ViteExpress from "vite-express";
1111
import { projectDir } from "../common/index.js";
1212
import { getRoot } from "../ioc.js";
13-
import { getAddress, parseBool } from "../utils.js";
13+
import { parseBool } from "../utils.js";
14+
import { getAddress } from "../utils/NetworkUtils.js";
1415
import { setupApi } from "./api.js";
1516

1617
const app = addAsync(express());

src/backend/sources/DeezerSource.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@ import request from 'superagent';
66
import { PlayObject } from "../../core/Atomic.js";
77
import { DEFAULT_RETRY_MULTIPLIER, FormatPlayObjectOptions, InternalConfig } from "../common/infrastructure/Atomic.js";
88
import { DeezerSourceConfig } from "../common/infrastructure/config/source/deezer.js";
9-
import { joinedUrl, parseRetryAfterSecsFromObj, readJson, sleep, sortByOldestPlayDate, writeFile, } from "../utils.js";
9+
import { parseRetryAfterSecsFromObj, readJson, sleep, sortByOldestPlayDate, writeFile, } from "../utils.js";
10+
import { joinedUrl } from "../utils/NetworkUtils.js";
1011
import AbstractSource, { RecentlyPlayedOptions } from "./AbstractSource.js";
1112

1213
export default class DeezerSource extends AbstractSource {

src/backend/sources/JellyfinApiSource.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,8 @@ import {
5656
PlayPlatformId, REPORTED_PLAYER_STATUSES
5757
} from "../common/infrastructure/Atomic.js";
5858
import { JellyApiSourceConfig } from "../common/infrastructure/config/source/jellyfin.js";
59-
import { genGroupIdStr, getPlatformIdFromData, joinedUrl, parseBool, } from "../utils.js";
59+
import { genGroupIdStr, getPlatformIdFromData, parseBool, } from "../utils.js";
60+
import { joinedUrl } from "../utils/NetworkUtils.js";
6061
import { parseArrayFromMaybeString } from "../utils/StringUtils.js";
6162
import { MemoryPositionalSource } from "./MemoryPositionalSource.js";
6263
import { FixedSizeList } from "fixed-size-list";

src/backend/sources/PlexApiSource.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,15 +11,15 @@ import {
1111
PlayerStateDataMaybePlay,
1212
PlayPlatformId, REPORTED_PLAYER_STATUSES
1313
} from "../common/infrastructure/Atomic.js";
14-
import { genGroupIdStr, getFirstNonEmptyString, getPlatformIdFromData, joinedUrl, parseBool, } from "../utils.js";
14+
import { genGroupIdStr, getFirstNonEmptyString, getPlatformIdFromData, parseBool, } from "../utils.js";
1515
import { buildStatePlayerPlayIdententifyingInfo, parseArrayFromMaybeString } from "../utils/StringUtils.js";
1616
import { GetSessionsMetadata } from "@lukehagar/plexjs/sdk/models/operations/getsessions.js";
1717
import { PlexAPI } from "@lukehagar/plexjs";
1818
import {
1919
SDKValidationError,
2020
} from "@lukehagar/plexjs/sdk/models/errors";
2121
import { PlexApiSourceConfig } from "../common/infrastructure/config/source/plex.js";
22-
import { isPortReachable } from '../utils/NetworkUtils.js';
22+
import { isPortReachable, joinedUrl } from '../utils/NetworkUtils.js';
2323
import normalizeUrl from 'normalize-url';
2424
import { GetTokenDetailsResponse, GetTokenDetailsUserPlexAccount } from '@lukehagar/plexjs/sdk/models/operations/gettokendetails.js';
2525
import { parseRegexSingle } from '@foxxmd/regex-buddy-core';
@@ -393,7 +393,7 @@ export default class PlexApiSource extends MemoryPositionalSource {
393393
return validSession;
394394
}
395395
return sessions[0];
396-
}
396+
}
397397

398398
sessionToPlayerState = (obj: GetSessionsMetadata): PlayerStateDataMaybePlay => {
399399

0 commit comments

Comments
 (0)