🏗️ implement proxy management features and refactor related services

This commit is contained in:
刘嘉伟 2025-02-23 21:07:44 +08:00
parent 2edbbcb871
commit 9f46ea781d
23 changed files with 588 additions and 387 deletions

View File

@ -1,108 +0,0 @@
import {ipcMain} from "electron";
import { logDebug, logError, logInfo, LogModule, logWarn } from "../utils/log";
const {exec, spawn} = require("child_process");
type LocalPort = {
protocol: string;
ip: string;
port: number;
}
export const initLocalApi = () => {
const command = process.platform === 'win32'
? 'netstat -a -n'
: 'netstat -an | grep LISTEN';
ipcMain.on("local.getLocalPorts", async (event, args) => {
logInfo(LogModule.APP, "Starting to retrieve local ports");
// 执行命令
exec(command, (error, stdout, stderr) => {
if (error) {
logError(LogModule.APP, `getLocalPorts - error: ${error.message}`);
return;
}
if (stderr) {
logWarn(LogModule.APP, `getLocalPorts - stderr: ${stderr}`);
return;
}
logDebug(LogModule.APP, `Command output: ${stdout}`);
let ports = [];
if (stdout) {
if (process.platform === 'win32') {
// window
ports = stdout.split('\r\n')
.filter(f => f.indexOf('TCP') !== -1 || f.indexOf('UDP') !== -1)
.map(m => {
const cols = m.split(' ')
.filter(f => f != '')
const local = cols[1]
const s = local.lastIndexOf(":")
let localIP = local.slice(0, s);
let localPort = local.slice(s - local.length + 1);
const singe: LocalPort = {
protocol: cols[0],
ip: localIP,
port: localPort
}
return singe;
})
} else if (process.platform === 'darwin') {
// mac
ports = stdout.split('\n')
.filter(m => {
const cols = m.split(' ')
.filter(f => f != '')
const local = cols[3]
return local
})
.map(m => {
const cols = m.split(' ')
.filter(f => f != '')
const local = cols[3]
const s = local.lastIndexOf(".")
let localIP = local.slice(0, s);
let localPort = local.slice(s - local.length + 1);
const singe: LocalPort = {
protocol: cols[0],
ip: localIP,
port: localPort
}
return singe;
})
} else if (process.platform === 'linux') {
ports = stdout.split('\n')
.filter(f =>
f.indexOf('tcp') !== -1||
f.indexOf('tcp6') !== -1||
f.indexOf('udp') !== -1 ||
f.indexOf('udp6') !== -1
).map(m => {
const cols = m.split(' ')
.filter(f => f != '')
const local = cols[3]
const s = local.lastIndexOf(":")
let localIP = local.slice(0, s);
let localPort = local.slice(s - local.length + 1);
const singe: LocalPort = {
protocol: cols[0],
ip: localIP,
port: localPort
}
return singe;
})
}
}
ports.sort((a, b) => a.port - b.port);
event.reply("local.getLocalPorts.hook", {
data: ports
});
});
});
}

View File

@ -1,115 +0,0 @@
import { ipcMain } from "electron";
import {
deleteProxyById,
getProxyById,
insertProxy,
listProxy,
updateProxyById,
updateProxyStatus
} from "../storage/proxy";
import { reloadFrpcProcess } from "./frpc";
import { logError, logInfo, LogModule, logWarn } from "../utils/log";
export const initProxyApi = () => {
ipcMain.on("proxy.getProxys", async (event, args) => {
logInfo(LogModule.APP, "Requesting to get proxies.");
listProxy((err, documents) => {
if (err) {
logError(LogModule.APP, `Error retrieving proxies: ${err.message}`);
} else {
logInfo(LogModule.APP, "Proxies retrieved successfully.");
}
event.reply("Proxy.getProxys.hook", {
err: err,
data: documents
});
});
});
ipcMain.on("proxy.insertProxy", async (event, args) => {
delete args["_id"];
logInfo(LogModule.APP, "Inserting a new proxy.");
insertProxy(args, (err, documents) => {
if (err) {
logError(LogModule.APP, `Error inserting proxy: ${err.message}`);
} else {
logInfo(LogModule.APP, "Proxy inserted successfully.");
reloadFrpcProcess();
}
event.reply("Proxy.insertProxy.hook", {
err: err,
data: documents
});
});
});
ipcMain.on("proxy.deleteProxyById", async (event, args) => {
logInfo(LogModule.APP, `Deleting proxy with ID: ${args._id}`);
deleteProxyById(args, (err, documents) => {
if (err) {
logError(LogModule.APP, `Error deleting proxy: ${err.message}`);
} else {
logInfo(LogModule.APP, "Proxy deleted successfully.");
reloadFrpcProcess();
}
event.reply("Proxy.deleteProxyById.hook", {
err: err,
data: documents
});
});
});
ipcMain.on("proxy.getProxyById", async (event, args) => {
logInfo(LogModule.APP, `Requesting proxy with ID: ${args._id}`);
getProxyById(args, (err, documents) => {
if (err) {
logError(LogModule.APP, `Error retrieving proxy: ${err.message}`);
} else {
logInfo(LogModule.APP, "Proxy retrieved successfully.");
}
event.reply("Proxy.getProxyById.hook", {
err: err,
data: documents
});
});
});
ipcMain.on("proxy.updateProxy", async (event, args) => {
if (!args._id) {
logWarn(LogModule.APP, "No proxy ID provided for update.");
return;
}
logInfo(LogModule.APP, `Updating proxy with ID: ${args._id}`);
updateProxyById(args, (err, documents) => {
if (err) {
logError(LogModule.APP, `Error updating proxy: ${err.message}`);
} else {
logInfo(LogModule.APP, "Proxy updated successfully.");
reloadFrpcProcess();
}
event.reply("Proxy.updateProxy.hook", {
err: err,
data: documents
});
});
});
ipcMain.on("proxy.updateProxyStatus", async (event, args) => {
logInfo(LogModule.APP, `Updating status for proxy ID: ${args._id}`);
if (!args._id) {
logWarn(LogModule.APP, "No proxy ID provided for status update.");
return;
}
updateProxyStatus(args._id, args.status, (err, documents) => {
if (err) {
logError(LogModule.APP, `Error updating proxy status: ${err.message}`);
} else {
logInfo(LogModule.APP, "Proxy status updated successfully.");
reloadFrpcProcess();
}
event.reply("Proxy.updateProxyStatus.hook", {
err: err,
data: documents
});
});
});
};

View File

