🚧 传输配置完善
This commit is contained in:
parent
a1910be29c
commit
91b97df99a
@ -1,268 +1,277 @@
|
|||||||
import {app, dialog, ipcMain, shell} from "electron";
|
import { app, dialog, ipcMain, shell } from "electron";
|
||||||
import {clearConfig, getConfig, saveConfig} from "../storage/config";
|
import { clearConfig, getConfig, saveConfig } from "../storage/config";
|
||||||
import {clearVersion, listVersion} from "../storage/version";
|
import { clearVersion, listVersion } from "../storage/version";
|
||||||
import {genIniConfig, genTomlConfig, stopFrpcProcess} from "./frpc";
|
import { genIniConfig, genTomlConfig, stopFrpcProcess } from "./frpc";
|
||||||
import {clearProxy, insertProxy, listProxy} from "../storage/proxy";
|
import { clearProxy, insertProxy, listProxy } from "../storage/proxy";
|
||||||
import path from "path";
|
import path from "path";
|
||||||
import fs from "fs";
|
import fs from "fs";
|
||||||
|
|
||||||
const log = require("electron-log");
|
const log = require("electron-log");
|
||||||
const toml = require("@iarna/toml");
|
const toml = require("@iarna/toml");
|
||||||
const {v4: uuidv4} = require("uuid");
|
const { v4: uuidv4 } = require("uuid");
|
||||||
|
|
||||||
export const initConfigApi = win => {
|
export const initConfigApi = win => {
|
||||||
ipcMain.on("config.saveConfig", async (event, args) => {
|
ipcMain.on("config.saveConfig", async (event, args) => {
|
||||||
saveConfig(args, (err, numberOfUpdated, upsert) => {
|
saveConfig(args, (err, numberOfUpdated, upsert) => {
|
||||||
if (!err) {
|
if (!err) {
|
||||||
const start = args.systemSelfStart || false;
|
const start = args.systemSelfStart || false;
|
||||||
log.info("开启自启状态", start);
|
log.info("开启自启状态", start);
|
||||||
app.setLoginItemSettings({
|
app.setLoginItemSettings({
|
||||||
openAtLogin: start, //win
|
openAtLogin: start, //win
|
||||||
openAsHidden: start //macOs
|
openAsHidden: start //macOs
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
event.reply("Config.saveConfig.hook", {
|
||||||
|
err: err,
|
||||||
|
numberOfUpdated: numberOfUpdated,
|
||||||
|
upsert: upsert
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
ipcMain.on("config.getConfig", async (event, args) => {
|
||||||
|
getConfig((err, doc) => {
|
||||||
|
event.reply("Config.getConfig.hook", {
|
||||||
|
err: err,
|
||||||
|
data: doc
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
ipcMain.on("config.versions", event => {
|
||||||
|
listVersion((err, doc) => {
|
||||||
|
event.reply("Config.versions.hook", {
|
||||||
|
err: err,
|
||||||
|
data: doc
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
ipcMain.on("config.hasConfig", event => {
|
||||||
|
getConfig((err, doc) => {
|
||||||
|
event.reply("Config.getConfig.hook", {
|
||||||
|
err: err,
|
||||||
|
data: doc
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
ipcMain.on("config.exportConfig", async (event, args) => {
|
||||||
|
const result = await dialog.showOpenDialog({
|
||||||
|
properties: ["openDirectory"]
|
||||||
|
});
|
||||||
|
const outputDirectory = result.filePaths[0];
|
||||||
|
if (!outputDirectory) {
|
||||||
|
// 取消了
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
log.info(`导出目录 ${outputDirectory} 类型:${args}`);
|
||||||
|
getConfig((err1, config) => {
|
||||||
|
if (!err1 && config) {
|
||||||
|
listProxy((err2, proxys) => {
|
||||||
|
if (!err2) {
|
||||||
|
let configContent = "";
|
||||||
|
if (args === "ini") {
|
||||||
|
configContent = genIniConfig(config, proxys);
|
||||||
|
} else if (args === "toml") {
|
||||||
|
configContent = genTomlConfig(config, proxys);
|
||||||
}
|
}
|
||||||
event.reply("Config.saveConfig.hook", {
|
const configPath = path.join(
|
||||||
err: err,
|
outputDirectory,
|
||||||
numberOfUpdated: numberOfUpdated,
|
`frpc-desktop.${args}`
|
||||||
upsert: upsert
|
);
|
||||||
|
fs.writeFile(
|
||||||
|
configPath, // 配置文件目录
|
||||||
|
configContent, // 配置文件内容
|
||||||
|
{ flag: "w" },
|
||||||
|
err => {
|
||||||
|
if (!err) {
|
||||||
|
// callback(filename);
|
||||||
|
event.reply("config.exportConfig.hook", {
|
||||||
|
data: "导出错误",
|
||||||
|
err: err
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
event.reply("Config.exportConfig.hook", {
|
||||||
|
data: {
|
||||||
|
configPath: configPath
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
});
|
||||||
|
|
||||||
ipcMain.on("config.getConfig", async (event, args) => {
|
const parseTomlConfig = (tomlPath: string) => {
|
||||||
getConfig((err, doc) => {
|
const importConfigPath = tomlPath;
|
||||||
event.reply("Config.getConfig.hook", {
|
const tomlData = fs.readFileSync(importConfigPath, "utf-8");
|
||||||
err: err,
|
log.info(`读取到配置内容 ${tomlData}`);
|
||||||
data: doc
|
const sourceConfig = toml.parse(tomlData);
|
||||||
});
|
// log.info(`解析结果 ${sourceConfig}`);
|
||||||
});
|
// console.log(sourceConfig, "frpcConfig");
|
||||||
});
|
// 解析config
|
||||||
|
const targetConfig: FrpConfig = {
|
||||||
ipcMain.on("config.versions", event => {
|
currentVersion: null,
|
||||||
listVersion((err, doc) => {
|
serverAddr: sourceConfig.serverAddr || "",
|
||||||
event.reply("Config.versions.hook", {
|
serverPort: sourceConfig.serverPort || "",
|
||||||
err: err,
|
authMethod: sourceConfig?.user
|
||||||
data: doc
|
? "multiuser"
|
||||||
});
|
: sourceConfig?.auth?.method || "",
|
||||||
});
|
authToken: sourceConfig?.auth?.token || "",
|
||||||
});
|
transportHeartbeatInterval:
|
||||||
|
sourceConfig?.transport?.heartbeatInterval || 30,
|
||||||
ipcMain.on("config.hasConfig", event => {
|
transportHeartbeatTimeout:
|
||||||
getConfig((err, doc) => {
|
sourceConfig?.transport?.heartbeatTimeout || 90,
|
||||||
event.reply("Config.getConfig.hook", {
|
tlsConfigEnable: sourceConfig?.transport?.tls?.enable || false,
|
||||||
err: err,
|
tlsConfigCertFile: sourceConfig?.transport?.tls?.certFile || "",
|
||||||
data: doc
|
tlsConfigKeyFile: sourceConfig?.transport?.tls?.keyFile || "",
|
||||||
});
|
tlsConfigServerName: sourceConfig?.transport?.tls?.serverName || "",
|
||||||
});
|
tlsConfigTrustedCaFile: sourceConfig?.transport?.tls?.trustedCaFile || "",
|
||||||
});
|
logLevel: sourceConfig?.log?.level || "info",
|
||||||
|
logMaxDays: sourceConfig?.log?.maxDays || 3,
|
||||||
ipcMain.on("config.exportConfig", async (event, args) => {
|
proxyConfigProxyUrl: sourceConfig?.transport?.proxyURL || "",
|
||||||
const result = await dialog.showOpenDialog({
|
proxyConfigEnable: Boolean(sourceConfig?.transport?.proxyURL) || false,
|
||||||
properties: ["openDirectory"]
|
user: sourceConfig?.user || "",
|
||||||
});
|
metaToken: sourceConfig?.metadatas?.token || "",
|
||||||
const outputDirectory = result.filePaths[0];
|
systemSelfStart: false,
|
||||||
if (!outputDirectory) {
|
systemStartupConnect: false,
|
||||||
// 取消了
|
systemSilentStartup: false,
|
||||||
return;
|
webEnable: true,
|
||||||
}
|
webPort: sourceConfig?.webServer?.port || 57400,
|
||||||
log.info(`导出目录 ${outputDirectory} 类型:${args}`);
|
transportProtocol: sourceConfig?.transport?.protocol || "tcp",
|
||||||
getConfig((err1, config) => {
|
transportDialServerTimeout:
|
||||||
if (!err1 && config) {
|
sourceConfig?.transport?.dialServerTimeout || 10,
|
||||||
listProxy((err2, proxys) => {
|
transportDialServerKeepalive:
|
||||||
if (!err2) {
|
sourceConfig?.transport?.dialServerKeepalive || 70,
|
||||||
let configContent = "";
|
transportPoolCount: sourceConfig?.transport?.poolCount || 0,
|
||||||
if (args === "ini") {
|
transportTcpMux: sourceConfig?.transport?.tcpMux || true,
|
||||||
configContent = genIniConfig(config, proxys);
|
transportTcpMuxKeepaliveInterval:
|
||||||
} else if (args === "toml") {
|
sourceConfig?.transport?.tcpMuxKeepaliveInterval || 7200
|
||||||
configContent = genTomlConfig(config, proxys);
|
|
||||||
}
|
|
||||||
const configPath = path.join(
|
|
||||||
outputDirectory,
|
|
||||||
`frpc-desktop.${args}`
|
|
||||||
);
|
|
||||||
fs.writeFile(
|
|
||||||
configPath, // 配置文件目录
|
|
||||||
configContent, // 配置文件内容
|
|
||||||
{flag: "w"},
|
|
||||||
err => {
|
|
||||||
if (!err) {
|
|
||||||
// callback(filename);
|
|
||||||
event.reply("config.exportConfig.hook", {
|
|
||||||
data: "导出错误",
|
|
||||||
err: err
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
event.reply("Config.exportConfig.hook", {
|
|
||||||
data: {
|
|
||||||
configPath: configPath
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
const parseTomlConfig = (tomlPath: string) => {
|
|
||||||
const importConfigPath = tomlPath;
|
|
||||||
const tomlData = fs.readFileSync(importConfigPath, "utf-8");
|
|
||||||
log.info(`读取到配置内容 ${tomlData}`);
|
|
||||||
const sourceConfig = toml.parse(tomlData);
|
|
||||||
// log.info(`解析结果 ${sourceConfig}`);
|
|
||||||
// console.log(sourceConfig, "frpcConfig");
|
|
||||||
// 解析config
|
|
||||||
const targetConfig: FrpConfig = {
|
|
||||||
currentVersion: null,
|
|
||||||
serverAddr: sourceConfig.serverAddr || "",
|
|
||||||
serverPort: sourceConfig.serverPort || "",
|
|
||||||
authMethod: sourceConfig?.user
|
|
||||||
? "multiuser"
|
|
||||||
: sourceConfig?.auth?.method || "",
|
|
||||||
authToken: sourceConfig?.auth?.token || "",
|
|
||||||
transportHeartbeatInterval:
|
|
||||||
sourceConfig?.transport?.heartbeatInterval || 30,
|
|
||||||
transportHeartbeatTimeout:
|
|
||||||
sourceConfig?.transport?.heartbeatTimeout || 90,
|
|
||||||
tlsConfigEnable: sourceConfig?.transport?.tls?.enable || false,
|
|
||||||
tlsConfigCertFile: sourceConfig?.transport?.tls?.certFile || "",
|
|
||||||
tlsConfigKeyFile: sourceConfig?.transport?.tls?.keyFile || "",
|
|
||||||
tlsConfigServerName: sourceConfig?.transport?.tls?.serverName || "",
|
|
||||||
tlsConfigTrustedCaFile: sourceConfig?.transport?.tls?.trustedCaFile || "",
|
|
||||||
logLevel: sourceConfig?.log?.level || "info",
|
|
||||||
logMaxDays: sourceConfig?.log?.maxDays || 3,
|
|
||||||
proxyConfigProxyUrl: sourceConfig?.transport?.proxyURL || "",
|
|
||||||
proxyConfigEnable: Boolean(sourceConfig?.transport?.proxyURL) || false,
|
|
||||||
user: sourceConfig?.user || "",
|
|
||||||
metaToken: sourceConfig?.metadatas?.token || "",
|
|
||||||
systemSelfStart: false,
|
|
||||||
systemStartupConnect: false,
|
|
||||||
systemSilentStartup: false,
|
|
||||||
webEnable: true,
|
|
||||||
webPort: sourceConfig?.webServer?.port || 57400
|
|
||||||
};
|
|
||||||
let frpcProxys = [];
|
|
||||||
// 解析proxy
|
|
||||||
if (sourceConfig?.proxies && sourceConfig.proxies.length > 0) {
|
|
||||||
const frpcProxys1 = sourceConfig.proxies.map(m => {
|
|
||||||
const rm: Proxy = {
|
|
||||||
_id: uuidv4(),
|
|
||||||
name: m?.name,
|
|
||||||
type: m?.type,
|
|
||||||
localIp: m?.localIP || "",
|
|
||||||
localPort: m?.localPort || null,
|
|
||||||
remotePort: m?.remotePort || null,
|
|
||||||
customDomains: m?.customDomains || [],
|
|
||||||
subdomain: m.subdomain || "",
|
|
||||||
basicAuth: m.basicAuth || false,
|
|
||||||
httpUser: m.httpUser || "",
|
|
||||||
httpPassword: m.httpPassword || "",
|
|
||||||
// 以下为stcp参数
|
|
||||||
stcpModel: "visited",
|
|
||||||
serverName: "",
|
|
||||||
secretKey: m?.secretKey || "",
|
|
||||||
bindAddr: "",
|
|
||||||
bindPort: null,
|
|
||||||
status: m?.status || true,
|
|
||||||
fallbackTo: m?.fallbackTo,
|
|
||||||
fallbackTimeoutMs: m?.fallbackTimeoutMs || 500
|
|
||||||
};
|
|
||||||
return rm;
|
|
||||||
});
|
|
||||||
frpcProxys = [...frpcProxys, ...frpcProxys1];
|
|
||||||
}
|
|
||||||
// 解析stcp的访问者
|
|
||||||
if (sourceConfig?.visitors && sourceConfig.visitors.length > 0) {
|
|
||||||
const frpcProxys2 = sourceConfig.visitors.map(m => {
|
|
||||||
const rm: Proxy = {
|
|
||||||
_id: uuidv4(),
|
|
||||||
name: m?.name,
|
|
||||||
type: m?.type,
|
|
||||||
localIp: "",
|
|
||||||
localPort: null,
|
|
||||||
remotePort: null,
|
|
||||||
customDomains: [],
|
|
||||||
subdomain: m.subdomain || "",
|
|
||||||
basicAuth: m.basicAuth || false,
|
|
||||||
httpUser: m.httpUser || "",
|
|
||||||
httpPassword: m.httpPassword || "",
|
|
||||||
// 以下为stcp参数
|
|
||||||
stcpModel: "visitors",
|
|
||||||
serverName: m?.serverName,
|
|
||||||
secretKey: m?.secretKey || "",
|
|
||||||
bindAddr: m?.bindAddr,
|
|
||||||
bindPort: m?.bindPort,
|
|
||||||
status: m?.status || true,
|
|
||||||
fallbackTo: m?.fallbackTo,
|
|
||||||
fallbackTimeoutMs: m?.fallbackTimeoutMs || 500
|
|
||||||
};
|
|
||||||
return rm;
|
|
||||||
});
|
|
||||||
frpcProxys = [...frpcProxys, ...frpcProxys2];
|
|
||||||
}
|
|
||||||
if (targetConfig) {
|
|
||||||
clearConfig(() => {
|
|
||||||
saveConfig(targetConfig);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
if (frpcProxys && frpcProxys.length > 0) {
|
|
||||||
clearProxy(() => {
|
|
||||||
frpcProxys.forEach(f => {
|
|
||||||
insertProxy(f, err => {
|
|
||||||
console.log("插入", f, err);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
let frpcProxys = [];
|
||||||
ipcMain.on("config.importConfig", async (event, args) => {
|
// 解析proxy
|
||||||
const result = await dialog.showOpenDialog(win, {
|
if (sourceConfig?.proxies && sourceConfig.proxies.length > 0) {
|
||||||
properties: ["openFile"],
|
const frpcProxys1 = sourceConfig.proxies.map(m => {
|
||||||
filters: [
|
const rm: Proxy = {
|
||||||
{name: "FrpcConfig Files", extensions: ["toml", "ini"]} // 允许选择的文件类型
|
_id: uuidv4(),
|
||||||
]
|
name: m?.name,
|
||||||
|
type: m?.type,
|
||||||
|
localIp: m?.localIP || "",
|
||||||
|
localPort: m?.localPort || null,
|
||||||
|
remotePort: m?.remotePort || null,
|
||||||
|
customDomains: m?.customDomains || [],
|
||||||
|
subdomain: m.subdomain || "",
|
||||||
|
basicAuth: m.basicAuth || false,
|
||||||
|
httpUser: m.httpUser || "",
|
||||||
|
httpPassword: m.httpPassword || "",
|
||||||
|
// 以下为stcp参数
|
||||||
|
stcpModel: "visited",
|
||||||
|
serverName: "",
|
||||||
|
secretKey: m?.secretKey || "",
|
||||||
|
bindAddr: "",
|
||||||
|
bindPort: null,
|
||||||
|
status: m?.status || true,
|
||||||
|
fallbackTo: m?.fallbackTo,
|
||||||
|
fallbackTimeoutMs: m?.fallbackTimeoutMs || 500
|
||||||
|
};
|
||||||
|
return rm;
|
||||||
|
});
|
||||||
|
frpcProxys = [...frpcProxys, ...frpcProxys1];
|
||||||
|
}
|
||||||
|
// 解析stcp的访问者
|
||||||
|
if (sourceConfig?.visitors && sourceConfig.visitors.length > 0) {
|
||||||
|
const frpcProxys2 = sourceConfig.visitors.map(m => {
|
||||||
|
const rm: Proxy = {
|
||||||
|
_id: uuidv4(),
|
||||||
|
name: m?.name,
|
||||||
|
type: m?.type,
|
||||||
|
localIp: "",
|
||||||
|
localPort: null,
|
||||||
|
remotePort: null,
|
||||||
|
customDomains: [],
|
||||||
|
subdomain: m.subdomain || "",
|
||||||
|
basicAuth: m.basicAuth || false,
|
||||||
|
httpUser: m.httpUser || "",
|
||||||
|
httpPassword: m.httpPassword || "",
|
||||||
|
// 以下为stcp参数
|
||||||
|
stcpModel: "visitors",
|
||||||
|
serverName: m?.serverName,
|
||||||
|
secretKey: m?.secretKey || "",
|
||||||
|
bindAddr: m?.bindAddr,
|
||||||
|
bindPort: m?.bindPort,
|
||||||
|
status: m?.status || true,
|
||||||
|
fallbackTo: m?.fallbackTo,
|
||||||
|
fallbackTimeoutMs: m?.fallbackTimeoutMs || 500
|
||||||
|
};
|
||||||
|
return rm;
|
||||||
|
});
|
||||||
|
frpcProxys = [...frpcProxys, ...frpcProxys2];
|
||||||
|
}
|
||||||
|
if (targetConfig) {
|
||||||
|
clearConfig(() => {
|
||||||
|
saveConfig(targetConfig);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (frpcProxys && frpcProxys.length > 0) {
|
||||||
|
clearProxy(() => {
|
||||||
|
frpcProxys.forEach(f => {
|
||||||
|
insertProxy(f, err => {
|
||||||
|
console.log("插入", f, err);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
if (result.canceled) {
|
});
|
||||||
return;
|
}
|
||||||
} else {
|
};
|
||||||
const filePath = result.filePaths[0];
|
|
||||||
const fileExtension = path.extname(filePath); // 获取文件后缀名
|
|
||||||
log.info(`导入文件 ${filePath} ${fileExtension}`);
|
|
||||||
if (fileExtension === ".toml") {
|
|
||||||
parseTomlConfig(filePath);
|
|
||||||
event.reply("Config.importConfig.hook", {
|
|
||||||
success: true
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
event.reply("Config.importConfig.hook", {
|
|
||||||
success: false,
|
|
||||||
data: `导入失败,暂不支持 ${fileExtension} 格式文件`
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
ipcMain.on("config.clearAll", async (event, args) => {
|
ipcMain.on("config.importConfig", async (event, args) => {
|
||||||
stopFrpcProcess(() => {
|
const result = await dialog.showOpenDialog(win, {
|
||||||
clearConfig();
|
properties: ["openFile"],
|
||||||
clearProxy();
|
filters: [
|
||||||
clearVersion();
|
{ name: "FrpcConfig Files", extensions: ["toml", "ini"] } // 允许选择的文件类型
|
||||||
event.reply("Config.clearAll.hook", {});
|
]
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
if (result.canceled) {
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
const filePath = result.filePaths[0];
|
||||||
|
const fileExtension = path.extname(filePath); // 获取文件后缀名
|
||||||
|
log.info(`导入文件 ${filePath} ${fileExtension}`);
|
||||||
|
if (fileExtension === ".toml") {
|
||||||
|
parseTomlConfig(filePath);
|
||||||
|
event.reply("Config.importConfig.hook", {
|
||||||
|
success: true
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
event.reply("Config.importConfig.hook", {
|
||||||
|
success: false,
|
||||||
|
data: `导入失败,暂不支持 ${fileExtension} 格式文件`
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
ipcMain.on("config.openDataFolder", async (event, args) => {
|
ipcMain.on("config.clearAll", async (event, args) => {
|
||||||
const userDataPath = app.getPath("userData");
|
stopFrpcProcess(() => {
|
||||||
shell.openPath(userDataPath).then((errorMessage) => {
|
clearConfig();
|
||||||
if (errorMessage) {
|
clearProxy();
|
||||||
console.error('Failed to open Logger:', errorMessage);
|
clearVersion();
|
||||||
event.reply("Config.openDataFolder.hook", false);
|
event.reply("Config.clearAll.hook", {});
|
||||||
} else {
|
|
||||||
console.log('Logger opened successfully');
|
|
||||||
event.reply("Config.openDataFolder.hook", true);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
ipcMain.on("config.openDataFolder", async (event, args) => {
|
||||||
|
const userDataPath = app.getPath("userData");
|
||||||
|
shell.openPath(userDataPath).then(errorMessage => {
|
||||||
|
if (errorMessage) {
|
||||||
|
console.error("Failed to open Logger:", errorMessage);
|
||||||
|
event.reply("Config.openDataFolder.hook", false);
|
||||||
|
} else {
|
||||||
|
console.log("Logger opened successfully");
|
||||||
|
event.reply("Config.openDataFolder.hook", true);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
@ -55,8 +55,7 @@ export const genTomlConfig = (config: FrpConfig, proxys: Proxy[]) => {
|
|||||||
/\\/g,
|
/\\/g,
|
||||||
"\\\\"
|
"\\\\"
|
||||||
);
|
);
|
||||||
let toml = `
|
let toml = `${
|
||||||
${
|
|
||||||
rangePort
|
rangePort
|
||||||
? `{{- range $_, $v := parseNumberRangePair "${m.localPort}" "${m.remotePort}" }}`
|
? `{{- range $_, $v := parseNumberRangePair "${m.localPort}" "${m.remotePort}" }}`
|
||||||
: ""
|
: ""
|
||||||
@ -67,7 +66,7 @@ ${
|
|||||||
? "visitors"
|
? "visitors"
|
||||||
: "proxies"
|
: "proxies"
|
||||||
}]]
|
}]]
|
||||||
${rangePort ? "" : `name = "${m.name}"\n`}
|
${rangePort ? "" : `name = "${m.name}"`}
|
||||||
type = "${m.type}"
|
type = "${m.type}"
|
||||||
`;
|
`;
|
||||||
|
|
||||||
@ -75,52 +74,38 @@ type = "${m.type}"
|
|||||||
case "tcp":
|
case "tcp":
|
||||||
case "udp":
|
case "udp":
|
||||||
if (rangePort) {
|
if (rangePort) {
|
||||||
toml += `
|
toml += `name = "${m.name}-{{ $v.First }}"
|
||||||
name = "${m.name}-{{ $v.First }}"
|
|
||||||
localPort = {{ $v.First }}
|
localPort = {{ $v.First }}
|
||||||
remotePort = {{ $v.Second }}
|
remotePort = {{ $v.Second }}`;
|
||||||
`;
|
|
||||||
} else {
|
} else {
|
||||||
toml += `
|
toml += `localIP = "${m.localIp}"
|
||||||
localIP = "${m.localIp}"
|
|
||||||
localPort = ${m.localPort}
|
localPort = ${m.localPort}
|
||||||
remotePort = ${m.remotePort}
|
remotePort = ${m.remotePort}`;
|
||||||
`;
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case "http":
|
case "http":
|
||||||
case "https":
|
case "https":
|
||||||
const customDomains = m.customDomains.filter(f1 => f1 !== "");
|
const customDomains = m.customDomains.filter(f1 => f1 !== "");
|
||||||
if (customDomains && customDomains.length > 0) {
|
if (customDomains && customDomains.length > 0) {
|
||||||
toml += `
|
toml += `customDomains=[${m.customDomains.map(m => `"${m}"`)}]`;
|
||||||
customDomains=[${m.customDomains.map(m => `"${m}"`)}]
|
|
||||||
`;
|
|
||||||
}
|
}
|
||||||
if (m.subdomain) {
|
if (m.subdomain) {
|
||||||
toml += `
|
toml += `subdomain="${m.subdomain}"`;
|
||||||
subdomain="${m.subdomain}"
|
|
||||||
`;
|
|
||||||
}
|
}
|
||||||
if (m.basicAuth) {
|
if (m.basicAuth) {
|
||||||
toml += `
|
toml += `httpUser = "${m.httpUser}"
|
||||||
httpUser = "${m.httpUser}"
|
httpPassword = "${m.httpPassword}"`;
|
||||||
httpPassword = "${m.httpPassword}"
|
|
||||||
`;
|
|
||||||
}
|
}
|
||||||
if (m.https2http) {
|
if (m.https2http) {
|
||||||
toml += `
|
toml += `[proxies.plugin]
|
||||||
[proxies.plugin]
|
|
||||||
type = "https2http"
|
type = "https2http"
|
||||||
localAddr = "${m.localIp}:${m.localPort}"
|
localAddr = "${m.localIp}:${m.localPort}"
|
||||||
|
|
||||||
crtPath = "${m.https2httpCaFile}"
|
crtPath = "${m.https2httpCaFile}"
|
||||||
keyPath = "${m.https2httpKeyFile}"
|
keyPath = "${m.https2httpKeyFile}"`;
|
||||||
`;
|
|
||||||
} else {
|
} else {
|
||||||
toml += `
|
toml += `localIP = "${m.localIp}"
|
||||||
localIP = "${m.localIp}"
|
localPort = ${m.localPort}`;
|
||||||
localPort = ${m.localPort}
|
|
||||||
`;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
@ -129,25 +114,19 @@ localPort = ${m.localPort}
|
|||||||
case "sudp":
|
case "sudp":
|
||||||
if (m.stcpModel === "visitors") {
|
if (m.stcpModel === "visitors") {
|
||||||
// 访问者
|
// 访问者
|
||||||
toml += `
|
toml += `serverName = "${m.serverName}"
|
||||||
serverName = "${m.serverName}"
|
|
||||||
bindAddr = "${m.bindAddr}"
|
bindAddr = "${m.bindAddr}"
|
||||||
bindPort = ${m.bindPort}
|
bindPort = ${m.bindPort}`;
|
||||||
`;
|
|
||||||
if (m.fallbackTo) {
|
if (m.fallbackTo) {
|
||||||
toml += `
|
toml += `fallbackTo = "${m.fallbackTo}"
|
||||||
fallbackTo = "${m.fallbackTo}"
|
fallbackTimeoutMs = ${m.fallbackTimeoutMs || 500}`;
|
||||||
fallbackTimeoutMs = ${m.fallbackTimeoutMs || 500}
|
|
||||||
`;
|
|
||||||
}
|
}
|
||||||
} else if (m.stcpModel === "visited") {
|
} else if (m.stcpModel === "visited") {
|
||||||
// 被访问者
|
// 被访问者
|
||||||
toml += `
|
toml += `localIP = "${m.localIp}"
|
||||||
localIP = "${m.localIp}"
|
|
||||||
localPort = ${m.localPort}`;
|
localPort = ${m.localPort}`;
|
||||||
}
|
}
|
||||||
toml += `
|
toml += `secretKey="${m.secretKey}"
|
||||||
secretKey="${m.secretKey}"
|
|
||||||
`;
|
`;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@ -159,87 +138,88 @@ secretKey="${m.secretKey}"
|
|||||||
}
|
}
|
||||||
return toml;
|
return toml;
|
||||||
});
|
});
|
||||||
const toml = `
|
const toml = `serverAddr = "${config.serverAddr}"
|
||||||
serverAddr = "${config.serverAddr}"
|
|
||||||
serverPort = ${config.serverPort}
|
serverPort = ${config.serverPort}
|
||||||
${
|
${
|
||||||
config.authMethod === "token"
|
config.authMethod === "token"
|
||||||
? `
|
? `auth.method = "token"
|
||||||
auth.method = "token"
|
auth.token = "${config.authToken}"`
|
||||||
auth.token = "${config.authToken}"
|
|
||||||
`
|
|
||||||
: ""
|
: ""
|
||||||
}
|
}
|
||||||
${
|
${
|
||||||
config.authMethod === "multiuser"
|
config.authMethod === "multiuser"
|
||||||
? `
|
? `user = "${config.user}"
|
||||||
user = "${config.user}"
|
metadatas.token = "${config.metaToken}"`
|
||||||
metadatas.token = "${config.metaToken}"
|
|
||||||
`
|
|
||||||
: ""
|
: ""
|
||||||
}
|
}
|
||||||
${
|
|
||||||
config.transportHeartbeatInterval
|
|
||||||
? `
|
|
||||||
transport.heartbeatInterval = ${config.transportHeartbeatInterval}
|
|
||||||
`
|
|
||||||
: ""
|
|
||||||
}
|
|
||||||
${
|
|
||||||
config.transportHeartbeatTimeout
|
|
||||||
? `
|
|
||||||
transport.heartbeatTimeout = ${config.transportHeartbeatTimeout}
|
|
||||||
`
|
|
||||||
: ""
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
log.to = "frpc.log"
|
log.to = "frpc.log"
|
||||||
log.level = "${config.logLevel}"
|
log.level = "${config.logLevel}"
|
||||||
log.maxDays = ${config.logMaxDays}
|
log.maxDays = ${config.logMaxDays}
|
||||||
webServer.addr = "127.0.0.1"
|
webServer.addr = "127.0.0.1"
|
||||||
webServer.port = ${config.webPort}
|
webServer.port = ${config.webPort}
|
||||||
|
${
|
||||||
|
config.transportProtocol
|
||||||
|
? `transport.protocol = "${config.transportProtocol}"`
|
||||||
|
: ""
|
||||||
|
}
|
||||||
|
${
|
||||||
|
config.transportPoolCount
|
||||||
|
? `transport.poolCount = ${config.transportPoolCount}`
|
||||||
|
: ""
|
||||||
|
}
|
||||||
|
${
|
||||||
|
config.transportDialServerTimeout
|
||||||
|
? `transport.dialServerTimeout = ${config.transportDialServerTimeout}`
|
||||||
|
: ""
|
||||||
|
}
|
||||||
|
${
|
||||||
|
config.transportDialServerKeepalive
|
||||||
|
? `transport.dialServerKeepalive = ${config.transportDialServerKeepalive}`
|
||||||
|
: ""
|
||||||
|
}
|
||||||
|
${
|
||||||
|
config.transportHeartbeatInterval
|
||||||
|
? `transport.heartbeatInterval = ${config.transportHeartbeatInterval}`
|
||||||
|
: ""
|
||||||
|
}
|
||||||
|
${
|
||||||
|
config.transportHeartbeatTimeout
|
||||||
|
? `transport.heartbeatTimeout = ${config.transportHeartbeatTimeout}`
|
||||||
|
: ""
|
||||||
|
}
|
||||||
|
${config.transportTcpMux ? `transport.tcpMux = ${config.transportTcpMux}` : ""}
|
||||||
|
${
|
||||||
|
config.transportTcpMux && config.transportTcpMuxKeepaliveInterval
|
||||||
|
? `transport.tcpMuxKeepaliveInterval = ${config.transportTcpMuxKeepaliveInterval}`
|
||||||
|
: ""
|
||||||
|
}
|
||||||
transport.tls.enable = ${config.tlsConfigEnable}
|
transport.tls.enable = ${config.tlsConfigEnable}
|
||||||
${
|
${
|
||||||
config.tlsConfigEnable && config.tlsConfigCertFile
|
config.tlsConfigEnable && config.tlsConfigCertFile
|
||||||
? `
|
? `transport.tls.certFile = "${config.tlsConfigCertFile}"`
|
||||||
transport.tls.certFile = "${config.tlsConfigCertFile}"
|
|
||||||
`
|
|
||||||
: ""
|
: ""
|
||||||
}
|
}
|
||||||
${
|
${
|
||||||
config.tlsConfigEnable && config.tlsConfigKeyFile
|
config.tlsConfigEnable && config.tlsConfigKeyFile
|
||||||
? `
|
? `transport.tls.keyFile = "${config.tlsConfigKeyFile}"`
|
||||||
transport.tls.keyFile = "${config.tlsConfigKeyFile}"
|
|
||||||
`
|
|
||||||
: ""
|
: ""
|
||||||
}
|
}
|
||||||
${
|
${
|
||||||
config.tlsConfigEnable && config.tlsConfigTrustedCaFile
|
config.tlsConfigEnable && config.tlsConfigTrustedCaFile
|
||||||
? `
|
? `transport.tls.trustedCaFile = "${config.tlsConfigTrustedCaFile}"`
|
||||||
transport.tls.trustedCaFile = "${config.tlsConfigTrustedCaFile}"
|
|
||||||
`
|
|
||||||
: ""
|
: ""
|
||||||
}
|
}
|
||||||
${
|
${
|
||||||
config.tlsConfigEnable && config.tlsConfigServerName
|
config.tlsConfigEnable && config.tlsConfigServerName
|
||||||
? `
|
? `transport.tls.serverName = "${config.tlsConfigServerName}"`
|
||||||
transport.tls.serverName = "${config.tlsConfigServerName}"
|
|
||||||
`
|
|
||||||
: ""
|
: ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
${
|
${
|
||||||
config.proxyConfigEnable
|
config.proxyConfigEnable
|
||||||
? `
|
? `transport.proxyURL = "${config.proxyConfigProxyUrl}"`
|
||||||
transport.proxyURL = "${config.proxyConfigProxyUrl}"
|
|
||||||
`
|
|
||||||
: ""
|
: ""
|
||||||
}
|
}
|
||||||
|
${proxyToml.join("")}`;
|
||||||
${proxyToml.join("")}
|
|
||||||
`;
|
|
||||||
return toml;
|
return toml;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -251,8 +231,7 @@ ${proxyToml.join("")}
|
|||||||
export const genIniConfig = (config: FrpConfig, proxys: Proxy[]) => {
|
export const genIniConfig = (config: FrpConfig, proxys: Proxy[]) => {
|
||||||
const proxyIni = proxys.map(m => {
|
const proxyIni = proxys.map(m => {
|
||||||
const rangePort = isRangePort(m);
|
const rangePort = isRangePort(m);
|
||||||
let ini = `
|
let ini = `[${rangePort ? "range:" : ""}${m.name}]
|
||||||
[${rangePort ? "range:" : ""}${m.name}]
|
|
||||||
type = "${m.type}"
|
type = "${m.type}"
|
||||||
`;
|
`;
|
||||||
switch (m.type) {
|
switch (m.type) {
|
||||||
|
@ -47,7 +47,13 @@ const defaultFormData = ref<FrpConfig>({
|
|||||||
transportHeartbeatInterval: 30,
|
transportHeartbeatInterval: 30,
|
||||||
transportHeartbeatTimeout: 90,
|
transportHeartbeatTimeout: 90,
|
||||||
webEnable: true,
|
webEnable: true,
|
||||||
webPort: 57400
|
webPort: 57400,
|
||||||
|
transportProtocol: "tcp",
|
||||||
|
transportDialServerTimeout: 10,
|
||||||
|
transportDialServerKeepalive: 7200,
|
||||||
|
transportPoolCount: 0,
|
||||||
|
transportTcpMux: true,
|
||||||
|
transportTcpMuxKeepaliveInterval: 30
|
||||||
});
|
});
|
||||||
|
|
||||||
const formData = ref<FrpConfig>(defaultFormData.value);
|
const formData = ref<FrpConfig>(defaultFormData.value);
|
||||||
@ -121,6 +127,24 @@ const rules = reactive<FormRules>({
|
|||||||
],
|
],
|
||||||
webPort: [
|
webPort: [
|
||||||
{ required: true, message: "web界面端口不能为空", trigger: "change" }
|
{ required: true, message: "web界面端口不能为空", trigger: "change" }
|
||||||
|
],
|
||||||
|
transportProtocol: [
|
||||||
|
{ required: true, message: "web界面端口不能为空", trigger: "change" }
|
||||||
|
],
|
||||||
|
transportDialServerTimeout: [
|
||||||
|
{ required: true, message: "web界面端口不能为空", trigger: "change" }
|
||||||
|
],
|
||||||
|
transportDialServerKeepalive: [
|
||||||
|
{ required: true, message: "web界面端口不能为空", trigger: "change" }
|
||||||
|
],
|
||||||
|
transportPoolCount: [
|
||||||
|
{ required: true, message: "web界面端口不能为空", trigger: "change" }
|
||||||
|
],
|
||||||
|
transportTcpMux: [
|
||||||
|
{ required: true, message: "web界面端口不能为空", trigger: "change" }
|
||||||
|
],
|
||||||
|
transportTcpMuxKeepaliveInterval: [
|
||||||
|
{ required: true, message: "web界面端口不能为空", trigger: "change" }
|
||||||
]
|
]
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -196,9 +220,49 @@ onMounted(() => {
|
|||||||
defaultFormData.value.transportHeartbeatTimeout;
|
defaultFormData.value.transportHeartbeatTimeout;
|
||||||
}
|
}
|
||||||
if (data.webEnable == null || data.webEnable == undefined) {
|
if (data.webEnable == null || data.webEnable == undefined) {
|
||||||
data.webEnable = true;
|
data.webEnable = defaultFormData.value.webEnable;
|
||||||
data.webPort = 57400;
|
data.webPort = defaultFormData.value.webPort;
|
||||||
}
|
}
|
||||||
|
if (
|
||||||
|
data.transportProtocol === undefined ||
|
||||||
|
data.transportProtocol == null
|
||||||
|
) {
|
||||||
|
data.transportProtocol = defaultFormData.value.transportProtocol;
|
||||||
|
}
|
||||||
|
if (
|
||||||
|
data.transportDialServerTimeout === undefined ||
|
||||||
|
data.transportDialServerTimeout == null
|
||||||
|
) {
|
||||||
|
data.transportDialServerTimeout =
|
||||||
|
defaultFormData.value.transportDialServerTimeout;
|
||||||
|
}
|
||||||
|
if (
|
||||||
|
data.transportDialServerKeepalive === undefined ||
|
||||||
|
data.transportDialServerKeepalive == null
|
||||||
|
) {
|
||||||
|
data.transportDialServerKeepalive =
|
||||||
|
defaultFormData.value.transportDialServerKeepalive;
|
||||||
|
}
|
||||||
|
if (
|
||||||
|
data.transportPoolCount === undefined ||
|
||||||
|
data.transportPoolCount == null
|
||||||
|
) {
|
||||||
|
data.transportPoolCount = defaultFormData.value.transportPoolCount;
|
||||||
|
}
|
||||||
|
if (
|
||||||
|
data.transportTcpMux === undefined ||
|
||||||
|
data.transportTcpMux == null
|
||||||
|
) {
|
||||||
|
data.transportTcpMux = defaultFormData.value.transportTcpMux;
|
||||||
|
}
|
||||||
|
if (
|
||||||
|
data.transportTcpMuxKeepaliveInterval === undefined ||
|
||||||
|
data.transportTcpMuxKeepaliveInterval == null
|
||||||
|
) {
|
||||||
|
data.transportTcpMuxKeepaliveInterval =
|
||||||
|
defaultFormData.value.transportTcpMuxKeepaliveInterval;
|
||||||
|
}
|
||||||
|
|
||||||
formData.value = data;
|
formData.value = data;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -422,7 +486,7 @@ onUnmounted(() => {
|
|||||||
:rules="rules"
|
:rules="rules"
|
||||||
label-position="right"
|
label-position="right"
|
||||||
ref="formRef"
|
ref="formRef"
|
||||||
label-width="130"
|
label-width="150"
|
||||||
>
|
>
|
||||||
<el-row :gutter="10">
|
<el-row :gutter="10">
|
||||||
<el-col :span="24">
|
<el-col :span="24">
|
||||||
@ -632,6 +696,72 @@ onUnmounted(() => {
|
|||||||
/>
|
/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
|
<!-- <el-col :span="24">
|
||||||
|
<div class="h2">TLS Config</div>
|
||||||
|
</el-col> -->
|
||||||
|
|
||||||
|
<el-col :span="24">
|
||||||
|
<div class="h2">传输配置</div>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="传输协议:" prop="transportProtocol">
|
||||||
|
<template #label>
|
||||||
|
<div class="h-full flex items-center mr-1">
|
||||||
|
<el-popover width="300" placement="top" trigger="hover">
|
||||||
|
<template #default>
|
||||||
|
和 frps 之间的通信协议。默认为 tcp。<br />
|
||||||
|
对应参数:<span class="font-black text-[#5A3DAA]"
|
||||||
|
>transport.protocol</span
|
||||||
|
>
|
||||||
|
</template>
|
||||||
|
<template #reference>
|
||||||
|
<IconifyIconOffline
|
||||||
|
class="text-base"
|
||||||
|
color="#5A3DAA"
|
||||||
|
icon="info"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
</el-popover>
|
||||||
|
</div>
|
||||||
|
传输协议:
|
||||||
|
</template>
|
||||||
|
<el-select v-model="formData.transportProtocol">
|
||||||
|
<el-option label="tcp" value="tcp" />
|
||||||
|
<el-option label="kcp" value="kcp" />
|
||||||
|
<el-option label="quic" value="quic" />
|
||||||
|
<el-option label="websocket" value="websocket" />
|
||||||
|
<el-option label="wss" value="wss" />
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="连接池大小:" prop="transportPoolCount">
|
||||||
|
<template #label>
|
||||||
|
<div class="h-full flex items-center mr-1">
|
||||||
|
<el-popover width="300" placement="top" trigger="hover">
|
||||||
|
<template #default>
|
||||||
|
对应参数:<span class="font-black text-[#5A3DAA]"
|
||||||
|
>transport.poolCount</span
|
||||||
|
>
|
||||||
|
</template>
|
||||||
|
<template #reference>
|
||||||
|
<IconifyIconOffline
|
||||||
|
class="text-base"
|
||||||
|
color="#5A3DAA"
|
||||||
|
icon="info"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
</el-popover>
|
||||||
|
</div>
|
||||||
|
连接池大小:
|
||||||
|
</template>
|
||||||
|
<el-input-number
|
||||||
|
class="w-full"
|
||||||
|
v-model="formData.transportPoolCount"
|
||||||
|
controls-position="right"
|
||||||
|
></el-input-number>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
<el-col :span="12">
|
<el-col :span="12">
|
||||||
<el-form-item
|
<el-form-item
|
||||||
label="心跳间隔:"
|
label="心跳间隔:"
|
||||||
@ -715,9 +845,176 @@ onUnmounted(() => {
|
|||||||
<!-- </el-input>-->
|
<!-- </el-input>-->
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="24">
|
<el-col :span="12">
|
||||||
<div class="h2">TLS Config</div>
|
<el-form-item
|
||||||
|
label="连接超时:"
|
||||||
|
prop="transportDialServerTimeout"
|
||||||
|
>
|
||||||
|
<template #label>
|
||||||
|
<div class="h-full flex items-center mr-1">
|
||||||
|
<el-popover width="300" placement="top" trigger="hover">
|
||||||
|
<template #default>
|
||||||
|
与服务器建立连接的最长等待时间。默认值为10秒。单位:
|
||||||
|
<span class="font-black text-[#5A3DAA]">秒</span> <br />
|
||||||
|
对应参数:<span class="font-black text-[#5A3DAA]"
|
||||||
|
>transport.dialServerTimeout</span
|
||||||
|
>
|
||||||
|
</template>
|
||||||
|
<template #reference>
|
||||||
|
<IconifyIconOffline
|
||||||
|
class="text-base"
|
||||||
|
color="#5A3DAA"
|
||||||
|
icon="info"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
</el-popover>
|
||||||
|
</div>
|
||||||
|
连接超时:
|
||||||
|
</template>
|
||||||
|
<el-input-number
|
||||||
|
class="w-full"
|
||||||
|
v-model="formData.transportDialServerTimeout"
|
||||||
|
controls-position="right"
|
||||||
|
></el-input-number>
|
||||||
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item
|
||||||
|
label="保活探测间隔:"
|
||||||
|
prop="transportDialServerKeepalive"
|
||||||
|
>
|
||||||
|
<template #label>
|
||||||
|
<div class="h-full flex items-center mr-1">
|
||||||
|
<el-popover width="300" placement="top" trigger="hover">
|
||||||
|
<template #default>
|
||||||
|
客户端与服务端之间的连接在一定时间内没有任何数据传输,系统会定期发送一些心跳数据包来保持连接的活跃状态。如果为负,则禁用保活探测。
|
||||||
|
单位:
|
||||||
|
<span class="font-black text-[#5A3DAA]">秒</span> <br />
|
||||||
|
对应参数:<span class="font-black text-[#5A3DAA]"
|
||||||
|
>transport.dialServerKeepalive</span
|
||||||
|
>
|
||||||
|
</template>
|
||||||
|
<template #reference>
|
||||||
|
<IconifyIconOffline
|
||||||
|
class="text-base"
|
||||||
|
color="#5A3DAA"
|
||||||
|
icon="info"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
</el-popover>
|
||||||
|
</div>
|
||||||
|
保活探测间隔:
|
||||||
|
</template>
|
||||||
|
<el-input-number
|
||||||
|
class="w-full"
|
||||||
|
v-model="formData.transportDialServerKeepalive"
|
||||||
|
controls-position="right"
|
||||||
|
></el-input-number>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="多路复用:" prop="transportTcpMux">
|
||||||
|
<template #label>
|
||||||
|
<div class="h-full flex items-center mr-1">
|
||||||
|
<el-popover width="300" placement="top" trigger="hover">
|
||||||
|
<template #default>
|
||||||
|
TCP 多路复用,默认启用。<br />
|
||||||
|
对应参数:<span class="font-black text-[#5A3DAA]"
|
||||||
|
>transport.tcpMux</span
|
||||||
|
>
|
||||||
|
</template>
|
||||||
|
<template #reference>
|
||||||
|
<IconifyIconOffline
|
||||||
|
class="text-base"
|
||||||
|
color="#5A3DAA"
|
||||||
|
icon="info"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
</el-popover>
|
||||||
|
</div>
|
||||||
|
TCP 多路复用:
|
||||||
|
</template>
|
||||||
|
<el-switch
|
||||||
|
active-text="开"
|
||||||
|
inline-prompt
|
||||||
|
inactive-text="关"
|
||||||
|
v-model="formData.transportTcpMux"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="12" v-if="formData.transportTcpMux">
|
||||||
|
<el-form-item
|
||||||
|
label="多复心跳间隔:"
|
||||||
|
prop="transportTcpMuxKeepaliveInterval"
|
||||||
|
>
|
||||||
|
<template #label>
|
||||||
|
<div class="h-full flex items-center mr-1">
|
||||||
|
<el-popover width="300" placement="top" trigger="hover">
|
||||||
|
<template #default>
|
||||||
|
多路复用的保活间隔,默认值为 30 秒。单位:
|
||||||
|
<span class="font-black text-[#5A3DAA]">秒</span> <br />
|
||||||
|
对应参数:<span class="font-black text-[#5A3DAA]"
|
||||||
|
>transport.tcpMuxKeepaliveInterval</span
|
||||||
|
>
|
||||||
|
</template>
|
||||||
|
<template #reference>
|
||||||
|
<IconifyIconOffline
|
||||||
|
class="text-base"
|
||||||
|
color="#5A3DAA"
|
||||||
|
icon="info"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
</el-popover>
|
||||||
|
</div>
|
||||||
|
多复心跳间隔:
|
||||||
|
</template>
|
||||||
|
<el-input-number
|
||||||
|
class="w-full"
|
||||||
|
v-model="formData.transportTcpMuxKeepaliveInterval"
|
||||||
|
controls-position="right"
|
||||||
|
></el-input-number>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="24">
|
||||||
|
<el-form-item label="启用代理:" prop="proxyConfigEnable">
|
||||||
|
<el-switch
|
||||||
|
active-text="开"
|
||||||
|
inline-prompt
|
||||||
|
inactive-text="关"
|
||||||
|
v-model="formData.proxyConfigEnable"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<template v-if="formData.proxyConfigEnable">
|
||||||
|
<el-col :span="24">
|
||||||
|
<el-form-item label="代理地址:" prop="proxyConfigProxyUrl">
|
||||||
|
<template #label>
|
||||||
|
<div class="h-full flex items-center mr-1">
|
||||||
|
<el-popover width="300" placement="top" trigger="hover">
|
||||||
|
<template #default>
|
||||||
|
对应参数:<span class="font-black text-[#5A3DAA]"
|
||||||
|
>transport.proxyURL</span
|
||||||
|
>
|
||||||
|
</template>
|
||||||
|
<template #reference>
|
||||||
|
<IconifyIconOffline
|
||||||
|
class="text-base"
|
||||||
|
color="#5A3DAA"
|
||||||
|
icon="info"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
</el-popover>
|
||||||
|
</div>
|
||||||
|
代理地址:
|
||||||
|
</template>
|
||||||
|
<el-input
|
||||||
|
v-model="formData.proxyConfigProxyUrl"
|
||||||
|
placeholder="http://user:pwd@192.168.1.128:8080"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
</template>
|
||||||
<el-col :span="24">
|
<el-col :span="24">
|
||||||
<el-form-item label="启用TLS:" prop="tlsConfigEnable">
|
<el-form-item label="启用TLS:" prop="tlsConfigEnable">
|
||||||
<el-switch
|
<el-switch
|
||||||
@ -904,48 +1201,6 @@ onUnmounted(() => {
|
|||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
</template>
|
</template>
|
||||||
<el-col :span="24">
|
|
||||||
<div class="h2">代理</div>
|
|
||||||
</el-col>
|
|
||||||
<el-col :span="24">
|
|
||||||
<el-form-item label="启用代理:" prop="proxyConfigEnable">
|
|
||||||
<el-switch
|
|
||||||
active-text="开"
|
|
||||||
inline-prompt
|
|
||||||
inactive-text="关"
|
|
||||||
v-model="formData.proxyConfigEnable"
|
|
||||||
/>
|
|
||||||
</el-form-item>
|
|
||||||
</el-col>
|
|
||||||
<template v-if="formData.proxyConfigEnable">
|
|
||||||
<el-col :span="24">
|
|
||||||
<el-form-item label="代理地址:" prop="proxyConfigProxyUrl">
|
|
||||||
<template #label>
|
|
||||||
<div class="h-full flex items-center mr-1">
|
|
||||||
<el-popover width="300" placement="top" trigger="hover">
|
|
||||||
<template #default>
|
|
||||||
对应参数:<span class="font-black text-[#5A3DAA]"
|
|
||||||
>transport.proxyURL</span
|
|
||||||
>
|
|
||||||
</template>
|
|
||||||
<template #reference>
|
|
||||||
<IconifyIconOffline
|
|
||||||
class="text-base"
|
|
||||||
color="#5A3DAA"
|
|
||||||
icon="info"
|
|
||||||
/>
|
|
||||||
</template>
|
|
||||||
</el-popover>
|
|
||||||
</div>
|
|
||||||
代理地址:
|
|
||||||
</template>
|
|
||||||
<el-input
|
|
||||||
v-model="formData.proxyConfigProxyUrl"
|
|
||||||
placeholder="http://user:pwd@192.168.1.128:8080"
|
|
||||||
/>
|
|
||||||
</el-form-item>
|
|
||||||
</el-col>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<el-col :span="24">
|
<el-col :span="24">
|
||||||
<div class="h2">Web 界面</div>
|
<div class="h2">Web 界面</div>
|
||||||
@ -963,9 +1218,10 @@ onUnmounted(() => {
|
|||||||
icon="info"
|
icon="info"
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
热更新等功能依赖于web界面,<span class="font-black text-[#5A3DAA]"
|
热更新等功能依赖于web界面,<span
|
||||||
>不可停用Web</span
|
class="font-black text-[#5A3DAA]"
|
||||||
>
|
>不可停用Web</span
|
||||||
|
>
|
||||||
</el-popover>
|
</el-popover>
|
||||||
</div>
|
</div>
|
||||||
启用Web:
|
启用Web:
|
||||||
@ -989,7 +1245,7 @@ onUnmounted(() => {
|
|||||||
<template #default>
|
<template #default>
|
||||||
对应参数:<span class="font-black text-[#5A3DAA]"
|
对应参数:<span class="font-black text-[#5A3DAA]"
|
||||||
>webServer.port</span
|
>webServer.port</span
|
||||||
><br/>
|
><br />
|
||||||
自行保证端口没有被占用,否则会导致启动失败
|
自行保证端口没有被占用,否则会导致启动失败
|
||||||
</template>
|
</template>
|
||||||
<template #reference>
|
<template #reference>
|
||||||
@ -1009,6 +1265,7 @@ onUnmounted(() => {
|
|||||||
:min="0"
|
:min="0"
|
||||||
:max="65535"
|
:max="65535"
|
||||||
controls-position="right"
|
controls-position="right"
|
||||||
|
class="w-full"
|
||||||
></el-input-number>
|
></el-input-number>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
|
6
types/global.d.ts
vendored
6
types/global.d.ts
vendored
@ -88,6 +88,12 @@ declare global {
|
|||||||
transportHeartbeatTimeout: number;
|
transportHeartbeatTimeout: number;
|
||||||
webEnable: boolean;
|
webEnable: boolean;
|
||||||
webPort: number;
|
webPort: number;
|
||||||
|
transportProtocol: string;
|
||||||
|
transportDialServerTimeout: number;
|
||||||
|
transportDialServerKeepalive: number;
|
||||||
|
transportPoolCount: number;
|
||||||
|
transportTcpMux: boolean;
|
||||||
|
transportTcpMuxKeepaliveInterval: number;
|
||||||
};
|
};
|
||||||
|
|
||||||
type GitHubMirror = {
|
type GitHubMirror = {
|
||||||
|
Loading…
Reference in New Issue
Block a user