✨ 支持toml配置文件的stcp
This commit is contained in:
parent
3961475421
commit
1d9ac090f3
@ -1,17 +1,17 @@
|
||||
import {app, ipcMain, Notification} from "electron";
|
||||
import {Config, getConfig} from "../storage/config";
|
||||
import {listProxy, Proxy} from "../storage/proxy";
|
||||
import {getVersionById} from "../storage/version";
|
||||
import { app, ipcMain, Notification } from "electron";
|
||||
import { getConfig } from "../storage/config";
|
||||
import { listProxy } from "../storage/proxy";
|
||||
import { getVersionById } from "../storage/version";
|
||||
import treeKill from "tree-kill";
|
||||
|
||||
const fs = require("fs");
|
||||
const path = require("path");
|
||||
const {exec, spawn} = require("child_process");
|
||||
const log = require('electron-log');
|
||||
const { exec, spawn } = require("child_process");
|
||||
const log = require("electron-log");
|
||||
export let frpcProcess = null;
|
||||
const runningCmd = {
|
||||
commandPath: null,
|
||||
configPath: null
|
||||
commandPath: null,
|
||||
configPath: null
|
||||
};
|
||||
let frpcStatusListener = null;
|
||||
|
||||
@ -21,16 +21,16 @@ let frpcStatusListener = null;
|
||||
* @param callback
|
||||
*/
|
||||
const getFrpcVersionWorkerPath = (
|
||||
versionId: string,
|
||||
callback: (workerPath: string) => void
|
||||
versionId: number,
|
||||
callback: (workerPath: string) => void
|
||||
) => {
|
||||
getVersionById(versionId, (err2, version) => {
|
||||
if (!err2) {
|
||||
if (version) {
|
||||
callback(version["frpcVersionPath"]);
|
||||
}
|
||||
}
|
||||
});
|
||||
getVersionById(versionId, (err2, version) => {
|
||||
if (!err2) {
|
||||
if (version) {
|
||||
callback(version["frpcVersionPath"]);
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
@ -38,47 +38,86 @@ const getFrpcVersionWorkerPath = (
|
||||
* @param config
|
||||
* @param proxys
|
||||
*/
|
||||
const genTomlConfig = (config: Config, proxys: Proxy[]) => {
|
||||
const proxyToml = proxys.map(m => {
|
||||
let toml = `
|
||||
[[proxies]]
|
||||
const genTomlConfig = (config: FrpConfig, proxys: Proxy[]) => {
|
||||
const proxyToml = proxys.map(m => {
|
||||
let toml = `
|
||||
[[${m.type === 'stcp' && m.stcpModel === 'visitors' ? 'visitors' : 'proxies'}]]
|
||||
name = "${m.name}"
|
||||
type = "${m.type}"
|
||||
`;
|
||||
switch (m.type) {
|
||||
case "tcp":
|
||||
case "udp":
|
||||
toml += `
|
||||
localIP = "${m.localIp}"
|
||||
localPort = ${m.localPort}
|
||||
remotePort = ${m.remotePort}
|
||||
`;
|
||||
switch (m.type) {
|
||||
case "tcp":
|
||||
case "udp":
|
||||
toml += `remotePort = ${m.remotePort}`;
|
||||
break;
|
||||
case "http":
|
||||
case "https":
|
||||
toml += `customDomains=[${m.customDomains.map(m => `"${m}"`)}]`;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
break;
|
||||
case "http":
|
||||
case "https":
|
||||
toml += `
|
||||
localIP = "${m.localIp}"
|
||||
localPort = ${m.localPort}
|
||||
customDomains=[${m.customDomains.map(m => `"${m}"`)}]
|
||||
`;
|
||||
break;
|
||||
case "stcp":
|
||||
if (m.stcpModel === "visitors") {
|
||||
// 访问者
|
||||
toml += `
|
||||
serverName = "${m.serverName}"
|
||||
bindAddr = "${m.bindAddr}"
|
||||
bindPort = ${m.bindPort}
|
||||
`;
|
||||
} else if (m.stcpModel === "visited") {
|
||||
// 被访问者
|
||||
toml += `
|
||||
localIP = "${m.localIp}"
|
||||
localPort = ${m.localPort}`;
|
||||
}
|
||||
toml += `
|
||||
secretKey="${m.secretKey}"
|
||||
`;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return toml;
|
||||
});
|
||||
const toml = `
|
||||
return toml;
|
||||
});
|
||||
const toml = `
|
||||
serverAddr = "${config.serverAddr}"
|
||||
serverPort = ${config.serverPort}
|
||||
${config.authMethod === 'token' ? `
|
||||
${
|
||||
config.authMethod === "token"
|
||||
? `
|
||||
auth.method = "token"
|
||||
auth.token = "${config.authToken}"
|
||||
` : ""}
|
||||
${config.authMethod === 'multiuser' ? `
|
||||
`
|
||||
: ""
|
||||
}
|
||||
${
|
||||
config.authMethod === "multiuser"
|
||||
? `
|
||||
user = "${config.user}"
|
||||
metadatas.token = "${config.metaToken}"
|
||||
` : ""}
|
||||
${config.transportHeartbeatInterval ? `
|
||||
`
|
||||
: ""
|
||||
}
|
||||
${
|
||||
config.transportHeartbeatInterval
|
||||
? `
|
||||
transport.heartbeatInterval = ${config.transportHeartbeatInterval}
|
||||
` : ""}
|
||||
${config.transportHeartbeatTimeout ? `
|
||||
`
|
||||
: ""
|
||||
}
|
||||
${
|
||||
config.transportHeartbeatTimeout
|
||||
? `
|
||||
transport.heartbeatTimeout = ${config.transportHeartbeatTimeout}
|
||||
` : ""}
|
||||
`
|
||||
: ""
|
||||
}
|
||||
|
||||
|
||||
log.to = "frpc.log"
|
||||
@ -87,69 +126,92 @@ log.maxDays = ${config.logMaxDays}
|
||||
webServer.addr = "127.0.0.1"
|
||||
webServer.port = 57400
|
||||
transport.tls.enable = ${config.tlsConfigEnable}
|
||||
${config.tlsConfigEnable ? `
|
||||
${
|
||||
config.tlsConfigEnable
|
||||
? `
|
||||
transport.tls.certFile = "${config.tlsConfigCertFile}"
|
||||
transport.tls.keyFile = "${config.tlsConfigKeyFile}"
|
||||
transport.tls.trustedCaFile = "${config.tlsConfigTrustedCaFile}"
|
||||
transport.tls.serverName = "${config.tlsConfigServerName}"
|
||||
` : ""}
|
||||
${config.proxyConfigEnable ? `
|
||||
`
|
||||
: ""
|
||||
}
|
||||
${
|
||||
config.proxyConfigEnable
|
||||
? `
|
||||
transport.proxyURL = "${config.proxyConfigProxyUrl}"
|
||||
` : ""}
|
||||
`
|
||||
: ""
|
||||
}
|
||||
|
||||
${proxyToml.join("")}
|
||||
`;
|
||||
return toml;
|
||||
}
|
||||
|
||||
return toml;
|
||||
};
|
||||
|
||||
/**
|
||||
* 生成ini配置
|
||||
* @param config
|
||||
* @param proxys
|
||||
*/
|
||||
const genIniConfig = (config: Config, proxys: Proxy[]) => {
|
||||
const proxyIni = proxys.map(m => {
|
||||
let ini = `
|
||||
const genIniConfig = (config: FrpConfig, proxys: Proxy[]) => {
|
||||
const proxyIni = proxys.map(m => {
|
||||
let ini = `
|
||||
[${m.name}]
|
||||
type = "${m.type}"
|
||||
local_ip = "${m.localIp}"
|
||||
local_port = ${m.localPort}
|
||||
`;
|
||||
switch (m.type) {
|
||||
case "tcp":
|
||||
case "udp":
|
||||
ini += `remote_port = ${m.remotePort}`;
|
||||
break;
|
||||
case "http":
|
||||
case "https":
|
||||
ini += `custom_domains=[${m.customDomains.map(m => `"${m}"`)}]`;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
switch (m.type) {
|
||||
case "tcp":
|
||||
case "udp":
|
||||
ini += `remote_port = ${m.remotePort}`;
|
||||
break;
|
||||
case "http":
|
||||
case "https":
|
||||
ini += `custom_domains=[${m.customDomains.map(m => `"${m}"`)}]`;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return ini;
|
||||
});
|
||||
const ini = `
|
||||
return ini;
|
||||
});
|
||||
const ini = `
|
||||
[common]
|
||||
server_addr = ${config.serverAddr}
|
||||
server_port = ${config.serverPort}
|
||||
${config.authMethod === 'token' ? `
|
||||
${
|
||||
config.authMethod === "token"
|
||||
? `
|
||||
authentication_method = ${config.authMethod}
|
||||
token = ${config.authToken}
|
||||
` : ""}
|
||||
${config.authMethod === 'multiuser' ? `
|
||||
`
|
||||
: ""
|
||||
}
|
||||
${
|
||||
config.authMethod === "multiuser"
|
||||
? `
|
||||
user = ${config.user}
|
||||
meta_token = ${config.metaToken}
|
||||
` : ""}
|
||||
`
|
||||
: ""
|
||||
}
|
||||
|
||||
${config.transportHeartbeatInterval ? `
|
||||
${
|
||||
config.transportHeartbeatInterval
|
||||
? `
|
||||
heartbeat_interval = ${config.transportHeartbeatInterval}
|
||||
` : ""}
|
||||
${config.transportHeartbeatTimeout ? `
|
||||
`
|
||||
: ""
|
||||
}
|
||||
${
|
||||
config.transportHeartbeatTimeout
|
||||
? `
|
||||
heartbeat_timeout = ${config.transportHeartbeatTimeout}
|
||||
` : ""}
|
||||
`
|
||||
: ""
|
||||
}
|
||||
|
||||
log_file = "frpc.log"
|
||||
log_level = ${config.logLevel}
|
||||
@ -157,55 +219,63 @@ log_max_days = ${config.logMaxDays}
|
||||
admin_addr = 127.0.0.1
|
||||
admin_port = 57400
|
||||
tls_enable = ${config.tlsConfigEnable}
|
||||
${config.tlsConfigEnable ? `
|
||||
${
|
||||
config.tlsConfigEnable
|
||||
? `
|
||||
tls_cert_file = ${config.tlsConfigCertFile}
|
||||
tls_key_file = ${config.tlsConfigKeyFile}
|
||||
tls_trusted_ca_file = ${config.tlsConfigTrustedCaFile}
|
||||
tls_server_name = ${config.tlsConfigServerName}
|
||||
` : ""}
|
||||
${config.proxyConfigEnable ? `
|
||||
`
|
||||
: ""
|
||||
}
|
||||
${
|
||||
config.proxyConfigEnable
|
||||
? `
|
||||
http_proxy = "${config.proxyConfigProxyUrl}"
|
||||
` : ""}
|
||||
`
|
||||
: ""
|
||||
}
|
||||
|
||||
${proxyIni.join("")}
|
||||
`
|
||||
return ini;
|
||||
}
|
||||
`;
|
||||
return ini;
|
||||
};
|
||||
|
||||
/**
|
||||
* 生成配置文件
|
||||
*/
|
||||
export const generateConfig = (
|
||||
config: Config,
|
||||
callback: (configPath: string) => void
|
||||
config: FrpConfig,
|
||||
callback: (configPath: string) => void
|
||||
) => {
|
||||
listProxy((err3, proxys) => {
|
||||
if (!err3) {
|
||||
const {currentVersion} = config;
|
||||
let filename = null;
|
||||
let configContent = "";
|
||||
if (currentVersion < 124395282) {
|
||||
// 版本小于v0.52.0
|
||||
filename = "frp.ini";
|
||||
configContent = genIniConfig(config, proxys)
|
||||
} else {
|
||||
filename = "frp.toml";
|
||||
configContent = genTomlConfig(config, proxys)
|
||||
}
|
||||
const configPath = path.join(app.getPath("userData"), filename)
|
||||
log.info(`生成配置成功 配置路径:${configPath}`)
|
||||
fs.writeFile(
|
||||
configPath, // 配置文件目录
|
||||
configContent, // 配置文件内容
|
||||
{flag: "w"},
|
||||
err => {
|
||||
if (!err) {
|
||||
callback(filename);
|
||||
}
|
||||
}
|
||||
);
|
||||
listProxy((err3, proxys) => {
|
||||
if (!err3) {
|
||||
const { currentVersion } = config;
|
||||
let filename = null;
|
||||
let configContent = "";
|
||||
if (currentVersion < 124395282) {
|
||||
// 版本小于v0.52.0
|
||||
filename = "frp.ini";
|
||||
configContent = genIniConfig(config, proxys);
|
||||
} else {
|
||||
filename = "frp.toml";
|
||||
configContent = genTomlConfig(config, proxys);
|
||||
}
|
||||
const configPath = path.join(app.getPath("userData"), filename);
|
||||
log.info(`生成配置成功 配置路径:${configPath}`);
|
||||
fs.writeFile(
|
||||
configPath, // 配置文件目录
|
||||
configContent, // 配置文件内容
|
||||
{ flag: "w" },
|
||||
err => {
|
||||
if (!err) {
|
||||
callback(filename);
|
||||
}
|
||||
}
|
||||
});
|
||||
);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
@ -215,149 +285,136 @@ export const generateConfig = (
|
||||
* @param configPath
|
||||
*/
|
||||
const startFrpcProcess = (commandPath: string, configPath: string) => {
|
||||
log.info(`启动frpc 目录:${app.getPath("userData")} 命令:${commandPath}`,)
|
||||
const command = `${commandPath} -c ${configPath}`;
|
||||
frpcProcess = spawn(command, {
|
||||
cwd: app.getPath("userData"),
|
||||
shell: true
|
||||
});
|
||||
runningCmd.commandPath = commandPath;
|
||||
runningCmd.configPath = configPath;
|
||||
frpcProcess.stdout.on("data", data => {
|
||||
log.debug(`启动输出:${data}`)
|
||||
});
|
||||
frpcProcess.stdout.on("error", data => {
|
||||
log.error(`启动错误:${data}`)
|
||||
stopFrpcProcess(() => {
|
||||
})
|
||||
});
|
||||
frpcStatusListener = setInterval(() => {
|
||||
const status = frpcProcessStatus()
|
||||
log.debug(`监听frpc子进程状态:${status}`)
|
||||
if (!status) {
|
||||
new Notification({
|
||||
title: "Frpc Desktop",
|
||||
body: "连接已断开,请前往日志查看原因"
|
||||
}).show()
|
||||
clearInterval(frpcStatusListener)
|
||||
}
|
||||
}, 3000)
|
||||
log.info(`启动frpc 目录:${app.getPath("userData")} 命令:${commandPath}`);
|
||||
const command = `${commandPath} -c ${configPath}`;
|
||||
frpcProcess = spawn(command, {
|
||||
cwd: app.getPath("userData"),
|
||||
shell: true
|
||||
});
|
||||
runningCmd.commandPath = commandPath;
|
||||
runningCmd.configPath = configPath;
|
||||
frpcProcess.stdout.on("data", data => {
|
||||
log.debug(`启动输出:${data}`);
|
||||
});
|
||||
frpcProcess.stdout.on("error", data => {
|
||||
log.error(`启动错误:${data}`);
|
||||
stopFrpcProcess(() => {});
|
||||
});
|
||||
frpcStatusListener = setInterval(() => {
|
||||
const status = frpcProcessStatus();
|
||||
log.debug(`监听frpc子进程状态:${status}`);
|
||||
if (!status) {
|
||||
new Notification({
|
||||
title: "Frpc Desktop",
|
||||
body: "连接已断开,请前往日志查看原因"
|
||||
}).show();
|
||||
clearInterval(frpcStatusListener);
|
||||
}
|
||||
}, 3000);
|
||||
};
|
||||
|
||||
/**
|
||||
* 重载frpc配置
|
||||
*/
|
||||
export const reloadFrpcProcess = () => {
|
||||
if (frpcProcess && !frpcProcess.killed) {
|
||||
getConfig((err1, config) => {
|
||||
if (!err1) {
|
||||
if (config) {
|
||||
generateConfig(config, configPath => {
|
||||
const command = `${runningCmd.commandPath} reload -c ${configPath}`;
|
||||
log.info(`重载配置:${command}`)
|
||||
exec(command, {
|
||||
cwd: app.getPath("userData"),
|
||||
shell: true
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
if (frpcProcess && !frpcProcess.killed) {
|
||||
getConfig((err1, config) => {
|
||||
if (!err1) {
|
||||
if (config) {
|
||||
generateConfig(config, configPath => {
|
||||
const command = `${runningCmd.commandPath} reload -c ${configPath}`;
|
||||
log.info(`重载配置:${command}`);
|
||||
exec(command, {
|
||||
cwd: app.getPath("userData"),
|
||||
shell: true
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 停止frpc子进程
|
||||
*/
|
||||
export const stopFrpcProcess = (callback?: () => void) => {
|
||||
if (frpcProcess) {
|
||||
treeKill(frpcProcess.pid, (error: Error) => {
|
||||
if (error) {
|
||||
log.error(`关闭frpc子进程失败 pid:${frpcProcess.pid} error:${error}`)
|
||||
callback()
|
||||
} else {
|
||||
log.info(`关闭frpc子进程成功`)
|
||||
frpcProcess = null
|
||||
clearInterval(frpcStatusListener)
|
||||
callback()
|
||||
}
|
||||
})
|
||||
} else {
|
||||
callback()
|
||||
}
|
||||
}
|
||||
if (frpcProcess) {
|
||||
treeKill(frpcProcess.pid, (error: Error) => {
|
||||
if (error) {
|
||||
log.error(`关闭frpc子进程失败 pid:${frpcProcess.pid} error:${error}`);
|
||||
callback();
|
||||
} else {
|
||||
log.info(`关闭frpc子进程成功`);
|
||||
frpcProcess = null;
|
||||
clearInterval(frpcStatusListener);
|
||||
callback();
|
||||
}
|
||||
});
|
||||
} else {
|
||||
callback();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 获取frpc子进程状态
|
||||
*/
|
||||
export const frpcProcessStatus = () => {
|
||||
if (!frpcProcess) {
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
// 发送信号给进程,如果进程存在,会正常返回
|
||||
process.kill(frpcProcess.pid, 0);
|
||||
return true;
|
||||
} catch (error) {
|
||||
// 进程不存在,抛出异常
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (!frpcProcess) {
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
// 发送信号给进程,如果进程存在,会正常返回
|
||||
process.kill(frpcProcess.pid, 0);
|
||||
return true;
|
||||
} catch (error) {
|
||||
// 进程不存在,抛出异常
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 启动frpc流程
|
||||
* @param config
|
||||
*/
|
||||
export const startFrpWorkerProcess = async (config: Config) => {
|
||||
getFrpcVersionWorkerPath(
|
||||
config.currentVersion,
|
||||
(frpcVersionPath: string) => {
|
||||
if (frpcVersionPath) {
|
||||
generateConfig(config, configPath => {
|
||||
const platform = process.platform;
|
||||
if (platform === 'win32') {
|
||||
startFrpcProcess(
|
||||
path.join(frpcVersionPath, "frpc.exe"),
|
||||
configPath
|
||||
);
|
||||
} else {
|
||||
startFrpcProcess(
|
||||
path.join(frpcVersionPath, "frpc"),
|
||||
configPath
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
export const startFrpWorkerProcess = async (config: FrpConfig) => {
|
||||
getFrpcVersionWorkerPath(config.currentVersion, (frpcVersionPath: string) => {
|
||||
if (frpcVersionPath) {
|
||||
generateConfig(config, configPath => {
|
||||
const platform = process.platform;
|
||||
if (platform === "win32") {
|
||||
startFrpcProcess(path.join(frpcVersionPath, "frpc.exe"), configPath);
|
||||
} else {
|
||||
startFrpcProcess(path.join(frpcVersionPath, "frpc"), configPath);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
export const initFrpcApi = () => {
|
||||
ipcMain.handle("frpc.running", async (event, args) => {
|
||||
return frpcProcessStatus()
|
||||
});
|
||||
ipcMain.handle("frpc.running", async (event, args) => {
|
||||
return frpcProcessStatus();
|
||||
});
|
||||
|
||||
ipcMain.on("frpc.start", async (event, args) => {
|
||||
getConfig((err1, config) => {
|
||||
if (!err1) {
|
||||
if (config) {
|
||||
startFrpWorkerProcess(config)
|
||||
} else {
|
||||
event.reply(
|
||||
"Home.frpc.start.error.hook", "请先前往设置页面,修改配置后再启动"
|
||||
);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
ipcMain.on("frpc.stop", () => {
|
||||
if (frpcProcess && !frpcProcess.killed) {
|
||||
stopFrpcProcess(() => {
|
||||
|
||||
})
|
||||
ipcMain.on("frpc.start", async (event, args) => {
|
||||
getConfig((err1, config) => {
|
||||
if (!err1) {
|
||||
if (config) {
|
||||
startFrpWorkerProcess(config);
|
||||
} else {
|
||||
event.reply(
|
||||
"Home.frpc.start.error.hook",
|
||||
"请先前往设置页面,修改配置后再启动"
|
||||
);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
ipcMain.on("frpc.stop", () => {
|
||||
if (frpcProcess && !frpcProcess.killed) {
|
||||
stopFrpcProcess(() => {});
|
||||
}
|
||||
});
|
||||
};
|
||||
|
@ -32,7 +32,7 @@ export const listVersion = (
|
||||
};
|
||||
|
||||
export const getVersionById = (
|
||||
id: string,
|
||||
id: number,
|
||||
callback: (err: Error | null, document: FrpVersion) => void
|
||||
) => {
|
||||
versionDB.findOne({id: id}, callback);
|
||||
|
@ -43,7 +43,7 @@ const defaultForm = ref<Proxy>({
|
||||
localPort: 8080,
|
||||
remotePort: 8080,
|
||||
customDomains: [""],
|
||||
stcpModel: "visitor",
|
||||
stcpModel: "visitors",
|
||||
serverName: "",
|
||||
secretKey: "",
|
||||
bindAddr: "",
|
||||
@ -63,7 +63,7 @@ const proxyTypes = ref(["http", "https", "tcp", "udp", "stcp"]);
|
||||
const stcpModels = ref([
|
||||
{
|
||||
label: "访问者",
|
||||
value: "visitor"
|
||||
value: "visitors"
|
||||
},
|
||||
{
|
||||
label: "被访问者",
|
||||
@ -469,7 +469,7 @@ onUnmounted(() => {
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</template>
|
||||
<el-col :span="editForm.stcpModel === 'visitor' ? 12 : 24">
|
||||
<el-col :span="editForm.stcpModel === 'visitors' ? 12 : 24">
|
||||
<el-form-item label="代理名称:" prop="name">
|
||||
<el-input
|
||||
v-model="editForm.name"
|
||||
@ -625,7 +625,7 @@ onUnmounted(() => {
|
||||
</el-col>
|
||||
</template>
|
||||
<template
|
||||
v-if="editForm.type === 'stcp' && editForm.stcpModel === 'visitor'"
|
||||
v-if="editForm.type === 'stcp' && editForm.stcpModel === 'visitors'"
|
||||
>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="被访问者代理名称:" prop="serverName">
|
||||
@ -791,6 +791,10 @@ onUnmounted(() => {
|
||||
background: #5ec7fe;
|
||||
}
|
||||
|
||||
.stcp {
|
||||
background: #D63DA6;
|
||||
}
|
||||
|
||||
.domain-input {
|
||||
width: calc(100% - 115px);
|
||||
}
|
||||
|
2
types/global.d.ts
vendored
2
types/global.d.ts
vendored
@ -53,7 +53,7 @@ declare global {
|
||||
* 全局配置
|
||||
*/
|
||||
type FrpConfig = {
|
||||
currentVersion: string;
|
||||
currentVersion: number;
|
||||
serverAddr: string;
|
||||
serverPort: number;
|
||||
authMethod: string;
|
||||
|
Loading…
Reference in New Issue
Block a user