@ -1,5 +1,17 @@
import BaseController from "./BaseController"; import BaseController from "./BaseController";
import FrpcProcessService from "../service/FrpcProcessService";
class LaunchController extends BaseController { class LaunchController extends BaseController {
private readonly _frpcProcessService: FrpcProcessService;
constructor(frpcProcessService: FrpcProcessService) {
super();
this._frpcProcessService = frpcProcessService;
} }
launch(req: ControllerParam) {
this._frpcProcessService.startFrpcProcess().then(r => {});
}
}
export default LaunchController;

View File

@ -1,7 +1,53 @@
import BaseController from "./BaseController"; import BaseController from "./BaseController";
import ProxyService from "../service/ProxyService";
import { success } from "../utils/response";
import ProxyDao from "../dao/ProxyDao";
class ProxyController extends BaseController { class ProxyController extends BaseController {
constructor() { private readonly _proxyService: ProxyService;
private readonly _proxyDao: ProxyDao;
constructor(proxyService: ProxyService, proxyDao: ProxyDao) {
super(); super();
this._proxyService = proxyService;
this._proxyDao = proxyDao;
}
createProxy(req: ControllerParam) {
this._proxyService.insertProxy(req.args).then(data => {
req.event.reply(req.channel, success(data));
});
}
modifyProxy(req: ControllerParam) {
this._proxyService.updateProxy(req.args).then(data => {
req.event.reply(req.channel, success(data));
});
}
getAllProxies(req: ControllerParam) {
this._proxyDao.findAll().then(data => {
req.event.reply(req.channel, success(data));
});
}
deleteProxy(req: ControllerParam) {
this._proxyService.deleteProxy(req.args).then(data => {
req.event.reply(req.channel, success(data));
});
}
modifyProxyStatus(req: ControllerParam) {
this._proxyDao.updateProxyStatus(req.args.id, req.args.status).then(() => {
req.event.reply(req.channel, success());
});
}
getLocalPorts(req: ControllerParam) {
this._proxyService.getLocalPorts().then(data => {
req.event.reply(req.channel, success(data));
});
} }
} }
export default ProxyController;

View File

@ -1,19 +1,23 @@
import BaseController from "./BaseController"; import BaseController from "./BaseController";
import ServerService from "../service/ServerService"; import ServerService from "../service/ServerService";
import { success } from "../utils/response"; import { success } from "../utils/response";
import FileService from "../service/FileService";
import PathUtils from "../utils/PathUtils";
class ServerController extends BaseController { class ServerController extends BaseController {
private readonly _serverService: ServerService; private readonly _serverService: ServerService;
private readonly _fileService: FileService;
constructor(serverService: ServerService) { constructor(serverService: ServerService, fileService: FileService) {
super(); super();
this._serverService = serverService; this._serverService = serverService;
this._fileService = fileService;
} }
saveConfig(req: ControllerParam) { saveConfig(req: ControllerParam) {
this._serverService.saveServerConfig(req.args).then(() => { this._serverService.saveServerConfig(req.args).then(() => {
req.event.reply(req.channel, success()); req.event.reply(req.channel, success());
}) });
} }
getServerConfig(req: ControllerParam) { getServerConfig(req: ControllerParam) {
@ -21,7 +25,12 @@ class ServerController extends BaseController {
this._serverService.getServerConfig().then(data => { this._serverService.getServerConfig().then(data => {
req.event.reply(req.channel, success(data)); req.event.reply(req.channel, success(data));
}); });
}
openAppData(req: ControllerParam) {
this._fileService.openLocalPath(PathUtils.getAppData()).then(data => {
req.event.reply(req.channel, success(data));
});
} }
} }

View File

@ -62,6 +62,10 @@ class VersionController extends BaseController {
req.event.reply(req.channel, fail()); req.event.reply(req.channel, fail());
}); });
} }
importLocalFrpcVersion (){
}
} }
export default VersionController; export default VersionController;

View File

