This commit is contained in:
2026-02-27 10:18:23 +00:00
commit 3f63d19173
36 changed files with 14285 additions and 0 deletions

View File

@@ -0,0 +1,87 @@
import * as plugins from './smartvpn.plugins.js';
import { VpnBridge } from './smartvpn.classes.vpnbridge.js';
import type {
IVpnClientOptions,
IVpnClientConfig,
IVpnStatus,
IVpnStatistics,
TVpnClientCommands,
} from './smartvpn.interfaces.js';
/**
* VPN Client — manages a smartvpn daemon in client mode.
*/
export class VpnClient extends plugins.events.EventEmitter {
private bridge: VpnBridge<TVpnClientCommands>;
private options: IVpnClientOptions;
constructor(options: IVpnClientOptions) {
super();
this.options = options;
this.bridge = new VpnBridge<TVpnClientCommands>({
transport: options.transport,
mode: 'client',
});
// Forward bridge events
this.bridge.on('exit', (code: number | null, signal: string | null) => {
this.emit('exit', { code, signal });
});
this.bridge.on('reconnected', () => {
this.emit('reconnected');
});
}
/**
* Start the daemon bridge (spawn or connect).
*/
public async start(): Promise<boolean> {
return this.bridge.start();
}
/**
* Connect to the VPN server using the provided config.
*/
public async connect(config?: IVpnClientConfig): Promise<{ assignedIp: string }> {
const cfg = config || this.options.config;
if (!cfg) {
throw new Error('VpnClient.connect: no config provided');
}
return this.bridge.sendCommand('connect', { config: cfg });
}
/**
* Disconnect from the VPN server.
*/
public async disconnect(): Promise<void> {
await this.bridge.sendCommand('disconnect', {} as Record<string, never>);
}
/**
* Get current connection status.
*/
public async getStatus(): Promise<IVpnStatus> {
return this.bridge.sendCommand('getStatus', {} as Record<string, never>);
}
/**
* Get traffic statistics.
*/
public async getStatistics(): Promise<IVpnStatistics> {
return this.bridge.sendCommand('getStatistics', {} as Record<string, never>);
}
/**
* Stop the daemon bridge.
*/
public stop(): void {
this.bridge.stop();
}
/**
* Whether the bridge is running.
*/
public get running(): boolean {
return this.bridge.running;
}
}