重构中继

This commit is contained in:
snltty
2025-12-03 17:37:19 +08:00
parent f0766266ba
commit a1acf27d6f
21 changed files with 199 additions and 171 deletions

View File

@@ -13,4 +13,6 @@ services:
- "/$TRIM_APPDEST_VOL/@appshare/linker-docker/configs:/app/configs"
- "/$TRIM_APPDEST_VOL/@appshare/linker-docker/logs:/app/logs"
devices:
- /dev/net/tun:/dev/net/tun
- /dev/net/tun:/dev/net/tun
environment:
- SNLTTY_LINKER_IS_FNOS=linker

View File

@@ -1,5 +1,5 @@
v1.9.6
2025-12-02 17:20:22
2025-12-03 17:37:19
1. 一些累计更新一些BUG修复
2. 优化客户端数据同步,减少服务器流量
3. 去除cdkey改为发电解锁中继速度

View File

@@ -65,13 +65,32 @@ namespace linker.libs
public static string GetSystemStr()
{
return $"{SystemName()}-{VersionNumber()}-{RuntimeInformation.OSArchitecture.ToString().ToLower()}";
return $"{SystemName()}-{VersionNumber()}-any";
}
private static string SystemName()
{
string pattern = @"ikuai|fnos|iphone|samsung|vivo|oppo|google|huawei|xiaomi|ios|android|windows|ubuntu|openwrt|armbian|archlinux|fedora|centos|rocky|alpine|debian|linux|docker";
return Regex.Match(RuntimeInformation.OSDescription.ToLower(), pattern)?.Value ?? "unknow";
string pattern = @"ikuai|fnos|iphone|samsung|vivo|oppo|google|huawei|xiaomi|ios|android|windows|docker|ubuntu|openwrt|armbian|archlinux|fedora|centos|rocky|alpine|debian|linux";
return Regex.Match(GetDesc(), pattern)?.Value ?? "unknow";
}
private static string GetDesc()
{
if(string.IsNullOrWhiteSpace(Environment.GetEnvironmentVariable("SNLTTY_LINKER_IS_FNOS")) == false)
{
return "fnos";
}
if (string.IsNullOrWhiteSpace(Environment.GetEnvironmentVariable("SNLTTY_LINKER_IS_DOCKER")) == false)
{
return "docker";
}
if (File.Exists("/usr/trim/www/static/pong.html"))
{
return "fnos";
}
return RuntimeInformation.OSDescription.ToLower();
}
private static string VersionNumber()
{
var version = Environment.OSVersion.Version;
@@ -91,34 +110,8 @@ namespace linker.libs
_ => $"unknow"
};
}
if (OperatingSystem.IsAndroid())
{
return version.Major switch
{
35 => "15",
34 => "14",
33 => "13",
32 => "12L",
31 => "12",
30 => "11",
29 => "10",
28 => "9",
27 => "8.1",
26 => "8.0",
25 => "7.1",
24 => "7.0",
23 => "6.0",
22 => "5.1",
21 => "5.0",
_ => $"unknow"
};
}
if (OperatingSystem.IsLinux())
{
return $"{version.Major}.x";
}
return version.ToString();
return $"any";
}
}
}

View File