@ -9,6 +9,11 @@ import VersionController from "../controller/VersionController";
import FileService from "../service/FileService"; import FileService from "../service/FileService";
import VersionDao from "../dao/VersionDao"; import VersionDao from "../dao/VersionDao";
import GitHubService from "../service/GitHubService"; import GitHubService from "../service/GitHubService";
import FrpcProcessService from "../service/FrpcProcessService";
import LaunchController from "../controller/LaunchController";
import ProxyDao from "../dao/ProxyDao";
import ProxyService from "../service/ProxyService";
import ProxyController from "../controller/ProxyController";
export const ipcRouters: IpcRouters = { export const ipcRouters: IpcRouters = {
SERVER: { SERVER: {
@ -48,6 +53,38 @@ export const ipcRouters: IpcRouters = {
path: "version/deleteDownloadedVersion", path: "version/deleteDownloadedVersion",
controller: "versionController.deleteDownloadedVersion" controller: "versionController.deleteDownloadedVersion"
} }
},
LAUNCH: {
launch: {
path: "launch/launch",
controller: "launchController.launch"
}
},
PROXY: {
createProxy: {
path: "proxy/createProxy",
controller: "proxyController.createProxy"
},
modifyProxy: {
path: "proxy/modifyProxy",
controller: "proxyController.modifyProxy"
},
deleteProxy: {
path: "proxy/deleteProxy",
controller: "proxyController.deleteProxy"
},
getAllProxies: {
path: "proxy/getAllProxies",
controller: "proxyController.getAllProxies"
},
modifyProxyStatus: {
path: "proxy/modifyProxyStatus",
controller: "proxyController.modifyProxyStatus"
},
getLocalPorts: {
path: "proxy/getLocalPorts",
controller: "proxyController.getLocalPorts"
}
} }
}; };
@ -70,8 +107,9 @@ class IpcRouterConfigurate {
private initializeBeans() { private initializeBeans() {
const serverDao = new ServerDao(); const serverDao = new ServerDao();
const versionDao = new VersionDao(); const versionDao = new VersionDao();
const proxyDao = new ProxyDao();
const fileService = new FileService(); const fileService = new FileService();
const serverService = new ServerService(serverDao); const serverService = new ServerService(serverDao, proxyDao);
const gitHubService = new GitHubService(); const gitHubService = new GitHubService();
const versionService = new VersionService( const versionService = new VersionService(
versionDao, versionDao,
@ -79,19 +117,31 @@ class IpcRouterConfigurate {
gitHubService gitHubService
); );
const logService = new LogService(fileService); const logService = new LogService(fileService);
const serverController = new ServerController(serverService); const frpcProcessService = new FrpcProcessService(
serverService,
versionDao
);
const proxyService = new ProxyService(proxyDao);
const serverController = new ServerController(serverService, fileService);
const versionController = new VersionController(versionService, versionDao); const versionController = new VersionController(versionService, versionDao);
const logController = new LogController(logService); const logController = new LogController(logService);
const launchController = new LaunchController(frpcProcessService);
const proxyController = new ProxyController(proxyService, proxyDao);
this._beans.set("serverDao", serverDao); this._beans.set("serverDao", serverDao);
this._beans.set("versionDao", versionDao); this._beans.set("versionDao", versionDao);
this._beans.set("proxyDao", proxyDao);
this._beans.set("fileService", fileService); this._beans.set("fileService", fileService);
this._beans.set("serverService", serverService); this._beans.set("serverService", serverService);
this._beans.set("versionService", versionService); this._beans.set("versionService", versionService);
this._beans.set("logService", logService); this._beans.set("logService", logService);
this._beans.set("proxyService", proxyService);
this._beans.set("frpcProcessService", frpcProcessService);
this._beans.set("serverController", serverController); this._beans.set("serverController", serverController);
this._beans.set("versionController", versionController); this._beans.set("versionController", versionController);
this._beans.set("logController", logController); this._beans.set("logController", logController);
this._beans.set("launchController", launchController);
this._beans.set("proxyController", proxyController);
} }
/** /**

26
electron/dao/ProxyDao.ts Normal file
View File

@ -0,0 +1,26 @@
import BaseDao from "./BaseDao";
class ProxyDao extends BaseDao<FrpcProxy> {
constructor() {
super("proxy");
}
updateProxyStatus(id: string, status: number): Promise<void> {
return new Promise<void>((resolve, reject) => {
this.db.update(
{ _id: id },
{ $set: { status: status } },
{},
(err, numberOfUpdated, upsert) => {
if (err) {
reject(err);
} else {
resolve();
}
}
);
});
}
}
export default ProxyDao;

View File

@ -12,7 +12,6 @@ import { release } from "node:os";
import node_path, { join } from "node:path"; import node_path, { join } from "node:path";
import { initGitHubApi } from "../api/github"; import { initGitHubApi } from "../api/github";
import { initConfigApi } from "../api/config"; import { initConfigApi } from "../api/config";
import { initProxyApi } from "../api/proxy";
import { import {
initFrpcApi, initFrpcApi,
startFrpWorkerProcess, startFrpWorkerProcess,
@ -21,7 +20,6 @@ import {
import { initFileApi } from "../api/file"; import { initFileApi } from "../api/file";
import { getConfig } from "../storage/config"; import { getConfig } from "../storage/config";
import { initCommonApi } from "../api/common"; import { initCommonApi } from "../api/common";
import { initLocalApi } from "../api/local";
import { initLog, logError, logInfo, LogModule } from "../utils/log"; import { initLog, logError, logInfo, LogModule } from "../utils/log";
import { maskSensitiveData } from "../utils/desensitize"; import { maskSensitiveData } from "../utils/desensitize";
import IpcRouterConfigurate from "../core/IpcRouter"; import IpcRouterConfigurate from "../core/IpcRouter";
@ -201,8 +199,6 @@ app.whenReady().then(() => {
initConfigApi(win); initConfigApi(win);
logInfo(LogModule.APP, `Config API initialized.`); logInfo(LogModule.APP, `Config API initialized.`);
initProxyApi();
logInfo(LogModule.APP, `Proxy API initialized.`);
initFrpcApi(); initFrpcApi();
logInfo(LogModule.APP, `FRPC API initialized.`); logInfo(LogModule.APP, `FRPC API initialized.`);
@ -215,8 +211,6 @@ app.whenReady().then(() => {
initCommonApi(); initCommonApi();
logInfo(LogModule.APP, `Common API initialized.`); logInfo(LogModule.APP, `Common API initialized.`);
initLocalApi();
logInfo(LogModule.APP, `Local API initialized.`);
// initUpdaterApi(win); // initUpdaterApi(win);
logInfo(LogModule.APP, `Updater API initialization skipped.`); logInfo(LogModule.APP, `Updater API initialization skipped.`);

View File

@ -1,10 +1,11 @@
import { shell } from "electron"; import { dialog, shell } from "electron";
import path from "path"; import path from "path";
import fs from "fs"; import fs from "fs";
import zlib from "zlib"; import zlib from "zlib";
import admZip from "adm-zip"; import admZip from "adm-zip";
import GlobalConstant from "../core/GlobalConstant"; import GlobalConstant from "../core/GlobalConstant";
// import tar from "tar"; // import tar from "tar";
const tar = require("tar"); const tar = require("tar");
@ -28,6 +29,18 @@ class FileService {
}); });
} }
openLocalPath(path: string) {
return new Promise<boolean>((resolve, reject) => {
shell.openPath(path).then(errorMessage => {
if (errorMessage) {
resolve(false);
} else {
reject(true);
}
});
});
}
decompressZipFile(zipFilePath: string, targetPath: string) { decompressZipFile(zipFilePath: string, targetPath: string) {
if (!zipFilePath.endsWith(GlobalConstant.ZIP_EXT)) { if (!zipFilePath.endsWith(GlobalConstant.ZIP_EXT)) {
throw new Error("The file is not a .zip file"); throw new Error("The file is not a .zip file");
@ -86,6 +99,18 @@ class FileService {
// ); // );
}); });
} }
selectLocalFile(name: string, path: any) {
dialog.showOpenDialogSync({
properties: ["openFile"],
filters: [
{
name: name,
extensions: path
}
]
});
}
} }
export default FileService; export default FileService;

View File

@ -1,13 +1,13 @@
import ServerService from "./ServerService"; import ServerService from "./ServerService";
import VersionDao from "../dao/VersionDao"; import VersionDao from "../dao/VersionDao";
import PathUtils from "../utils/PathUtils"; import PathUtils from "../utils/PathUtils";
import { frpcProcess } from "../api/frpc";
import GlobalConstant from "../core/GlobalConstant"; import GlobalConstant from "../core/GlobalConstant";
import { Notification } from "electron"; import { Notification } from "electron";
import { logDebug, LogModule } from "../utils/log";
const { exec, spawn } = require("child_process"); const { exec, spawn } = require("child_process");
class FrpProcessService { class FrpcProcessService {
private readonly _serverService: ServerService; private readonly _serverService: ServerService;
private readonly _versionDao: VersionDao; private readonly _versionDao: VersionDao;
private _frpcProcess: any; private _frpcProcess: any;
@ -28,6 +28,7 @@ class FrpProcessService {
config.frpcVersion config.frpcVersion
); );
// todo genConfigfile. // todo genConfigfile.
await this._serverService.genTomlConfig();
const configPath = ""; const configPath = "";
const command = `${PathUtils.getFrpcFilename()} -c ${configPath}`; const command = `${PathUtils.getFrpcFilename()} -c ${configPath}`;
this._frpcProcess = spawn(command, { this._frpcProcess = spawn(command, {
@ -35,11 +36,11 @@ class FrpProcessService {
shell: true shell: true
}); });
frpcProcess.stdout.on("data", data => { this._frpcProcess.stdout.on("data", data => {
// logDebug(LogModule.FRP_CLIENT, `Frpc process output: ${data}`); logDebug(LogModule.FRP_CLIENT, `Frpc process output: ${data}`);
}); });
frpcProcess.stdout.on("error", data => { this._frpcProcess.stdout.on("error", data => {
// logError(LogModule.FRP_CLIENT, `Frpc process error: ${data}`); // logError(LogModule.FRP_CLIENT, `Frpc process error: ${data}`);
// stopFrpcProcess(() => {}); // stopFrpcProcess(() => {});
this.stopFrpcProcess(); this.stopFrpcProcess();
@ -71,4 +72,4 @@ class FrpProcessService {
} }
} }
export default FrpProcessService; export default FrpcProcessService;

View File

@ -0,0 +1,132 @@
import ProxyDao from "../dao/ProxyDao";
const { exec, spawn } = require("child_process");
class ProxyService {
private readonly _proxyDao: ProxyDao;
constructor(proxyDao: ProxyDao) {
this._proxyDao = proxyDao;
}
async insertProxy(proxy: FrpcProxy) {
return await this._proxyDao.insert(proxy);
}
async updateProxy(proxy: FrpcProxy) {
return await this._proxyDao.updateById(proxy._id, proxy);
}
async deleteProxy(proxyId: string) {
return await this._proxyDao.deleteById(proxyId);
}
async getLocalPorts(): Promise<Array<LocalPort>> {
const command =
process.platform === "win32"
? "netstat -a -n"
: "netstat -an | grep LISTEN";
return new Promise((resolve, reject) => {
exec(command, (error, stdout, stderr) => {
if (error) {
reject(error);
}
if (stderr) {
reject(stderr);
}
let ports: Array<LocalPort> = [];
if (stdout) {
if (process.platform === "win32") {
// window
ports = stdout
.split("\r\n")
.filter(f => f.indexOf("TCP") !== -1 || f.indexOf("UDP") !== -1)
.map(m => {
const cols = m.split(" ").filter(f => f != "");
const local = cols[1];
const s = local.lastIndexOf(":");
let localIP = local.slice(0, s);
let localPort = local.slice(s - local.length + 1);
const singe: LocalPort = {
protocol: cols[0],
ip: localIP,
port: localPort
};
return singe;
});
} else if (process.platform === "darwin") {
// mac
ports = stdout
.split("\n")
.filter(m => {
const cols = m.split(" ").filter(f => f != "");
const local = cols[3];
return local;
})
.map(m => {
const cols = m.split(" ").filter(f => f != "");
const local = cols[3];
const s = local.lastIndexOf(".");
let localIP = local.slice(0, s);
let localPort = local.slice(s - local.length + 1);
const singe: LocalPort = {
protocol: cols[0],
ip: localIP,
port: localPort
};
return singe;
});
} else if (process.platform === "linux") {
ports = stdout
.split("\n")
.filter(
f =>
f.indexOf("tcp") !== -1 ||
f.indexOf("tcp6") !== -1 ||
f.indexOf("udp") !== -1 ||
f.indexOf("udp6") !== -1
)
.map(m => {
const cols = m.split(" ").filter(f => f != "");
const local = cols[3];
const s = local.lastIndexOf(":");
let localIP = local.slice(0, s);
let localPort = local.slice(s - local.length + 1);
const singe: LocalPort = {
protocol: cols[0],
ip: localIP,
port: localPort
};
return singe;
});
}
}
ports.sort((a, b) => a.port - b.port);
resolve(ports);
});
// exec(command, (error, stdout, stderr) => {
// if (error) {
// logError(LogModule.APP, `getLocalPorts - error: ${error.message}`);
// return;
// }
// if (stderr) {
// logWarn(LogModule.APP, `getLocalPorts - stderr: ${stderr}`);
// return;
// }
//
// logDebug(LogModule.APP, `Command output: ${stdout}`);
// let ports = [];
//
// event.reply("local.getLocalPorts.hook", {
// data: ports
// });
// });
});
}
}
export default ProxyService;

View File

@ -1,33 +1,68 @@
import BaseService from "./BaseService"; import BaseService from "./BaseService";
import ServerDao from "../dao/ServerDao"; import ServerDao from "../dao/ServerDao";
import TOML from "smol-toml";
import fs from "fs";
import PathUtils from "../utils/PathUtils";
import ProxyDao from "../dao/ProxyDao";
class ServerService extends BaseService<FrpcDesktopServer> { class ServerService extends BaseService<FrpcDesktopServer> {
private readonly _serverDao: ServerDao; private readonly _serverDao: ServerDao;
constructor(serverDao: ServerDao) { private readonly _proxyDao: ProxyDao;
private readonly _serverId: string = "1";
constructor(serverDao: ServerDao, proxyDao: ProxyDao) {
super(); super();
this._serverDao = serverDao; this._serverDao = serverDao;
this._proxyDao = proxyDao;
} }
async saveServerConfig( async saveServerConfig(
frpcServer: FrpcDesktopServer frpcServer: FrpcDesktopServer
): Promise<FrpcDesktopServer> { ): Promise<FrpcDesktopServer> {
return await this._serverDao.updateById("1", frpcServer); frpcServer._id = this._serverId;
return await this._serverDao.updateById(this._serverId, frpcServer);
} }
async getServerConfig(): Promise<FrpcDesktopServer> { async getServerConfig(): Promise<FrpcDesktopServer> {
return await this._serverDao.findById("1"); return await this._serverDao.findById(this._serverId);
} }
hasServerConfig(): Promise<boolean> { hasServerConfig(): Promise<boolean> {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
this._serverDao this._serverDao
.exists("1") .exists(this._serverId)
.then(r => { .then(r => {
resolve(r); resolve(r);
}) })
.catch(err => reject(err)); .catch(err => reject(err));
}); });
} }
async genTomlConfig() {
const server = await this.getServerConfig();
const proxies = await this._proxyDao.findAll();
const enabledProxies = proxies
.filter(f => f.status === 1)
.map(proxy => {
const { _id, status, ...frpProxyConfig } = proxy;
return frpProxyConfig
});
const { frpcVersion, _id, system, ...commonConfig } = server;
const frpcConfig = { ...commonConfig };
frpcConfig.log.to = PathUtils.getFrpcLogFilePath();
const toml = TOML.stringify({ ...frpcConfig, enabledProxies });
fs.writeFile(
PathUtils.getTomlConfigFilePath(), // 配置文件目录
toml, // 配置文件内容
{ flag: "w" },
err => {
if (err) {
} else {
// callback(filename);
}
}
);
}
} }
export default ServerService; export default ServerService;

View File

@ -4,20 +4,21 @@ import GitHubService from "./GitHubService";
import FileService from "./FileService"; import FileService from "./FileService";
import frpReleasesJson from "../json/frp-releases.json"; import frpReleasesJson from "../json/frp-releases.json";
import { download } from "electron-dl"; import { download } from "electron-dl";
import { BrowserWindow } from "electron"; import { BrowserWindow, dialog } from "electron";
import GlobalConstant from "../core/GlobalConstant"; import GlobalConstant from "../core/GlobalConstant";
import path from "path"; import path from "path";
import fs from "fs"; import fs from "fs";
import SecureUtils from "../utils/SecureUtils"; import SecureUtils from "../utils/SecureUtils";
import PathUtils from "../utils/PathUtils"; import PathUtils from "../utils/PathUtils";
import FileUtils from "../utils/FileUtils"; import FileUtils from "../utils/FileUtils";
import frpChecksums from "../json/frp_all_sha256_checksums.json";
class VersionService extends BaseService<FrpcVersion> { class VersionService extends BaseService<FrpcVersion> {
private readonly _versionDao: VersionDao; private readonly _versionDao: VersionDao;
private readonly _fileService: FileService; private readonly _fileService: FileService;
private readonly _gitHubService: GitHubService; private readonly _gitHubService: GitHubService;
private readonly _currFrpArch: Array<string>; private readonly _currFrpArch: Array<string>;
private versions: Array<FrpcVersion> = []; private _versions: Array<FrpcVersion> = [];
constructor( constructor(
versionDao: VersionDao, versionDao: VersionDao,
@ -34,7 +35,7 @@ class VersionService extends BaseService<FrpcVersion> {
downloadFrpVersion(githubReleaseId: number, onProgress: Function) { downloadFrpVersion(githubReleaseId: number, onProgress: Function) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
const version = this.versions.find( const version = this._versions.find(
f => f.githubReleaseId === githubReleaseId f => f.githubReleaseId === githubReleaseId
); );
if (!version) { if (!version) {
@ -133,8 +134,8 @@ class VersionService extends BaseService<FrpcVersion> {
.then(async (releases: Array<GithubRelease>) => { .then(async (releases: Array<GithubRelease>) => {
const versions: Array<FrpcVersion> = const versions: Array<FrpcVersion> =
await this.githubRelease2FrpcVersion(releases); await this.githubRelease2FrpcVersion(releases);
// const versions: Array<FrpcVersion> = (this.versions = versions); // const _versions: Array<FrpcVersion> = (this._versions = _versions);
this.versions = versions; this._versions = versions;
resolve(versions); resolve(versions);
}) })
.catch(err => reject(err)); .catch(err => reject(err));
@ -158,6 +159,10 @@ class VersionService extends BaseService<FrpcVersion> {
): Promise<Array<FrpcVersion>> { ): Promise<Array<FrpcVersion>> {
const allVersions = await this._versionDao.findAll(); const allVersions = await this._versionDao.findAll();
return releases return releases
.filter(release => {
// only support toml version.
return release.id > 124395282;
})
.filter(release => { .filter(release => {
return this.findCurrentArchitectureAsset(release.assets); return this.findCurrentArchitectureAsset(release.assets);
}) })
@ -197,6 +202,31 @@ class VersionService extends BaseService<FrpcVersion> {
} }
return false; return false;
} }
async importLocalFrpcVersion(win: BrowserWindow) {
const result = await dialog.showOpenDialog(win, {
properties: ["openFile"],
filters: [
{ name: "Frpc", extensions: ["tar.gz", "zip"] } // 允许选择的文件类型,分开后缀以确保可以选择
]
});
if (result.canceled) {
return;
} else {
const filePath = result.filePaths[0];
const checksum = FileUtils.calculateFileChecksum(filePath);
const frpName = frpChecksums[checksum];
if (frpName) {
if (this._currFrpArch.every(item => frpName.includes(item))) {
const version = this.getFrpVersionByAssetName(frpName);
}
}
}
}
getFrpVersionByAssetName(assetName: string) {
return this._versions.find(f => f.assetName === assetName);
}
} }
export default VersionService; export default VersionService;

View File

@ -18,6 +18,12 @@ class FileUtils {
hash.update(fileBuffer); hash.update(fileBuffer);
return hash.digest("hex"); return hash.digest("hex");
} }
public static mkdir(path: string) {
if (!fs.existsSync(path)) {
fs.mkdirSync(path, { recursive: true, mode: 0o777 });
}
}
} }
export default FileUtils; export default FileUtils;

View File

@ -2,29 +2,61 @@ import SecureUtils from "./SecureUtils";
import { app } from "electron"; import { app } from "electron";
import path from "path"; import path from "path";
import FileUtils from "./FileUtils";
class PathUtils { class PathUtils {
public static getDownloadStoragePath() { public static getDownloadStoragePath() {
return path.join( const result = path.join(PathUtils.getAppData(), "download");
PathUtils.getAppData(), FileUtils.mkdir(result);
SecureUtils.calculateMD5("download") return result;
);
} }
public static getVersionStoragePath() { public static getVersionStoragePath() {
return path.join( const result = path.join(
PathUtils.getAppData(), PathUtils.getAppData(),
SecureUtils.calculateMD5("frpc") SecureUtils.calculateMD5("frpc")
); );
FileUtils.mkdir(result);
return result;
}
public static getConfigStoragePath() {
const result = path.join(
PathUtils.getAppData(),
// SecureUtils.calculateMD5("config")
"config"
);
FileUtils.mkdir(result);
return result;
} }
public static getFrpcFilename() { public static getFrpcFilename() {
return SecureUtils.calculateMD5("frpc") return SecureUtils.calculateMD5("frpc");
} }
public static getAppData() { public static getAppData() {
return app.getPath("userData"); return app.getPath("userData");
} }
public static getTomlConfigFilePath() {
return path.join(
PathUtils.getConfigStoragePath(),
SecureUtils.calculateMD5("frpc") + ".toml"
);
}
public static getFrpcLogStoragePath() {
const result = path.join(PathUtils.getAppData(), "log");
FileUtils.mkdir(result);
return result;
}
public static getFrpcLogFilePath() {
return path.join(
PathUtils.getFrpcLogStoragePath(),
SecureUtils.calculateMD5("frpc-log") + ".log"
);
}
} }
export default PathUtils; export default PathUtils;

View File

@ -85,6 +85,7 @@
"snowflakify": "^1.0.5", "snowflakify": "^1.0.5",
"tar": "^6.2.0", "tar": "^6.2.0",
"unused-filename": "^4.0.1", "unused-filename": "^4.0.1",
"uuid": "^10.0.0" "uuid": "^10.0.0",
"smol-toml": "^1.3.1"
} }
} }

View File

@ -200,15 +200,12 @@ const handleSubmit = useDebounceFn(() => {
if (valid) { if (valid) {
loading.value = 1; loading.value = 1;
const data = clone(formData.value); const data = clone(formData.value);
ipcRenderer.send("server/saveConfig", data); send(ipcRouters.SERVER.saveConfig, data);
// ipcRenderer.send("server/saveConfig", data);
} }
}); });
}, 300); }, 300);
const handleLoadVersions = () => {
ipcRenderer.send("config.versions");
};
const handleAuthMethodChange = e => { const handleAuthMethodChange = e => {
if (e === "multiuser") { if (e === "multiuser") {
ElMessageBox.alert( ElMessageBox.alert(
@ -242,12 +239,14 @@ const handleLoadSavedConfig = () => {
send(ipcRouters.SERVER.getServerConfig); send(ipcRouters.SERVER.getServerConfig);
}; };
onMounted(() => { onMounted(() => {
handleLoadDownloadedVersion(); handleLoadDownloadedVersion();
handleLoadSavedConfig(); handleLoadSavedConfig();
on(ipcRouters.SERVER.getServerConfig, data => { on(ipcRouters.SERVER.getServerConfig, data => {
console.log("data", data); console.log("data", data);
formData.value = data;
loading.value--; loading.value--;
}); });
@ -256,6 +255,14 @@ onMounted(() => {
versions.value = data; versions.value = data;
// checkAndResetVersion(); // checkAndResetVersion();
}); });
on(ipcRouters.SERVER.saveConfig, data => {
ElMessage({
type: "success",
message: "保存成功"
});
loading.value--;
});
// ipcRenderer.send("config.getConfig"); // ipcRenderer.send("config.getConfig");
// handleLoadVersions(); // handleLoadVersions();
// ipcRenderer.on("Config.getConfig.hook", (event, args) => { // ipcRenderer.on("Config.getConfig.hook", (event, args) => {

View File

@ -5,6 +5,8 @@ import { ipcRenderer } from "electron";
import { ElMessageBox } from "element-plus"; import { ElMessageBox } from "element-plus";
import router from "@/router"; import router from "@/router";
import { useDebounceFn, useIntervalFn } from "@vueuse/core"; import { useDebounceFn, useIntervalFn } from "@vueuse/core";
import { send } from "@/utils/ipcUtils";
import { ipcRouters } from "../../../electron/core/IpcRouter";
defineComponent({ defineComponent({
name: "Home" name: "Home"
@ -13,7 +15,8 @@ defineComponent({
const running = ref(false); const running = ref(false);
const handleStartFrpc = () => { const handleStartFrpc = () => {
ipcRenderer.send("frpc.start"); // ipcRenderer.send("frpc.start");
send(ipcRouters.LAUNCH.launch);
}; };
const handleStopFrpc = () => { const handleStopFrpc = () => {

View File

@ -15,6 +15,8 @@ import { useClipboard, useDebounceFn } from "@vueuse/core";
import IconifyIconOffline from "@/components/IconifyIcon/src/iconifyIconOffline"; import IconifyIconOffline from "@/components/IconifyIcon/src/iconifyIconOffline";
import commonIps from "./commonIp.json"; import commonIps from "./commonIp.json";
import path from "path"; import path from "path";
import { on, removeRouterListeners, send } from "@/utils/ipcUtils";
import { ipcRouters } from "../../../electron/core/IpcRouter";
defineComponent({ defineComponent({
name: "Proxy" name: "Proxy"
@ -23,7 +25,7 @@ defineComponent({
/** /**
* 代理列表 * 代理列表
*/ */
const proxys = ref<Array<Proxy>>([]); const proxys = ref<Array<FrpcProxy>>([]);
/** /**
* loading * loading
*/ */
@ -44,11 +46,13 @@ const edit = ref({
visible: false visible: false
}); });
const defaultForm = ref<Proxy>({ const defaultForm: FrpcProxy = {
_id: "", _id: "",
hostHeaderRewrite: "",
locations: [],
name: "", name: "",
type: "http", type: "http",
localIp: "", localIP: "",
localPort: "8080", localPort: "8080",
remotePort: "8080", remotePort: "8080",
customDomains: [""], customDomains: [""],
@ -57,7 +61,6 @@ const defaultForm = ref<Proxy>({
secretKey: "", secretKey: "",
bindAddr: "", bindAddr: "",
bindPort: null, bindPort: null,
status: true,
subdomain: "", subdomain: "",
basicAuth: false, basicAuth: false,
httpUser: "", httpUser: "",
@ -67,13 +70,14 @@ const defaultForm = ref<Proxy>({
https2http: false, https2http: false,
https2httpCaFile: "", https2httpCaFile: "",
https2httpKeyFile: "", https2httpKeyFile: "",
keepTunnelOpen: false keepTunnelOpen: false,
}); status: 1
};
/** /**
* 表单内容 * 表单内容
*/ */
const editForm = ref<Proxy>(defaultForm.value); const editForm = ref<FrpcProxy>(defaultForm);
/** /**
* 代理类型 * 代理类型
@ -104,7 +108,7 @@ const editFormRules = reactive<FormRules>({
// } // }
], ],
type: [{ required: true, message: "请选择类型", trigger: "blur" }], type: [{ required: true, message: "请选择类型", trigger: "blur" }],
localIp: [ localIP: [
{ required: true, message: "请输入内网地址", trigger: "blur" }, { required: true, message: "请输入内网地址", trigger: "blur" },
{ {
pattern: /^[\w-]+(\.[\w-]+)+$/, pattern: /^[\w-]+(\.[\w-]+)+$/,
@ -247,7 +251,7 @@ const handleRangePort = () => {
*/ */
const handleSubmit = async () => { const handleSubmit = async () => {
if (!editFormRef.value) return; if (!editFormRef.value) return;
await editFormRef.value.validate(valid => { editFormRef.value.validate(valid => {
if (valid) { if (valid) {
if (handleRangePort()) { if (handleRangePort()) {
const lc = handleGetPortCount(editForm.value.localPort); const lc = handleGetPortCount(editForm.value.localPort);
@ -278,9 +282,9 @@ const handleSubmit = async () => {
loading.value.form = 1; loading.value.form = 1;
const data = clone(editForm.value); const data = clone(editForm.value);
if (data._id) { if (data._id) {
ipcRenderer.send("proxy.updateProxy", data); send(ipcRouters.PROXY.createProxy, data);
} else { } else {
ipcRenderer.send("proxy.insertProxy", data); send(ipcRouters.PROXY.modifyProxy, data);
} }
} }
}); });
@ -305,97 +309,25 @@ const handleDeleteDomain = (index: number) => {
* 加载代理 * 加载代理
*/ */
const handleLoadProxys = () => { const handleLoadProxys = () => {
ipcRenderer.send("proxy.getProxys"); send(ipcRouters.PROXY.getAllProxies);
}; };
/** /**
* 删除代理 * 删除代理
* @param proxy * @param proxy
*/ */
const handleDeleteProxy = (proxy: Proxy) => { const handleDeleteProxy = (proxy: FrpcProxy) => {
ipcRenderer.send("proxy.deleteProxyById", proxy._id); send(ipcRouters.PROXY.deleteProxy, proxy._id);
// ipcRenderer.send("proxy.deleteProxyById", proxy._id);
}; };
/** /**
* 重置表单 * 重置表单
*/ */
const handleResetForm = () => { const handleResetForm = () => {
editForm.value = defaultForm.value; editForm.value = defaultForm;
}; };
/**
* 初始化回调
*/
const handleInitHook = () => {
const InsertOrUpdateHook = (message: string, args: any) => {
loading.value.form--;
const { err } = args;
if (!err) {
ElMessage({
type: "success",
message: message
});
handleResetForm();
handleLoadProxys();
edit.value.visible = false;
}
};
ipcRenderer.on("Proxy.insertProxy.hook", (event, args) => {
InsertOrUpdateHook("新增成功", args);
});
ipcRenderer.on("Proxy.updateProxy.hook", (event, args) => {
InsertOrUpdateHook("修改成功", args);
});
ipcRenderer.on("Proxy.updateProxyStatus.hook", (event, args) => {
if (args.data > 0) {
handleLoadProxys();
}
console.log("更新结果", args);
});
ipcRenderer.on("local.getLocalPorts.hook", (event, args) => {
loading.value.localPorts--;
localPorts.value = args.data;
console.log("内网端口", localPorts.value);
});
// ipcRenderer.on("Proxy.updateProxy.hook", (event, args) => {
// loading.value.form--;
// const { err } = args;
// if (!err) {
// ElMessage({
// type: "success",
// message: ""
// });
// handleResetForm();
// handleLoadProxys();
// edit.value.visible = false;
// }
// });
ipcRenderer.on("Proxy.getProxys.hook", (event, args) => {
loading.value.list--;
const { err, data } = args;
if (!err) {
data.forEach(f => {
if (f.status === null || f.status === undefined) {
f.status = true;
}
});
proxys.value = data;
}
});
ipcRenderer.on("Proxy.deleteProxyById.hook", (event, args) => {
const { err, data } = args;
if (!err) {
handleLoadProxys();
ElMessage({
type: "success",
message: "删除成功"
});
}
});
};
const handleOpenInsert = () => { const handleOpenInsert = () => {
edit.value = { edit.value = {
title: "新增代理", title: "新增代理",
@ -403,10 +335,10 @@ const handleOpenInsert = () => {
}; };
}; };
const handleOpenUpdate = (proxy: Proxy) => { const handleOpenUpdate = (proxy: FrpcProxy) => {
editForm.value = clone(proxy); editForm.value = clone(proxy);
if (!editForm.value.fallbackTimeoutMs) { if (!editForm.value.fallbackTimeoutMs) {
editForm.value.fallbackTimeoutMs = defaultForm.value.fallbackTimeoutMs; editForm.value.fallbackTimeoutMs = defaultForm.fallbackTimeoutMs;
} }
edit.value = { edit.value = {
title: "修改代理", title: "修改代理",
@ -414,17 +346,17 @@ const handleOpenUpdate = (proxy: Proxy) => {
}; };
}; };
const handleReversalUpdate = (proxy: Proxy) => { const handleReversalUpdate = (proxy: FrpcProxy) => {
console.log("更新", proxy); send(ipcRouters.PROXY.modifyProxyStatus, {
ipcRenderer.send("proxy.updateProxyStatus", { id: proxy._id,
_id: proxy._id, status: proxy.status === 1 ? 0 : 1
status: !proxy.status
}); });
}; };
const handleLoadLocalPorts = () => { const handleLoadLocalPorts = () => {
loading.value.localPorts = 1; loading.value.localPorts = 1;
ipcRenderer.send("local.getLocalPorts"); // ipcRenderer.send("local.getLocalPorts");
send(ipcRouters.PROXY.getLocalPorts);
}; };
const handleSelectLocalPort = useDebounceFn((port: number) => { const handleSelectLocalPort = useDebounceFn((port: number) => {
@ -441,7 +373,7 @@ const handleOpenLocalPortDialog = () => {
handleLoadLocalPorts(); handleLoadLocalPorts();
}; };
const allowCopyAccessAddress = (proxy: Proxy) => { const allowCopyAccessAddress = (proxy: FrpcProxy) => {
if ( if (
(proxy.type === "http" || proxy.type === "https") && (proxy.type === "http" || proxy.type === "https") &&
(proxy.customDomains.length < 1 || !proxy.customDomains[0]) (proxy.customDomains.length < 1 || !proxy.customDomains[0])
@ -460,7 +392,7 @@ const allowCopyAccessAddress = (proxy: Proxy) => {
return true; return true;
}; };
const handleCopyAccessAddress = (proxy: Proxy) => { const handleCopyAccessAddress = (proxy: FrpcProxy) => {
if ( if (
(proxy.type === "http" || proxy.type === "https") && (proxy.type === "http" || proxy.type === "https") &&
(proxy.customDomains.length < 1 || !proxy.customDomains[0]) (proxy.customDomains.length < 1 || !proxy.customDomains[0])
@ -584,26 +516,79 @@ const handleSelectFile = (type: number, ext: string[]) => {
}; };
onMounted(() => { onMounted(() => {
handleInitHook();
handleLoadProxys(); handleLoadProxys();
ipcRenderer.send("config.getConfig");
ipcRenderer.on("Config.getConfig.hook", (event, args) => { on(ipcRouters.PROXY.getAllProxies, data => {
const { err, data } = args; console.log("allProxies", data);
if (!err) { loading.value.list--;
if (data) { proxys.value = data;
frpcConfig.value = data; });
}
} const insertOrUpdateHook = (message: string) => {
loading.value.form--;
// const { err } = args;
// if (!err) {
ElMessage({
type: "success",
message: message
});
handleResetForm();
handleLoadProxys();
edit.value.visible = false;
// }
};
on(ipcRouters.PROXY.createProxy, data => {
console.log("data", data);
insertOrUpdateHook("新增成功");
});
on(ipcRouters.PROXY.modifyProxy, data => {
console.log("data", data);
insertOrUpdateHook("修改成功");
});
on(ipcRouters.PROXY.deleteProxy, () => {
handleLoadProxys();
ElMessage({
type: "success",
message: "删除成功"
}); });
}); });
on(ipcRouters.PROXY.modifyProxyStatus, () => {
ElMessage({
type: "success",
message: "修改成功"
});
// handleResetForm();
handleLoadProxys();
// edit.value.visible = false;
});
on(ipcRouters.PROXY.getLocalPorts, data => {
loading.value.localPorts--;
localPorts.value = data;
});
// ipcRenderer.send("config.getConfig");
// ipcRenderer.on("Config.getConfig.hook", (event, args) => {
// const { err, data } = args;
// if (!err) {
// if (data) {
// frpcConfig.value = data;
// }
// }
// });
});
onUnmounted(() => { onUnmounted(() => {
ipcRenderer.removeAllListeners("Proxy.insertProxy.hook"); removeRouterListeners(ipcRouters.PROXY.createProxy);
ipcRenderer.removeAllListeners("Proxy.updateProxy.hook"); removeRouterListeners(ipcRouters.PROXY.modifyProxy);
ipcRenderer.removeAllListeners("Proxy.updateProxyStatus.hook"); removeRouterListeners(ipcRouters.PROXY.deleteProxy);
ipcRenderer.removeAllListeners("Proxy.deleteProxyById.hook"); removeRouterListeners(ipcRouters.PROXY.getAllProxies);
ipcRenderer.removeAllListeners("Proxy.getProxys.hook"); removeRouterListeners(ipcRouters.PROXY.modifyProxyStatus);
ipcRenderer.removeAllListeners("local.getLocalPorts.hook"); removeRouterListeners(ipcRouters.PROXY.getLocalPorts);
}); });
</script> </script>
<template> <template>
@ -641,7 +626,7 @@ onUnmounted(() => {
<span>{{ proxy.name }}</span> <span>{{ proxy.name }}</span>
</div> </div>
<el-tag <el-tag
v-if="!proxy.status" v-if="proxy.status === 0"
class="mr-2" class="mr-2"
type="danger" type="danger"
size="small" size="small"
@ -741,7 +726,7 @@ onUnmounted(() => {
" "
> >
<p class="text-[#ADADAD] font-bold">内网地址</p> <p class="text-[#ADADAD] font-bold">内网地址</p>
<p>{{ proxy.localIp }}</p> <p>{{ proxy.localIP }}</p>
</div> </div>
<div class="text-sm text-center" v-if="proxy.type === 'tcp'"> <div class="text-sm text-center" v-if="proxy.type === 'tcp'">
@ -919,15 +904,15 @@ onUnmounted(() => {
</el-col> </el-col>
<template v-if="!(isStcp || isXtcp || isSudp) || isStcpVisited"> <template v-if="!(isStcp || isXtcp || isSudp) || isStcpVisited">
<el-col :span="12"> <el-col :span="12">
<el-form-item label="内网地址:" prop="localIp"> <el-form-item label="内网地址:" prop="localIP">
<el-autocomplete <el-autocomplete
v-model="editForm.localIp" v-model="editForm.localIP"
:fetch-suggestions="handleIpFetchSuggestions" :fetch-suggestions="handleIpFetchSuggestions"
clearable clearable
placeholder="127.0.0.1" placeholder="127.0.0.1"
/> />
<!-- <el-input--> <!-- <el-input-->
<!-- v-model="editForm.localIp"--> <!-- v-model="editForm.localIP"-->
<!-- placeholder="127.0.0.1"--> <!-- placeholder="127.0.0.1"-->
<!-- clearable--> <!-- clearable-->
<!-- />--> <!-- />-->

2
types/core.d.ts vendored
View File

@ -31,6 +31,8 @@ enum IpcRouterKeys {
SERVER = "SERVER", SERVER = "SERVER",
LOG = "LOG", LOG = "LOG",
VERSION = "VERSION", VERSION = "VERSION",
LAUNCH = "LAUNCH",
PROXY = "PROXY",
} }
type IpcRouters = Record< type IpcRouters = Record<

22
types/frp.d.ts vendored
View File

@ -58,6 +58,24 @@ interface FrpcProxyConfig {
name: string; name: string;
type: string; type: string;
localIP: string; localIP: string;
localPort: number; localPort: any;
remotePort: number; remotePort: any;
customDomains: string[];
locations: string[];
hostHeaderRewrite: string;
stcpModel: string;
serverName: string;
secretKey: string;
bindAddr: string;
bindPort: number;
subdomain: string;
basicAuth: boolean;
httpUser: string;
httpPassword: string;
fallbackTo: string;
fallbackTimeoutMs: number;
https2http: boolean;
https2httpCaFile: string;
https2httpKeyFile: string;
keepTunnelOpen: boolean;
} }

View File

@ -2,7 +2,7 @@ type FrpcDesktopProxy = FrpcProxyConfig & {};
interface BaseEntity { interface BaseEntity {
_id: string; _id: string;
}; }
interface FrpcSystemConfiguration { interface FrpcSystemConfiguration {
launchAtStartup: boolean; launchAtStartup: boolean;
@ -10,8 +10,10 @@ interface FrpcSystemConfiguration {
autoConnectOnStartup: boolean; autoConnectOnStartup: boolean;
} }
type FrpcDesktopServer = FrpcCommonConfig & { type FrpcDesktopServer = BaseEntity &
FrpcCommonConfig & {
frpcVersion: number; frpcVersion: number;
system: any;
}; };
type FrpcVersion = BaseEntity & { type FrpcVersion = BaseEntity & {
@ -31,3 +33,7 @@ type FrpcVersion = BaseEntity & {
type OpenSourceFrpcDesktopServer = FrpcDesktopServer & { type OpenSourceFrpcDesktopServer = FrpcDesktopServer & {
system: FrpcSystemConfiguration; system: FrpcSystemConfiguration;
}; };
type FrpcProxy = BaseEntity & FrpcProxyConfig & {
status: number; // 0: disable 1: enable
};