🚧 传输配置完善

This commit is contained in:
刘嘉伟 2025-01-06 16:14:52 +08:00
parent a1910be29c
commit 91b97df99a
4 changed files with 643 additions and 392 deletions

View File

@ -140,7 +140,16 @@ export const initConfigApi = win => {
systemStartupConnect: false, systemStartupConnect: false,
systemSilentStartup: false, systemSilentStartup: false,
webEnable: true, webEnable: true,
webPort: sourceConfig?.webServer?.port || 57400 webPort: sourceConfig?.webServer?.port || 57400,
transportProtocol: sourceConfig?.transport?.protocol || "tcp",
transportDialServerTimeout:
sourceConfig?.transport?.dialServerTimeout || 10,
transportDialServerKeepalive:
sourceConfig?.transport?.dialServerKeepalive || 70,
transportPoolCount: sourceConfig?.transport?.poolCount || 0,
transportTcpMux: sourceConfig?.transport?.tcpMux || true,
transportTcpMuxKeepaliveInterval:
sourceConfig?.transport?.tcpMuxKeepaliveInterval || 7200
}; };
let frpcProxys = []; let frpcProxys = [];
// 解析proxy // 解析proxy
@ -255,12 +264,12 @@ export const initConfigApi = win => {
ipcMain.on("config.openDataFolder", async (event, args) => { ipcMain.on("config.openDataFolder", async (event, args) => {
const userDataPath = app.getPath("userData"); const userDataPath = app.getPath("userData");
shell.openPath(userDataPath).then((errorMessage) => { shell.openPath(userDataPath).then(errorMessage => {
if (errorMessage) { if (errorMessage) {
console.error('Failed to open Logger:', errorMessage); console.error("Failed to open Logger:", errorMessage);
event.reply("Config.openDataFolder.hook", false); event.reply("Config.openDataFolder.hook", false);
} else { } else {
console.log('Logger opened successfully'); console.log("Logger opened successfully");
event.reply("Config.openDataFolder.hook", true); event.reply("Config.openDataFolder.hook", true);
} }
}); });

View File

@ -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) {

View File

@ -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,7 +1218,8 @@ onUnmounted(() => {
icon="info" icon="info"
/> />
</template> </template>
热更新等功能依赖于web界面<span class="font-black text-[#5A3DAA]" 热更新等功能依赖于web界面<span
class="font-black text-[#5A3DAA]"
>不可停用Web</span >不可停用Web</span
> >
</el-popover> </el-popover>
@ -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
View File

@ -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 = {