@@ -1,6 +1,5 @@
using linker.libs.extends;
using linker.libs.web;
using System.Threading.Tasks;
namespace linker.messenger.flow.webapi
{
public sealed class WebApiSystemsController : IWebApiController

View File

@@ -226,7 +226,8 @@ namespace linker.messenger.relay.server
ConnectionsRatio = connectionNum,
BandwidthRatio = Math.Round(diff / 5, 2),
Version = VersionHelper.Version,
Masters = connections.Select(c => c.Address).ToArray()
Masters = connections.Select(c => c.Address).ToArray(),
MasterKey = config.MasterKey,
};
byte[] memory = serializer.Serialize(info);
var tasks = connections.Select(c => messengerSender.SendOnly(new MessageRequestWrap

View File

@@ -1,9 +1,7 @@
using linker.libs;
using linker.libs.timer;
using linker.messenger.sforward.messenger;
using linker.messenger.signin;
using System.Collections.Concurrent;
using System.Linq;
using System.Net;
namespace linker.messenger.sforward.server
@@ -15,9 +13,6 @@ namespace linker.messenger.sforward.server
{
private readonly ConcurrentDictionary<string, SForwardServerNodeReportInfo> reports = new ConcurrentDictionary<string, SForwardServerNodeReportInfo>();
private readonly ConcurrentQueue<Dictionary<int, long>> trafficQueue = new ConcurrentQueue<Dictionary<int, long>>();
private readonly ConcurrentQueue<List<int>> trafficIdsQueue = new ConcurrentQueue<List<int>>();
private readonly ISerializer serializer;
private readonly IMessengerSender messengerSender;
private readonly ISForwardServerWhiteListStore sForwardServerWhiteListStore;
@@ -97,7 +92,14 @@ namespace linker.messenger.sforward.server
public async Task<SForwardAddResultInfo> Add(SForwardAddInfo info, SignCacheInfo from)
{
if (string.IsNullOrWhiteSpace(info.NodeId)) info.NodeId = sForwardServerNodeStore.Node.Id;
if (string.IsNullOrWhiteSpace(info.NodeId))
{
var nodes = await GetNodes(from.Super, from.UserId, from.MachineId);
if (nodes.Count > 0)
{
info.NodeId = nodes[0].Id;
}
}
if (GetNode(info.NodeId, out var node) == false)
{
return new SForwardAddResultInfo
@@ -118,7 +120,7 @@ namespace linker.messenger.sforward.server
return new SForwardAddResultInfo
{
BufferSize = 1,
Message = "white list deney",
Message = "white list deny",
Success = false
};
}

View File

@@ -10,18 +10,16 @@ namespace linker.messenger.sforward.server.validator
public string Name => "default";
private readonly ISForwardServerStore sForwardServerStore;
private readonly SForwardServerMasterTransfer sForwardServerMasterTransfer;
private readonly ISForwardServerNodeStore sForwardServerNodeStore;
public SForwardValidator(ISForwardServerStore sForwardServerStore, SForwardServerMasterTransfer sForwardServerMasterTransfer, ISForwardServerNodeStore sForwardServerNodeStore)
public SForwardValidator(ISForwardServerStore sForwardServerStore, ISForwardServerNodeStore sForwardServerNodeStore)
{
this.sForwardServerStore = sForwardServerStore;
this.sForwardServerMasterTransfer = sForwardServerMasterTransfer;
this.sForwardServerNodeStore = sForwardServerNodeStore;
}
public async Task<string> Validate(SignCacheInfo signCacheInfo, SForwardAddInfo sForwardAddInfo)
{
if (string.IsNullOrWhiteSpace(sForwardAddInfo.NodeId)) sForwardAddInfo.NodeId = sForwardServerNodeStore.Node.Id;
//if (string.IsNullOrWhiteSpace(sForwardAddInfo.NodeId)) sForwardAddInfo.NodeId = sForwardServerNodeStore.Node.Id;
if (sForwardAddInfo.RemotePort > 0)
{

View File

@@ -59,7 +59,7 @@ namespace linker.messenger.store.file.relay
MasterKey = info.MasterKey,
Masters = info.Masters,
//是我初始化的,可以管理
Manageable = info.MasterKey == md5
Manageable = false//info.MasterKey == md5
}, c => c.NodeId == info.NodeId);
return await Task.FromResult(length > 0).ConfigureAwait(false); ;

View File

@@ -243,6 +243,9 @@
<a href="" class="linker-download block px-4 py-1.5 text-sm hover:bg-light-dark rounded transition-colors" data-file="linker-docker-x64.fpk">
<i class="fa fa-linux mr-2 text-accent"></i> x64 (Docker)
</a>
<a href="" class="linker-download block px-4 py-1.5 text-sm hover:bg-light-dark rounded transition-colors" data-file="linker-bin-x64.fpk">
<i class="fa fa-linux mr-2 text-accent"></i> x64 (Binary)
</a>
</div>
<!-- OpenWRT 下载链接 -->
<div class="border-b border-light-dark pb-1 mb-1 download-openwrt">

View File

@@ -235,6 +235,9 @@
<a href="" class="linker-download block px-4 py-1.5 text-sm hover:bg-light-dark rounded transition-colors" data-file="linker-docker-x64.fpk">
<i class="fa fa-linux mr-2 text-accent"></i> x64 (Docker)
</a>
<a href="" class="linker-download block px-4 py-1.5 text-sm hover:bg-light-dark rounded transition-colors" data-file="linker-bin-x64.fpk">
<i class="fa fa-linux mr-2 text-accent"></i> x64 (Binary)
</a>
</div>
<!-- OpenWRT 下载链接 -->
<div class="border-b border-light-dark pb-1 mb-1 download-openwrt">

View File

@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<project ver="10" name="linker.tray.win" libEmbed="true" icon="..\linker\favicon.ico" ui="win" output="linker.tray.win.exe" CompanyName="snltty" FileDescription="linker.tray.win" LegalCopyright="Copyright (C) snltty 2024" ProductName="linker.tray.win" InternalName="linker.install.win" FileVersion="0.0.0.350" ProductVersion="0.0.0.350" publishDir="/dist/" dstrip="false" local="false" ignored="false">
<project ver="10" name="linker.tray.win" libEmbed="true" icon="..\linker\favicon.ico" ui="win" output="linker.tray.win.exe" CompanyName="snltty" FileDescription="linker.tray.win" LegalCopyright="Copyright (C) snltty 2024" ProductName="linker.tray.win" InternalName="linker.install.win" FileVersion="0.0.0.352" ProductVersion="0.0.0.352" publishDir="/dist/" dstrip="false" local="false" ignored="false">
<file name="main.aardio" path="main.aardio" comment="main.aardio"/>
<folder name="资源文件" path="res" embed="true" local="false" ignored="false">
<file name="favicon.ico" path="res\favicon.ico" comment="res\favicon.ico"/>

Binary file not shown.

View File

@@ -1,6 +1,6 @@
import win.ui;
/*DSG{{*/
var winform = win.form(text="linker 管理";right=820;bottom=750;max=false)
var winform = win.form(text="linker 管理";right=820;bottom=820;max=false)
winform.add()
/*}}*/

View File

@@ -202,6 +202,7 @@ export default {
'server.relayPublic': 'Public',
'server.relayAllow': 'Allow',
'server.relayUrl': 'Url',
'server.relayLogo': 'Logo',
'server.relayOper': 'Oper',
'server.relayUse': 'Use',
'server.relayDefault': 'Default',

View File

@@ -298,6 +298,7 @@ export default {
'server.relayPublic': '公开',
'server.relayAllow': '支持协议',
'server.relayUrl': 'Url',
'server.relayLogo': 'Logo',
'server.relayOper': '操作',
'server.relayUse': '使用',
'server.relayDefault': '默认',

View File

@@ -3,35 +3,35 @@
<div>
<el-form ref="ruleFormRef" :model="state.ruleForm" :rules="state.rules" label-width="auto">
<el-form-item :label="$t('server.relayName')" prop="Name">
<el-input v-trim minlength="1" maxlength="32" show-word-limit v-model="state.ruleForm.Name" />
<el-input :disabled="data.Manageable==false" v-trim minlength="1" maxlength="32" show-word-limit v-model="state.ruleForm.Name" />
</el-form-item>
<el-form-item :label="$t('server.relayConnection')" prop="MaxConnection">
<el-input-number v-model="state.ruleForm.MaxConnection" :min="0" :max="65535"/>
<el-form-item :label="$t('server.relayConnection')" prop="Connections">
<el-input-number :disabled="data.Manageable==false" v-model="state.ruleForm.Connections" :min="0" :max="65535"/>
</el-form-item>
<el-form-item :label="$t('server.relaySpeed')" prop="MaxBandwidth">
<el-input-number v-model="state.ruleForm.MaxBandwidth" :min="0"/>Mbps
<el-form-item :label="$t('server.relaySpeed')" prop="BandwidthEach">
<el-input-number v-model="state.ruleForm.BandwidthEach" :min="0"/>Mbps
</el-form-item>
<el-form-item :label="$t('server.relaySpeed1')" prop="MaxBandwidthTotal">
<el-input-number v-model="state.ruleForm.MaxBandwidthTotal" :min="0"/>Mbps
<el-form-item :label="$t('server.relaySpeed1')" prop="Bandwidth">
<el-input-number :disabled="data.Manageable==false" v-model="state.ruleForm.Bandwidth" :min="0"/>Mbps
</el-form-item>
<el-form-item :label="$t('server.relayFlow')" prop="MaxGbTotal">
<el-input-number v-model="state.ruleForm.MaxGbTotal" :min="0"/>GB <el-button size="small" @click="handleRefresh"><el-icon><Refresh /></el-icon></el-button>
<el-form-item :label="$t('server.relayFlow')" prop="DataEachMonth">
<el-input-number :disabled="data.Manageable==false" v-model="state.ruleForm.DataEachMonth" :min="0"/>GB <el-button size="small" @click="handleRefresh"><el-icon><Refresh /></el-icon></el-button>
</el-form-item>
<el-form-item :label="$t('server.relayFlowLast')" prop="MaxGbTotalLastBytes">
<el-input-number v-model="state.ruleForm.MaxGbTotalLastBytes" :min="0" />byte
<el-form-item :label="$t('server.relayFlowLast')" prop="DataRemain">
<el-input-number :disabled="data.Manageable==false" v-model="state.ruleForm.DataRemain" :min="0" />byte
</el-form-item>
<el-form-item :label="$t('server.relayUrl')" prop="Url">
<el-input v-trim v-model="state.ruleForm.Url" />
<el-input :disabled="data.Manageable==false" v-trim v-model="state.ruleForm.Url" />
</el-form-item>
<el-form-item :label="$t('server.relayLogo')" prop="Logo">
<el-input :disabled="data.Manageable==false" v-trim v-model="state.ruleForm.Logo" />
</el-form-item>
<el-form-item :label="$t('server.relayPublic')" prop="Public">
<el-switch v-model="state.ruleForm.Public " size="small" />
</el-form-item>
<el-form-item :label="$t('server.relaySync2Server')" prop="Sync2Server">
<el-switch v-model="state.ruleForm.Sync2Server " size="small" />
</el-form-item>
<el-form-item :label="$t('server.relayAllow')" prop="Allow">
<el-checkbox v-model="state.ruleForm.AllowTcp">TCP</el-checkbox>
<el-checkbox v-model="state.ruleForm.AllowUdp">UDP</el-checkbox>
<el-checkbox :disabled="data.Manageable==false" v-model="state.ruleForm.AllowTcp">TCP</el-checkbox>
<el-checkbox :disabled="data.Manageable==false" v-model="state.ruleForm.AllowUdp">UDP</el-checkbox>
</el-form-item>
<el-form-item></el-form-item>
<el-form-item label="" prop="Btns">
@@ -62,16 +62,16 @@ export default {
ruleForm:{
Id:props.data.Id,
Name:props.data.Name,
MaxConnection:props.data.MaxConnection,
MaxBandwidth:props.data.MaxBandwidth,
MaxBandwidthTotal:props.data.MaxBandwidthTotal,
MaxGbTotal:props.data.MaxGbTotal,
MaxGbTotalLastBytes:props.data.MaxGbTotalLastBytes,
Connections:props.data.Connections,
BandwidthEach:props.data.BandwidthEach,
Bandwidth:props.data.Bandwidth,
DataEachMonth:props.data.DataEachMonth,
DataRemain:props.data.DataRemain,
Public:props.data.Public,
Url:props.data.Url,
AllowTcp:(props.data.AllowProtocol & 1) == 1,
AllowUdp:(props.data.AllowProtocol & 2) == 2,
Sync2Server:props.data.Sync2Server || false,
Logo:props.data.Logo,
AllowTcp:(props.data.Protocol & 1) == 1,
AllowUdp:(props.data.Protocol & 2) == 2,
},
rules:{
}
@@ -84,7 +84,7 @@ export default {
}
});
const handleRefresh = ()=>{
state.ruleForm.MaxGbTotalLastBytes = state.ruleForm.MaxGbTotal * 1024*1024*1024;
state.ruleForm.DataRemain = state.ruleForm.DataEachMonth * 1024*1024*1024;
}
const ruleFormRef = ref(null);
@@ -93,7 +93,7 @@ export default {
if (!valid) return;
const json = JSON.parse(JSON.stringify(state.ruleForm));
json.AllowProtocol = (json.AllowTcp ? 1 : 0) | (json.AllowUdp ? 2 : 0);
json.Protocol = (json.AllowTcp ? 1 : 0) | (json.AllowUdp ? 2 : 0);
relayEdit(json).then((res)=>{
if(res){

View File

@@ -5,82 +5,85 @@
<el-table :data="state.nodes" size="small" border height="500" stripe>
<el-table-column property="Name" :label="$t('server.relayName')">
<template #default="scope">
<div>
<p class="flex">
<a :href="scope.row.Url" class="a-line"
:class="{green:scope.row.Public}" target="_blank"
:title="scope.row.Public?$t('server.relayPublic'):''"><strong>{{ scope.row.Name }}</strong></a>
<span class="flex-1"></span>
<a href="javascript:;">
<span v-if="(scope.row.AllowProtocol & 1) == 1">tcp</span>
<span v-if="(scope.row.AllowProtocol & 2) == 2">,udp</span>
<div class="flex">
<div>
<a :href="scope.row.Url" target="_blank" >
<img class="logo" :src="scope.row.Logo || 'https://linker.snltty.com/img/logo.png'" alt=""/>
</a>
</p>
<p class="flex">
<el-checkbox v-if="state.super" class="mgr-p6" v-model="scope.row.Sync2Server" disabled size="small" @click="handleSync2Server(scope.row)">{{ $t('server.relaySync2Server') }}</el-checkbox>
<template v-if="(scope.row.AllowProtocol & 1) == 1">
<template v-if="state.syncData.Key == scope.row.Id && state.syncData.Value == 1">
<el-checkbox class="mgr-p6" size="small" disabled checked>{{ $t('server.relayDefault') }}TCP</el-checkbox>
</template>
<template v-else>
<el-checkbox class="mgr-p6" size="small" disabled @click.stop="handleShowSync(scope.row.Id, 1)">{{ $t('server.relayDefault') }}TCP</el-checkbox>
</template>
</template>
<template v-if="(scope.row.AllowProtocol & 2) == 2">
<template v-if="state.syncData.Key == scope.row.Id && state.syncData.Value == 2">
<el-checkbox class="mgr-p6" size="small" disabled checked>{{ $t('server.relayDefault') }}UDP</el-checkbox>
</template>
<template v-else>
<el-checkbox class="mgr-p6" size="small" disabled @click.stop="handleShowSync(scope.row.Id, 2)">{{ $t('server.relayDefault') }}UDP</el-checkbox>
</template>
</template>
<span class="flex-1"></span>
<a v-if="state.super" href="javascript:;" class="a-line a-edit" @click="handleUpdate(scope.row.Id)"><el-icon><Refresh /></el-icon>{{ scope.row.Version }}</a>
<a v-else href="javascript:;" class="a-line a-edit"><el-icon><Refresh /></el-icon>{{ scope.row.Version }}</a>
</p>
</div>
<div class="flex-1">
<p class="flex">
<a :href="scope.row.Url" class="a-line"
:class="{green:scope.row.Public}" target="_blank"
:title="scope.row.Public?$t('server.relayPublic'):''"><strong>{{ scope.row.Name }}</strong></a>
<span class="flex-1"></span>
<a href="javascript:;" class="protocol">
<span v-if="(scope.row.Protocol & 1) == 1">tcp</span>
<span v-if="(scope.row.Protocol & 2) == 2">,udp</span>
</a>
</p>
<p class="flex">
<div>
<template v-if="state.syncData.Key == scope.row.Id">
<el-checkbox size="small" disabled checked>{{ $t('server.relayDefault') }}</el-checkbox>
</template>
<template v-else>
<el-checkbox size="small" disabled @click.stop="handleShowSync(scope.row, 1)">{{ $t('server.relayDefault') }}</el-checkbox>
</template>
</div>
<span class="flex-1"></span>
<a v-if="state.super" href="javascript:;" class="a-line a-edit" @click="handleUpdate(scope.row)"><el-icon><Refresh /></el-icon>{{ scope.row.Version }}</a>
<a v-else href="javascript:;" class="a-line a-edit"><el-icon><Refresh /></el-icon>{{ scope.row.Version }}</a>
</p>
</div>
</div>
</template>
</el-table-column>
<el-table-column property="MaxGbTotal" :label="$t('server.relayFlow')" width="100">
<el-table-column property="ConnectionsRatio" :label="$t('server.relayConnection')" width="80">
<template #default="scope">
<template v-if="scope.row.MaxGbTotal == 0">--</template>
<p>
<template v-if="scope.row.Connections == 0">--</template>
<template v-else>{{ scope.row.Connections }}</template>
</p>
<p><strong>{{scope.row.ConnectionsRatio}}</strong></p>
</template>
</el-table-column>
<el-table-column property="Bandwidth" :label="$t('server.relaySpeed1')" width="100">
<template #default="scope">
<p>
<template v-if="scope.row.Bandwidth == 0">--</template>
<template v-else>{{ scope.row.Bandwidth }}Mbps</template>
</p>
<p><strong>{{scope.row.BandwidthRatio}}Mbps</strong></p>
</template>
</el-table-column>
<el-table-column property="DataEachMonth" :label="$t('server.relayFlow')" width="100">
<template #default="scope">
<template v-if="scope.row.DataEachMonth == 0">
<p>--</p>
<p>--</p>
</template>
<template v-else>
<p>{{ scope.row.MaxGbTotal }}GB</p>
<p><strong>{{ (scope.row.MaxGbTotalLastBytes/1024/1024/1024).toFixed(2) }}GB</strong></p>
<p>{{ scope.row.DataEachMonth }}GB</p>
<p><strong>{{ (scope.row.DataRemain/1024/1024/1024).toFixed(2) }}GB</strong></p>
</template>
</template>
</el-table-column>
<el-table-column property="MaxBandwidth" :label="$t('server.relaySpeed')" width="80">
<el-table-column property="BandwidthEach" :label="$t('server.relaySpeed')" width="80">
<template #default="scope">
<p>
<span v-if="scope.row.MaxBandwidth == 0">--</span>
<span v-else>{{ scope.row.MaxBandwidth }}Mbps</span>
<span v-if="scope.row.BandwidthEach == 0">--</span>
<span v-else>{{ scope.row.BandwidthEach }}Mbps</span>
</p>
<p>{{ scope.row.Delay }}ms</p>
</template>
</el-table-column>
<el-table-column property="MaxBandwidthTotal" :label="$t('server.relaySpeed1')" width="100">
<el-table-column v-if="state.super" property="Manageable" :label="$t('server.relayOper')" width="110">
<template #default="scope">
<p>
<template v-if="scope.row.MaxBandwidthTotal == 0">--</template>
<template v-else>{{ scope.row.MaxBandwidthTotal }}Mbps</template>
</p>
<p><strong>{{scope.row.BandwidthRatio}}mbps</strong></p>
</template>
</el-table-column>
<el-table-column property="ConnectionRatio" :label="$t('server.relayConnection')" width="80">
<template #default="scope">
<p>{{scope.row.MaxConnection}}</p>
<p><strong>{{scope.row.ConnectionRatio}}</strong></p>
</template>
</el-table-column>
<el-table-column v-if="state.super" property="Public" :label="$t('server.relayOper')" width="60">
<template #default="scope">
<p>
<a href="javascript:;" class="a-line" @click="handleExit(scope.row.Id)"><el-icon><Refresh /></el-icon>{{ $t('server.relayExit') }}</a>
</p>
<p>
<a href="javascript:;" class="a-line" @click="handleEdit(scope.row)"><el-icon><Edit /></el-icon>{{ $t('server.relayEdit') }}</a>
<el-button v-if="scope.row.Manageable" size="small" @click="handleExit(scope.row)"><el-icon><Refresh /></el-icon></el-button>
<el-button size="small" @click="handleEdit(scope.row)"><el-icon><Edit /></el-icon></el-button>
</p>
</template>
</el-table-column>
@@ -93,7 +96,7 @@
<div class="t-c">{{ $t('server.relaySetDefaultText') }}</div>
<Ids ref="domIds"></Ids>
<div class="t-c w-100 mgt-1">
<el-button @click="state.showSync = false">{{$t('common.cancel')}}</el-button>
<el-button @click="handleCancelSync">{{$t('common.cancel')}}</el-button>
<el-button type="primary" @click="handleSync">{{$t('common.confirm')}}</el-button>
</div>
</div>
@@ -138,13 +141,20 @@ export default {
}
});
const _getDefault = ()=>{
getDefault().then((res)=>{
state.syncData.Key = res.Key || '';
state.syncData.Value = res.Value || 0;
});
}
const handleEdit = (row)=>{
state.current = row;
state.showEdit = true;
}
const domIds = ref(null);
const handleShowSync = (id,proto)=>{
state.syncData.Key = id;
const handleShowSync = (row,proto)=>{
state.syncData.Key = row.Id;
state.syncData.Value = proto;
state.showSync = true;
}
@@ -155,10 +165,16 @@ export default {
}).then((res)=>{
state.showSync = false;
ElMessage.success(t('common.oper'));
_getDefault();
}).catch(()=>{
ElMessage.error(t('common.operFail'));
_getDefault();
//ElMessage.error(t('common.operFail'));
});
}
const handleCancelSync = ()=>{
state.showSync = false;
_getDefault();
}
const handleSync2Server = (row)=>{
row.Sync2Server = !row.Sync2Server;
@@ -170,13 +186,13 @@ export default {
ElMessage.error(t('common.operFail'));
});
}
const handleExit = (id)=>{
const handleExit = (row)=>{
ElMessageBox.confirm(t('server.relayExit'), t('common.confirm'), {
confirmButtonText: t('common.confirm'),
cancelButtonText: t('common.cancel'),
type: 'warning',
}).then(() => {
relayExit(id).then(res => {
relayExit(row.Id).then(res => {
ElMessage.success(t('common.oper'));
}).catch(()=>{
ElMessage.error(t('common.operFail'));
@@ -185,13 +201,14 @@ export default {
ElMessage.error(t('common.operFail'));
});
}
const handleUpdate = (id)=>{
const handleUpdate = (row)=>{
if(row.Manageable == false) return;
ElMessageBox.confirm(`${t('server.relayUpdate')} ${globalData.value.signin.Version}`,t('server.relayUpdate'), {
confirmButtonText: t('common.confirm'),
cancelButtonText: t('common.cancel'),
type: 'warning',
}).then(() => {
relayUpdate({Key:id,Value:globalData.value.signin.Version}).then(res => {
relayUpdate({Key:row.Id,Value:globalData.value.signin.Version}).then(res => {
ElMessage.success(t('common.oper'));
}).catch(()=>{
ElMessage.error(t('common.operFail'));
@@ -202,16 +219,15 @@ export default {
}
onMounted(()=>{
getDefault().then((res)=>{
state.syncData.Key = res.Key || '';
state.syncData.Value = res.Value || 0;
});
_getDefault();
});
onUnmounted(()=>{
clearTimeout(state.timer);
});
return {globalData,state,handleEdit,domIds,handleShowSync,handleSync,handleExit,handleUpdate,handleSync2Server}
return {globalData,state,
handleEdit,domIds,handleShowSync,handleSync,handleCancelSync,
handleExit,handleUpdate,handleSync2Server}
}
}
</script>
@@ -225,4 +241,9 @@ a.a-edit{
vertical-align middle
}
}
.logo{
margin-right:1rem;
height:4rem;
vertical-align:text-top;
}
</style>

View File

@@ -67,31 +67,29 @@
</div>
</template>
</el-table-column>
<el-table-column property="MaxGbTotal" :label="$t('server.relayFlow')" width="100">
<el-table-column property="ConnectionsRatio" :label="$t('server.relayConnection')" width="80">
<template #default="scope">
<span v-if="scope.row.MaxGbTotal == 0">--</span>
<span><strong>{{ scope.row.ConnectionsRatio }}</strong></span>
</template>
</el-table-column>
<el-table-column property="BandwidthEach" :label="$t('server.relaySpeed')" width="140">
<template #default="scope">
<p>
<span>{{ scope.row.BandwidthRatio }}Mbps</span>
<span> / </span>
<span v-if="scope.row.BandwidthEach == 0">--</span>
<span v-else>{{ scope.row.BandwidthEach }}Mbps</span>
</p>
</template>
</el-table-column>
<el-table-column property="DataEachMonth" :label="$t('server.relayFlow')" width="100">
<template #default="scope">
<span v-if="scope.row.DataEachMonth == 0">--</span>
<span v-else>
{{ (scope.row.MaxGbTotalLastBytes / 1024 / 1024 / 1024).toFixed(2) }}GB
{{ (scope.row.DataRemain / 1024 / 1024 / 1024).toFixed(2) }}GB
</span>
</template>
</el-table-column>
<el-table-column property="MaxBandwidth" :label="$t('server.relaySpeed')" width="80">
<template #default="scope">
<span v-if="scope.row.MaxBandwidth == 0">--</span>
<span v-else>{{ scope.row.MaxBandwidth }}Mbps</span>
</template>
</el-table-column>
<el-table-column property="MaxBandwidthTotal"
:label="$t('server.relaySpeed2')" width="80">
<template #default="scope">
<span>{{ scope.row.BandwidthRatio }}Mbps</span>
</template>
</el-table-column>
<el-table-column property="ConnectionRatio" :label="$t('server.relayConnection')" width="80">
<template #default="scope">
<span><strong>{{ scope.row.ConnectionRatio }}</strong></span>
</template>
</el-table-column>
<el-table-column property="Delay" :label="$t('server.relayDelay')" width="60">
<template #default="scope">
<span>{{ scope.row.Delay }}ms</span>
@@ -104,8 +102,8 @@
</el-table-column>
<el-table-column property="Oper" :label="$t('server.relayUse')" width="130">
<template #default="scope">
<el-button size="small" v-if="(scope.row.AllowProtocol & 1) == 1" @click="handleConnect(scope.row.Id, 1)">TCP</el-button>
<el-button size="small" v-if="(scope.row.AllowProtocol & 2) == 2" @click="handleConnect(scope.row.Id, 2)">UDP</el-button>
<el-button size="small" v-if="(scope.row.Protocol & 1) == 1" @click="handleConnect(scope.row, 1)">TCP</el-button>
<el-button size="small" v-if="(scope.row.Protocol & 2) == 2" @click="handleConnect(scope.row, 2)">UDP</el-button>
</template>
</el-table-column>
</el-table>
@@ -189,12 +187,12 @@ export default {
const handleNode = () => {
state.showNodes = true;
}
const handleConnect = (id, protocol) => {
const handleConnect = (row, protocol) => {
const json = {
FromMachineId: globalData.value.config.Client.Id,
TransactionId: state.transactionId,
ToMachineId: state.device.MachineId,
NodeId: id,
NodeId: row.NodeId,
Protocol: protocol
};
relayConnect(json).then(() => {ElMessage.success(t('common.oper')); }).catch(() => {ElMessage.success(t('common.operFail')); });

View File

@@ -20,6 +20,8 @@ RUN apt update \
EXPOSE 1802/tcp
EXPOSE 1802/udp
EXPOSE 1803/tcp
EXPOSE 1803/udp
EXPOSE 1804/tcp
EXPOSE 1804/udp

View File

@@ -20,6 +20,8 @@ RUN apt update \
EXPOSE 1802/tcp
EXPOSE 1802/udp
EXPOSE 1803/tcp
EXPOSE 1803/udp
EXPOSE 1804/tcp
EXPOSE 1804/udp
EXPOSE 1806/tcp

View File

@@ -10,6 +10,8 @@ RUN echo "https://mirrors.ustc.edu.cn/alpine/latest-stable/main/" > /etc/apk/rep
EXPOSE 1802/tcp
EXPOSE 1802/udp
EXPOSE 1803/tcp
EXPOSE 1803/udp
EXPOSE 1804/tcp
EXPOSE 1804/udp