Files
XCDesktop/remote/src/services/network/FRPService.js
2026-03-08 01:34:54 +08:00

132 lines
3.4 KiB
JavaScript

const { spawn } = require('child_process');
const path = require('path');
const fs = require('fs');
const config = require('../../config');
const paths = require('../../utils/paths');
const logger = require('../../utils/logger');
class FRPService {
constructor(options = {}) {
this.enabled = options.enabled !== false;
this.frpcPath = options.frpcPath || path.join(paths.getFRPPath(), 'frpc.exe');
this.configPath = options.configPath || path.join(paths.getFRPPath(), 'frpc.toml');
this.process = null;
this.isRunning = false;
}
_prepareConfig() {
const frpDir = paths.getFRPPath();
const logPath = path.join(paths.getBasePath(), 'logs', 'frpc.log');
const logsDir = path.dirname(logPath);
if (!fs.existsSync(logsDir)) {
fs.mkdirSync(logsDir, { recursive: true });
}
if (fs.existsSync(this.configPath)) {
let content = fs.readFileSync(this.configPath, 'utf8');
content = content.replace(/log\.to\s*=\s*"[^"]*"/, `log.to = "${logPath.replace(/\\/g, '\\\\')}"`);
const tempConfigPath = path.join(frpDir, 'frpc-runtime.toml');
fs.writeFileSync(tempConfigPath, content);
return tempConfigPath;
}
return this.configPath;
}
start() {
if (!this.enabled) {
logger.info('FRP service is disabled');
return;
}
if (this.isRunning) {
logger.warn('FRP service is already running');
return;
}
try {
if (!fs.existsSync(this.frpcPath)) {
logger.error('FRP client not found', { path: this.frpcPath });
return;
}
if (!fs.existsSync(this.configPath)) {
logger.error('FRP config not found', { path: this.configPath });
return;
}
const runtimeConfigPath = this._prepareConfig();
logger.info('Starting FRP client', {
frpcPath: this.frpcPath,
configPath: runtimeConfigPath
});
this.process = spawn(this.frpcPath, ['-c', runtimeConfigPath], {
stdio: ['ignore', 'pipe', 'pipe'],
windowsHide: true
});
this.isRunning = true;
this.process.stdout.on('data', (data) => {
const output = data.toString().trim();
if (output) {
logger.info(`[FRP] ${output}`);
}
});
this.process.stderr.on('data', (data) => {
const output = data.toString().trim();
if (output) {
logger.error(`[FRP] ${output}`);
}
});
this.process.on('error', (error) => {
logger.error('FRP process error', { error: error.message });
this.isRunning = false;
});
this.process.on('close', (code) => {
logger.info('FRP process closed', { code });
this.isRunning = false;
this.process = null;
});
logger.info('FRP service started successfully');
} catch (error) {
logger.error('Failed to start FRP service', { error: error.message });
this.isRunning = false;
}
}
stop() {
if (!this.isRunning || !this.process) {
return;
}
logger.info('Stopping FRP service');
try {
this.process.kill();
this.process = null;
this.isRunning = false;
logger.info('FRP service stopped');
} catch (error) {
logger.error('Failed to stop FRP service', { error: error.message });
}
}
getStatus() {
return {
enabled: this.enabled,
running: this.isRunning
};
}
}
module.exports = FRPService;