mirror of
https://github.com/remnawave/node.git
synced 2026-10-21 18:31:34 +00:00
chore: release v3.4.2
This commit is contained in:
commit
ea7a835485
18 changed files with 168 additions and 38 deletions
|
|
@ -6,7 +6,6 @@ export enum CipherType {
|
|||
AES_128_GCM = 5,
|
||||
AES_256_GCM = 6,
|
||||
CHACHA20_POLY1305 = 7,
|
||||
NONE = 9,
|
||||
UNKNOWN = 0,
|
||||
UNRECOGNIZED = -1,
|
||||
XCHACHA20_POLY1305 = 8,
|
||||
|
|
|
|||
38
package-lock.json
generated
38
package-lock.json
generated
|
|
@ -1,12 +1,12 @@
|
|||
{
|
||||
"name": "@remnawave/node",
|
||||
"version": "3.4.1",
|
||||
"version": "3.4.2",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "@remnawave/node",
|
||||
"version": "3.4.1",
|
||||
"version": "3.4.2",
|
||||
"license": "AGPL-3.0-only",
|
||||
"dependencies": {
|
||||
"@henrygd/semaphore": "0.1.0",
|
||||
|
|
@ -20,8 +20,8 @@
|
|||
"@nestjs/platform-express": "11.2.1",
|
||||
"@nestjs/schedule": "^6.1.3",
|
||||
"@remnawave/hashed-set": "^0.0.4",
|
||||
"@remnawave/node-plugins": "0.8.2",
|
||||
"@remnawave/xtls-sdk": "0.16.0",
|
||||
"@remnawave/node-plugins": "0.8.3",
|
||||
"@remnawave/xtls-sdk": "0.17.0",
|
||||
"@remnawave/xtls-sdk-nestjs": "0.6.1",
|
||||
"compression": "^1.8.1",
|
||||
"consola": "^3.4.2",
|
||||
|
|
@ -286,9 +286,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@bufbuild/protobuf": {
|
||||
"version": "2.12.1",
|
||||
"resolved": "https://registry.npmjs.org/@bufbuild/protobuf/-/protobuf-2.12.1.tgz",
|
||||
"integrity": "sha512-BvAMfS6LrgZiryOAZ4pBYucu4wG/Ei/9o9DZ9akbREnMLbPJiom2i8b9C8IsKErQoiKqVhrerzt3kOT/RrzLHg==",
|
||||
"version": "2.14.1",
|
||||
"resolved": "https://registry.npmjs.org/@bufbuild/protobuf/-/protobuf-2.14.1.tgz",
|
||||
"integrity": "sha512-agRJn3+EJDUe8AvxTx/LnHA/GErvLE62pSaSk7+MwFOtOv8eWBu/qCq2qoZjBjVZ3C2aiFJCveuSs17KMkYGOw==",
|
||||
"license": "(Apache-2.0 AND BSD-3-Clause)"
|
||||
},
|
||||
"node_modules/@colors/colors": {
|
||||
|
|
@ -2537,24 +2537,24 @@
|
|||
"license": "AGPL-3.0-only"
|
||||
},
|
||||
"node_modules/@remnawave/node-plugins": {
|
||||
"version": "0.8.2",
|
||||
"resolved": "https://registry.npmjs.org/@remnawave/node-plugins/-/node-plugins-0.8.2.tgz",
|
||||
"integrity": "sha512-/klo/XH4imZ2cupLavj4++S+hHgVA8uzhVgpQdC0y9kzUtVE168d7brcYEdxB1UGw49LsER+UDYplcyTSvV5QQ==",
|
||||
"version": "0.8.3",
|
||||
"resolved": "https://registry.npmjs.org/@remnawave/node-plugins/-/node-plugins-0.8.3.tgz",
|
||||
"integrity": "sha512-GtJv0vOoAarwj4dmVndkrOgA9QzqxiX4Qm4AgMKPk+MmLOQhcOfZSXjGrLstekNkuXgvTZY2KnLBzzR1qGcYKA==",
|
||||
"license": "AGPL-3.0-only",
|
||||
"dependencies": {
|
||||
"zod": "4.5.4"
|
||||
}
|
||||
},
|
||||
"node_modules/@remnawave/xtls-sdk": {
|
||||
"version": "0.16.0",
|
||||
"resolved": "https://registry.npmjs.org/@remnawave/xtls-sdk/-/xtls-sdk-0.16.0.tgz",
|
||||
"integrity": "sha512-RKu3Ss+2jBuzHp3uqUqRNOqk1mtq54GfcRgeI83SrrbsZsZBZ6aeX0p2B54jVd6fx2BYyunY+1ZlyzNRK6mvIA==",
|
||||
"version": "0.17.0",
|
||||
"resolved": "https://registry.npmjs.org/@remnawave/xtls-sdk/-/xtls-sdk-0.17.0.tgz",
|
||||
"integrity": "sha512-D6pTJ2CqchuttUbF/b1RDU5+8HSv+FURYGqxyrJ2f7qYf5br8WokSiE7uveeYPn5OwG75HQh4ZFCRsWlA1Fs2A==",
|
||||
"license": "AGPL-3.0-only",
|
||||
"dependencies": {
|
||||
"@bufbuild/protobuf": "^2.12.1",
|
||||
"@bufbuild/protobuf": "^2.14.1",
|
||||
"long": "^5.3.2",
|
||||
"nice-grpc": "^2.1.16",
|
||||
"protobufjs": "^8.6.5"
|
||||
"nice-grpc": "^2.1.17",
|
||||
"protobufjs": "^8.8.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@remnawave/xtls-sdk-nestjs": {
|
||||
|
|
@ -6355,9 +6355,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/protobufjs": {
|
||||
"version": "8.6.5",
|
||||
"resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-8.6.5.tgz",
|
||||
"integrity": "sha512-zeE5LPpencAGXvsxyOYmEgJhxzHY8IsmPAFzstZVhDSVT8QH03q6gMZwZRaQGApevZbAL6u28ugs4CC+YKB2jQ==",
|
||||
"version": "8.8.0",
|
||||
"resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-8.8.0.tgz",
|
||||
"integrity": "sha512-N3xhQ5yyBx3vQq4gubBfASzYhJGNzeDbjqBpu61g7UVylsN/qyffU96TKWD3GbbLOKF82VGNRNvv1+BFgE31Eg==",
|
||||
"license": "BSD-3-Clause",
|
||||
"dependencies": {
|
||||
"long": "^5.3.2"
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@remnawave/node",
|
||||
"version": "3.4.1",
|
||||
"version": "3.4.2",
|
||||
"private": false,
|
||||
"description": "Remnawave Node",
|
||||
"homepage": "https://github.com/remnawave",
|
||||
|
|
@ -42,8 +42,8 @@
|
|||
"@nestjs/platform-express": "11.2.1",
|
||||
"@nestjs/schedule": "^6.1.3",
|
||||
"@remnawave/hashed-set": "^0.0.4",
|
||||
"@remnawave/node-plugins": "0.8.2",
|
||||
"@remnawave/xtls-sdk": "0.16.0",
|
||||
"@remnawave/node-plugins": "0.8.3",
|
||||
"@remnawave/xtls-sdk": "0.17.0",
|
||||
"@remnawave/xtls-sdk-nestjs": "0.6.1",
|
||||
"compression": "^1.8.1",
|
||||
"consola": "^3.4.2",
|
||||
|
|
|
|||
16
src/common/utils/send-webhook.ts
Normal file
16
src/common/utils/send-webhook.ts
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
const WEBHOOK_TIMEOUT_MS = 5_000;
|
||||
|
||||
export function sendWebhook(url: string, body: unknown, onError?: (error: unknown) => void): void {
|
||||
fetch(url, {
|
||||
method: 'POST',
|
||||
headers: { 'content-type': 'application/json' },
|
||||
body: JSON.stringify(body),
|
||||
signal: AbortSignal.timeout(WEBHOOK_TIMEOUT_MS),
|
||||
})
|
||||
.then((response) => {
|
||||
if (!response.ok) onError?.(new Error(`HTTP ${response.status}`));
|
||||
|
||||
return response.body?.cancel();
|
||||
})
|
||||
.catch((error) => onError?.(error));
|
||||
}
|
||||
|
|
@ -1,4 +1,5 @@
|
|||
import { ResetPluginsHandler } from './reset-plugins/reset-plugins.handler';
|
||||
import { RunPostStartHandler } from './run-post-start/run-post-start.handler';
|
||||
import { RunPreStartHandler } from './run-pre-start/run-pre-start.handler';
|
||||
|
||||
export const COMMANDS = [ResetPluginsHandler, RunPreStartHandler];
|
||||
export const COMMANDS = [ResetPluginsHandler, RunPreStartHandler, RunPostStartHandler];
|
||||
|
|
|
|||
2
src/modules/_plugin/commands/run-post-start/index.ts
Normal file
2
src/modules/_plugin/commands/run-post-start/index.ts
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
export * from './run-post-start.command';
|
||||
export * from './run-post-start.handler';
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
import { Command } from '@nestjs/cqrs';
|
||||
|
||||
import { TNodeMetadata } from '@libs/contracts/models';
|
||||
|
||||
export class RunPostStartCommand extends Command<void> {
|
||||
constructor(public readonly metadata: TNodeMetadata | undefined) {
|
||||
super();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
import { Logger } from '@nestjs/common';
|
||||
import { CommandHandler, ICommandHandler } from '@nestjs/cqrs';
|
||||
|
||||
import { PostStartService } from '../../services/post-start.service';
|
||||
import { RunPostStartCommand } from './run-post-start.command';
|
||||
|
||||
@CommandHandler(RunPostStartCommand)
|
||||
export class RunPostStartHandler implements ICommandHandler<RunPostStartCommand> {
|
||||
public readonly logger = new Logger(RunPostStartHandler.name);
|
||||
|
||||
constructor(private readonly postStartService: PostStartService) {}
|
||||
|
||||
async execute(command: RunPostStartCommand) {
|
||||
try {
|
||||
this.postStartService.run(command.metadata);
|
||||
return;
|
||||
} catch (error) {
|
||||
this.logger.error(error);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -4,6 +4,7 @@ import { Logger } from '@nestjs/common';
|
|||
import { IEventHandler, EventsHandler } from '@nestjs/cqrs';
|
||||
|
||||
import { formatExecutionTime, getTime } from '@common/utils/get-elapsed-time';
|
||||
import { sendWebhook } from '@common/utils/send-webhook';
|
||||
import { TorrentBlockerReportModel, XrayWebhookSchema } from '@libs/contracts/models';
|
||||
|
||||
import { NftService } from '../../services/nft.service';
|
||||
|
|
@ -11,7 +12,6 @@ import { PluginStateService } from '../../services/plugin-state.service';
|
|||
import { XrayWebhookEvent } from './xray-webhook.event';
|
||||
|
||||
const SOURCE_REGEX = /^(?:(?:tcp|udp):)?(?:\[(.+?)\]|(.+?))(?::(\d+))?$/;
|
||||
const WEBHOOK_TIMEOUT_MS = 5_000;
|
||||
|
||||
@EventsHandler(XrayWebhookEvent)
|
||||
export class XrayWebhookHandler implements IEventHandler<XrayWebhookEvent> {
|
||||
|
|
@ -80,7 +80,7 @@ export class XrayWebhookHandler implements IEventHandler<XrayWebhookEvent> {
|
|||
const webhookUrl = this.pluginState.torrentBlocker.getWebhookUrl();
|
||||
|
||||
if (webhookUrl) {
|
||||
this.sendWebhook(webhookUrl, report);
|
||||
sendWebhook(webhookUrl, report);
|
||||
}
|
||||
} catch (error) {
|
||||
this.logger.error(`Error in Event XrayWebhookHandler: ${error}`);
|
||||
|
|
@ -99,15 +99,4 @@ export class XrayWebhookHandler implements IEventHandler<XrayWebhookEvent> {
|
|||
|
||||
return candidate;
|
||||
}
|
||||
|
||||
private sendWebhook(url: string, report: TorrentBlockerReportModel): void {
|
||||
fetch(url, {
|
||||
method: 'POST',
|
||||
headers: { 'content-type': 'application/json' },
|
||||
body: JSON.stringify(report),
|
||||
signal: AbortSignal.timeout(WEBHOOK_TIMEOUT_MS),
|
||||
})
|
||||
.then((response) => response.body?.cancel())
|
||||
.catch(() => void 0);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,4 +4,5 @@ export interface IPlugins {
|
|||
torrentBlocker: boolean;
|
||||
connectionDrop: boolean;
|
||||
preStart: boolean;
|
||||
postStart: boolean;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ import { PluginService } from './plugin.service';
|
|||
import { QUERIES } from './queries';
|
||||
import { NftService } from './services/nft.service';
|
||||
import { PluginStateService } from './services/plugin-state.service';
|
||||
import { PostStartService } from './services/post-start.service';
|
||||
import { PreStartService } from './services/pre-start.service';
|
||||
|
||||
@Module({
|
||||
|
|
@ -18,6 +19,7 @@ import { PreStartService } from './services/pre-start.service';
|
|||
PluginStateService,
|
||||
NftService,
|
||||
PreStartService,
|
||||
PostStartService,
|
||||
...QUERIES,
|
||||
...EVENTS,
|
||||
...COMMANDS,
|
||||
|
|
|
|||
|
|
@ -90,6 +90,7 @@ export class PluginService {
|
|||
this.syncConnectionDrop(pluginData, sharedMap);
|
||||
this.syncTorrentBlocker(pluginData, sharedMap);
|
||||
this.syncPreStart(pluginData);
|
||||
this.syncPostStart(pluginData);
|
||||
|
||||
await this.syncIngressFilter(pluginData, sharedMap);
|
||||
await this.syncEgressFilter(pluginData, sharedMap);
|
||||
|
|
@ -170,6 +171,18 @@ export class PluginService {
|
|||
);
|
||||
}
|
||||
|
||||
private syncPostStart(pluginData: TNodePlugin): void {
|
||||
if (!pluginData.postStart) return;
|
||||
if (!pluginData.postStart.enabled) return;
|
||||
if (!this.state.plugins.postStart) return;
|
||||
|
||||
this.state.postStart.configure(pluginData.postStart);
|
||||
|
||||
const { enabled } = this.state.postStart.webhookConfig;
|
||||
|
||||
this.logger.log(`[PLUGIN] Post-Start: webhook ${enabled ? 'enabled' : 'disabled'}.`);
|
||||
}
|
||||
|
||||
private async syncIngressFilter(
|
||||
pluginData: TNodePlugin,
|
||||
sharedMap: Map<string, string[]>,
|
||||
|
|
|
|||
|
|
@ -42,6 +42,7 @@ export class NftService implements OnModuleDestroy, OnModuleInit {
|
|||
torrentBlocker: false,
|
||||
egressFilter: false,
|
||||
preStart: true,
|
||||
postStart: true,
|
||||
});
|
||||
|
||||
try {
|
||||
|
|
@ -66,6 +67,7 @@ export class NftService implements OnModuleDestroy, OnModuleInit {
|
|||
torrentBlocker: true,
|
||||
egressFilter: true,
|
||||
preStart: true,
|
||||
postStart: true,
|
||||
});
|
||||
} catch (error) {
|
||||
this.logger.error(error);
|
||||
|
|
|
|||
|
|
@ -1,13 +1,14 @@
|
|||
import { Injectable } from '@nestjs/common';
|
||||
|
||||
import { IPlugins } from '../interfaces';
|
||||
import { TorrentBlockerState, ConnectionDropState, PreStartState } from './states';
|
||||
import { TorrentBlockerState, ConnectionDropState, PreStartState, PostStartState } from './states';
|
||||
|
||||
@Injectable()
|
||||
export class PluginStateService {
|
||||
public readonly torrentBlocker = new TorrentBlockerState();
|
||||
public readonly connectionDrop = new ConnectionDropState();
|
||||
public readonly preStart = new PreStartState();
|
||||
public readonly postStart = new PostStartState();
|
||||
|
||||
private initialized = false;
|
||||
private lastConfigHash: string | null = null;
|
||||
|
|
@ -18,6 +19,7 @@ export class PluginStateService {
|
|||
torrentBlocker: false,
|
||||
egressFilter: false,
|
||||
preStart: true,
|
||||
postStart: true,
|
||||
};
|
||||
|
||||
private pluginConfigDetails: { uuid: string; name: string } | null = null;
|
||||
|
|
@ -47,6 +49,7 @@ export class PluginStateService {
|
|||
this.torrentBlocker.reset();
|
||||
this.connectionDrop.reset();
|
||||
this.preStart.reset();
|
||||
this.postStart.reset();
|
||||
}
|
||||
|
||||
cleanUpActivePlugin(): void {
|
||||
|
|
|
|||
37
src/modules/_plugin/services/post-start.service.ts
Normal file
37
src/modules/_plugin/services/post-start.service.ts
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
import { Injectable, Logger } from '@nestjs/common';
|
||||
|
||||
import { sendWebhook } from '@common/utils/send-webhook';
|
||||
import { TNodeMetadata } from '@libs/contracts/models';
|
||||
|
||||
import { PluginStateService } from './plugin-state.service';
|
||||
|
||||
@Injectable()
|
||||
export class PostStartService {
|
||||
private readonly logger = new Logger(PostStartService.name);
|
||||
|
||||
constructor(private readonly state: PluginStateService) {}
|
||||
|
||||
public run(metadata: TNodeMetadata | undefined): void {
|
||||
if (!this.state.plugins.postStart) return;
|
||||
if (!this.state.postStart.isEnabled) return;
|
||||
|
||||
this.sendCoreStartedWebhook(metadata);
|
||||
}
|
||||
|
||||
private sendCoreStartedWebhook(metadata: TNodeMetadata | undefined): void {
|
||||
const { enabled, url } = this.state.postStart.webhookConfig;
|
||||
|
||||
if (!enabled) return;
|
||||
|
||||
sendWebhook(
|
||||
url,
|
||||
{
|
||||
scope: 'service',
|
||||
event: 'service.core_started',
|
||||
timestamp: new Date().toISOString(),
|
||||
metadata: metadata ?? {},
|
||||
},
|
||||
(error) => this.logger.warn(`[POST-START] Webhook failed: ${error}`),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,3 +1,4 @@
|
|||
export { ConnectionDropState } from './connection-drop.state';
|
||||
export { TorrentBlockerState } from './torrent-blocker.state';
|
||||
export { PreStartState } from './pre-start.state';
|
||||
export { PostStartState } from './post-start.state';
|
||||
|
|
|
|||
30
src/modules/_plugin/services/states/post-start.state.ts
Normal file
30
src/modules/_plugin/services/states/post-start.state.ts
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
import { TNodePlugin } from '@remnawave/node-plugins';
|
||||
|
||||
type TPostStartConfig = NonNullable<TNodePlugin['postStart']>;
|
||||
type TPostStartWebhook = NonNullable<TPostStartConfig['webhook']>;
|
||||
|
||||
export class PostStartState {
|
||||
private enabled = false;
|
||||
private webhook: TPostStartWebhook = { enabled: false, url: '' };
|
||||
|
||||
get isEnabled(): boolean {
|
||||
return this.enabled;
|
||||
}
|
||||
|
||||
get webhookConfig(): TPostStartWebhook {
|
||||
return this.webhook;
|
||||
}
|
||||
|
||||
configure(config: TPostStartConfig): void {
|
||||
this.enabled = config.enabled;
|
||||
|
||||
this.webhook = config.webhook
|
||||
? { enabled: config.webhook.enabled, url: config.webhook.url }
|
||||
: { enabled: false, url: '' };
|
||||
}
|
||||
|
||||
reset(): void {
|
||||
this.enabled = false;
|
||||
this.webhook = { enabled: false, url: '' };
|
||||
}
|
||||
}
|
||||
|
|
@ -19,6 +19,7 @@ import { KNOWN_ERRORS } from '@libs/contracts/constants';
|
|||
import { IntegrationsService } from '@integration-modules/integrations.service';
|
||||
|
||||
import { ResetPluginsCommand } from '../_plugin/commands/reset-plugins/reset-plugins.command';
|
||||
import { RunPostStartCommand } from '../_plugin/commands/run-post-start/run-post-start.command';
|
||||
import { RunPreStartCommand } from '../_plugin/commands/run-pre-start/run-pre-start.command';
|
||||
import { GetTorrentBlockerStateQuery } from '../_plugin/queries/get-torrent-blocker-state';
|
||||
import { InternalService } from '../internal/internal.service';
|
||||
|
|
@ -242,6 +243,8 @@ export class XrayService implements OnApplicationBootstrap {
|
|||
|
||||
this.logger.log(`✔ XRay Core v${this.xrayVersion} is up and running.`);
|
||||
|
||||
await this.commandBus.execute(new RunPostStartCommand(body.internals.metadata));
|
||||
|
||||
return ok(
|
||||
new StartXrayResponseModel(
|
||||
isStarted,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue