重构中继

This commit is contained in:
snltty
2025-12-04 17:55:01 +08:00
parent 3b613a87de
commit 7acd88526c
29 changed files with 536 additions and 146 deletions

View File

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

View File

@@ -8,7 +8,7 @@ sidebar_position: 1
:::tip[说明]
#### 1.2、加入组织
#### 1.2、一起探讨
<a href="https://jq.qq.com/?_wv=1027&k=ucoIVfz4" target="_blank">你可以加入QQ群1121552990</a>
@@ -16,6 +16,9 @@ sidebar_position: 1
简单视频说明:<a href="https://www.bilibili.com/video/BV1PDpxz9EcW" target="_blank">B站视频</a>
<div style={{color:'red',fontSize:'20px'}}>郑重声明linker的目标是完全自由、受控不是傻瓜式工具需要具备一定的入手基础。</div>
--
:::

View File

@@ -162,6 +162,19 @@ namespace linker.messenger.api
Socks5Flow = 51,
[AccessDisplay("查看隧道流量")]
TunnelFlow = 52,
[AccessDisplay("导入中继节点")]
ImportRelayNode = 53,
[AccessDisplay("删除中继节点")]
RemoveRelayNode = 54,
[AccessDisplay("修改中继节点")]
UpdateRelayNode = 55,
[AccessDisplay("分享中继节点")]
ShareRelayNode = 56,
[AccessDisplay("重启中继节点")]
RebootRelayNode = 57,
[AccessDisplay("更新中继节点")]
UpgradeRelayNode = 58,
}
public sealed class AccessTextInfo

View File

@@ -61,6 +61,7 @@ namespace linker.messenger.relay.client
{
relayClientStore.SetDefaultNodeId(info.Data.Key);
relayClientStore.SetDefaultProtocol(info.Data.Value);
relayClientStore.Confirm();
}
}
@@ -70,7 +71,8 @@ namespace linker.messenger.relay.client
var resp = await messengerSender.SendReply(new MessageRequestWrap
{
Connection = signInClientState.Connection,
MessengerId = (ushort)RelayMessengerIds.Share,
MessengerId = (ushort)RelayMessengerIds.ShareForward,
Payload = serializer.Serialize(param.Content)
});
return resp.Code == MessageResponeCodes.OK ? serializer.Deserialize<string>(resp.Data.Span) : $"network error:{resp.Code}";
}
@@ -90,10 +92,44 @@ namespace linker.messenger.relay.client
{
Connection = signInClientState.Connection,
MessengerId = (ushort)RelayMessengerIds.Remove,
Payload = serializer.Serialize(int.Parse(param.Content))
Payload = serializer.Serialize(param.Content)
});
return resp.Code == MessageResponeCodes.OK ? serializer.Deserialize<string>(resp.Data.Span) : $"network error:{resp.Code}";
}
public async Task<bool> Update(ApiControllerParamsInfo param)
{
var resp = await messengerSender.SendReply(new MessageRequestWrap
{
Connection = signInClientState.Connection,
MessengerId = (ushort)RelayMessengerIds.UpdateForward,
Payload = serializer.Serialize(param.Content.DeJson<RelayServerNodeStoreInfo>())
});
return resp.Code == MessageResponeCodes.OK && resp.Data.Span.SequenceEqual(Helper.TrueArray);
}
public async Task<bool> Upgrade(ApiControllerParamsInfo param)
{
KeyValueInfo<string, string> info = param.Content.DeJson<KeyValueInfo<string, string>>();
var resp = await messengerSender.SendReply(new MessageRequestWrap
{
Connection = signInClientState.Connection,
MessengerId = (ushort)RelayMessengerIds.UpgradeForward,
Payload = serializer.Serialize(new KeyValuePair<string, string>(info.Key, info.Value))
});
return resp.Code == MessageResponeCodes.OK && resp.Data.Span.SequenceEqual(Helper.TrueArray);
}
public async Task<bool> Exit(ApiControllerParamsInfo param)
{
var resp = await messengerSender.SendReply(new MessageRequestWrap
{
Connection = signInClientState.Connection,
MessengerId = (ushort)RelayMessengerIds.ExitForward,
Payload = serializer.Serialize(param.Content)
});
return resp.Code == MessageResponeCodes.OK && resp.Data.Span.SequenceEqual(Helper.TrueArray);
}
}

View File

@@ -13,8 +13,39 @@ namespace linker.messenger.relay.messenger
/// </summary>
public class RelayClientMessenger : IMessenger
{
public RelayClientMessenger()
private readonly ISerializer serializer;
private readonly RelayServerNodeReportTransfer relayServerNodeReportTransfer;
public RelayClientMessenger(SignInServerCaching signCaching, ISerializer serializer, RelayServerNodeReportTransfer relayServerNodeReportTransfer)
{
this.serializer = serializer;
this.relayServerNodeReportTransfer = relayServerNodeReportTransfer;
}
[MessengerId((ushort)RelayMessengerIds.Share)]
public async Task Share(IConnection connection)
{
string masterKey = serializer.Deserialize<string>(connection.ReceiveRequestWrap.Payload.Span);
connection.Write(serializer.Serialize(await relayServerNodeReportTransfer.GetShareKey(masterKey)));
}
[MessengerId((ushort)RelayMessengerIds.Update)]
public async Task Update(IConnection connection)
{
RelayServerNodeStoreInfo info = serializer.Deserialize<RelayServerNodeStoreInfo>(connection.ReceiveRequestWrap.Payload.Span);
await relayServerNodeReportTransfer.Update(info).ConfigureAwait(false);
}
[MessengerId((ushort)RelayMessengerIds.Upgrade)]
public async Task Upgrade(IConnection connection)
{
KeyValuePair<string, string> info = serializer.Deserialize<KeyValuePair<string, string>>(connection.ReceiveRequestWrap.Payload.Span);
await relayServerNodeReportTransfer.Upgrade(info.Key, info.Value).ConfigureAwait(false);
}
[MessengerId((ushort)RelayMessengerIds.Exit)]
public async Task Exit(IConnection connection)
{
string masterKey = serializer.Deserialize<string>(connection.ReceiveRequestWrap.Payload.Span);
await relayServerNodeReportTransfer.Exit(masterKey).ConfigureAwait(false);
}
}
@@ -123,15 +154,16 @@ namespace linker.messenger.relay.messenger
}
[MessengerId((ushort)RelayMessengerIds.Share)]
public async Task Share(IConnection connection)
[MessengerId((ushort)RelayMessengerIds.ShareForward)]
public async Task ShareForward(IConnection connection)
{
string id = serializer.Deserialize<string>(connection.ReceiveRequestWrap.Payload.Span);
if (signCaching.TryGet(connection.Id, out SignCacheInfo from) == false || from.Super == false)
{
connection.Write(serializer.Serialize("need super key"));
return;
}
connection.Write(serializer.Serialize(relayServerNodeReportTransfer.Config.ShareKey));
connection.Write(serializer.Serialize(await relayServerNodeReportTransfer.GetShareKeyForward(id)));
}
[MessengerId((ushort)RelayMessengerIds.Import)]
public async Task Import(IConnection connection)
@@ -150,7 +182,7 @@ namespace linker.messenger.relay.messenger
[MessengerId((ushort)RelayMessengerIds.Remove)]
public async Task Remove(IConnection connection)
{
int id = serializer.Deserialize<int>(connection.ReceiveRequestWrap.Payload.Span);
string id = serializer.Deserialize<string>(connection.ReceiveRequestWrap.Payload.Span);
if (signCaching.TryGet(connection.Id, out SignCacheInfo from) == false || from.Super == false)
{
connection.Write(serializer.Serialize("need super key"));
@@ -160,7 +192,47 @@ namespace linker.messenger.relay.messenger
bool result = await relayServerNodeReportTransfer.Remove(id).ConfigureAwait(false);
connection.Write(serializer.Serialize(result ? string.Empty : "remove fail"));
}
[MessengerId((ushort)RelayMessengerIds.UpdateForward)]
public async Task UpdateForward(IConnection connection)
{
RelayServerNodeStoreInfo info = serializer.Deserialize<RelayServerNodeStoreInfo>(connection.ReceiveRequestWrap.Payload.Span);
if (signCaching.TryGet(connection.Id, out SignCacheInfo from) == false || from.Super == false)
{
connection.Write(Helper.FalseArray);
return;
}
bool result = await relayServerNodeReportTransfer.UpdateForward(info).ConfigureAwait(false);
connection.Write(result ? Helper.TrueArray : Helper.FalseArray);
}
[MessengerId((ushort)RelayMessengerIds.UpgradeForward)]
public async Task UpgradeForward(IConnection connection)
{
KeyValuePair<string, string> info = serializer.Deserialize<KeyValuePair<string, string>>(connection.ReceiveRequestWrap.Payload.Span);
if (signCaching.TryGet(connection.Id, out SignCacheInfo from) == false || from.Super == false)
{
connection.Write(Helper.FalseArray);
return;
}
bool result = await relayServerNodeReportTransfer.UpgradeForward(info.Key, info.Value).ConfigureAwait(false);
connection.Write(result ? Helper.TrueArray : Helper.FalseArray);
}
[MessengerId((ushort)RelayMessengerIds.ExitForward)]
public async Task ExitForward(IConnection connection)
{
string nodeid = serializer.Deserialize<string>(connection.ReceiveRequestWrap.Payload.Span);
if (signCaching.TryGet(connection.Id, out SignCacheInfo from) == false || from.Super == false)
{
connection.Write(Helper.FalseArray);
return;
}
bool result = await relayServerNodeReportTransfer.ExitForward(nodeid).ConfigureAwait(false);
connection.Write(result ? Helper.TrueArray : Helper.FalseArray);
}
[MessengerId((ushort)RelayMessengerIds.NodeReport)]

View File

@@ -15,9 +15,18 @@
Report = 2135,
Share = 2136,
Import = 2137,
Remove = 2138,
ShareForward = 2137,
Import = 2138,
Remove = 2139,
UpdateForward = 2140,
Update = 2141,
ExitForward = 2142,
Exit = 2143,
UpgradeForward = 2144,
Upgrade = 2145,
Max = 2199
}

View File

@@ -74,6 +74,8 @@ namespace linker.messenger.relay.server
public double BandwidthRatio { get; set; }
public IPEndPoint[] Masters { get; set; } = Array.Empty<IPEndPoint>();
public string Domain { get; set; } = string.Empty;
}
public sealed class RelayServerNodeStoreInfo : RelayServerNodeReportInfo

View File

@@ -6,8 +6,9 @@
public Task<RelayServerNodeStoreInfo> GetByNodeId(string nodeId);
public Task<bool> Add(RelayServerNodeStoreInfo info);
public Task<bool> Report(RelayServerNodeReportInfo info);
public Task<bool> Delete(int id);
public Task<bool> Delete(string nodeId);
public Task<bool> Update(RelayServerNodeStoreInfo info);
}
}

View File

@@ -2,6 +2,7 @@
using linker.libs.extends;
using linker.libs.timer;
using linker.messenger.relay.messenger;
using System;
using System.Net;
using System.Net.Sockets;
@@ -93,6 +94,32 @@ namespace linker.messenger.relay.server
return true;
}
public async Task<string> GetShareKeyForward(string nodeId)
{
RelayServerNodeStoreInfo store = await relayServerNodeStore.GetByNodeId(nodeId);
if (store != null && store.Manageable && relayServerConnectionTransfer.TryGet(ConnectionSideType.Node, nodeId, out var connection))
{
var resp = await messengerSender.SendReply(new MessageRequestWrap
{
Connection = connection,
MessengerId = (ushort)RelayMessengerIds.Share,
Payload = serializer.Serialize(store.MasterKey)
});
if (resp.Code == MessageResponeCodes.OK)
{
return serializer.Deserialize<string>(resp.Data.Span);
}
}
return string.Empty;
}
public async Task<string> GetShareKey(string masterKey)
{
if (masterKey != Config.MasterKey) return string.Empty;
return Config.ShareKey;
}
public async Task<string> Import(string shareKey)
{
try
@@ -117,16 +144,110 @@ namespace linker.messenger.relay.server
}
return string.Empty;
}
public async Task<bool> Remove(int id)
public async Task<bool> Remove(string nodeId)
{
return await relayServerNodeStore.Delete(id).ConfigureAwait(false);
if (nodeId == Config.NodeId) return false;
return await relayServerNodeStore.Delete(nodeId).ConfigureAwait(false);
}
public async Task<bool> UpdateForward(RelayServerNodeStoreInfo info)
{
RelayServerNodeStoreInfo store = await relayServerNodeStore.GetByNodeId(info.NodeId);
if (store != null && store.Manageable && relayServerConnectionTransfer.TryGet(ConnectionSideType.Node, info.NodeId, out var connection))
{
info.MasterKey = store.MasterKey;
await messengerSender.SendOnly(new MessageRequestWrap
{
Connection = connection,
MessengerId = (ushort)RelayMessengerIds.Update,
Payload = serializer.Serialize(info)
});
}
return await relayServerNodeStore.Update(info).ConfigureAwait(false);
}
public async Task<bool> Update(RelayServerNodeStoreInfo info)
{
if (info.MasterKey != Config.MasterKey) return false;
Config.Connections = info.Connections;
Config.MasterKey = info.MasterKey;
Config.Bandwidth = info.Bandwidth;
Config.Protocol = info.Protocol;
Config.DataEachMonth = info.DataEachMonth;
Config.DataRemain = info.DataRemain;
Config.Logo = info.Logo;
Config.Name = info.Name;
Config.Url = info.Url;
Config.Domain = info.Domain;
relayServerConfigStore.Confirm();
return true;
}
public async Task<bool> UpgradeForward(string nodeId, string version)
{
RelayServerNodeStoreInfo store = await relayServerNodeStore.GetByNodeId(nodeId);
if (store != null && store.Manageable && relayServerConnectionTransfer.TryGet(ConnectionSideType.Node, nodeId, out var connection))
{
await messengerSender.SendOnly(new MessageRequestWrap
{
Connection = connection,
MessengerId = (ushort)RelayMessengerIds.Update,
Payload = serializer.Serialize(new KeyValuePair<string, string>(store.MasterKey, version))
});
return true;
}
return false;
}
public async Task<bool> Upgrade(string masterKey, string version)
{
if (masterKey != Config.MasterKey) return false;
Helper.AppUpdate(version);
return true;
}
public async Task<bool> ExitForward(string nodeId)
{
RelayServerNodeStoreInfo store = await relayServerNodeStore.GetByNodeId(nodeId);
if (store != null && store.Manageable && relayServerConnectionTransfer.TryGet(ConnectionSideType.Node, nodeId, out var connection))
{
await messengerSender.SendOnly(new MessageRequestWrap
{
Connection = connection,
MessengerId = (ushort)RelayMessengerIds.Update,
Payload = serializer.Serialize(new KeyValuePair<string, string>(store.MasterKey, nodeId))
});
return true;
}
return false;
}
public async Task<bool> Exit(string masterKey)
{
if (masterKey != Config.MasterKey) return false;
Helper.AppExit(-1);
return true;
}
public async Task<List<RelayServerNodeStoreInfo>> GetNodes(bool validated, string userid, string machineId)
{
var nodes = (await relayServerWhiteListStore.GetNodes(userid, machineId)).Where(c => c.Bandwidth >= 0).SelectMany(c => c.Nodes);
var result = (await relayServerNodeStore.GetAll())
var list = await relayServerNodeStore.GetAll();
list.ForEach(c =>
{
c.MasterKey = string.Empty;
});
var result = list
.Where(c => validated || Environment.TickCount64 - c.LastTicks < 15000)
.Where(c =>
{
@@ -146,7 +267,13 @@ namespace linker.messenger.relay.server
}
public async Task<List<RelayServerNodeStoreInfo>> GetPublicNodes()
{
var result = (await relayServerNodeStore.GetAll())
var list = await relayServerNodeStore.GetAll();
list.ForEach(c =>
{
c.MasterKey = string.Empty;
});
var result = list
.Where(c => Environment.TickCount64 - c.LastTicks < 15000)
.Where(c => c.Public)
.OrderByDescending(c => c.LastTicks);
@@ -227,7 +354,7 @@ namespace linker.messenger.relay.server
BandwidthRatio = Math.Round(diff / 5, 2),
Version = VersionHelper.Version,
Masters = connections.Select(c => c.Address).ToArray(),
MasterKey = config.MasterKey,
MasterKey = config.MasterKey,
};
byte[] memory = serializer.Serialize(info);
var tasks = connections.Select(c => messengerSender.SendOnly(new MessageRequestWrap

View File

@@ -63,8 +63,12 @@ namespace linker.messenger.relay.server
return serializer.Deserialize<RelayMessageInfo>(crypto.Decode(buffer, 0, length).Span);
}
catch (Exception)
catch (Exception ex)
{
if (LoggerHelper.Instance.LoggerLevel <= LoggerTypes.DEBUG)
{
LoggerHelper.Instance.Error(ex);
}
}
finally
{
@@ -93,7 +97,7 @@ namespace linker.messenger.relay.server
if (relayCache == null)
{
if (LoggerHelper.Instance.LoggerLevel <= LoggerTypes.DEBUG)
LoggerHelper.Instance.Error($"relay {relayMessage.Type} get cache fail,flowid:{relayMessage.FlowId}");
LoggerHelper.Instance.Error($"relay server {relayMessage.Type} get cache fail,flowid:{relayMessage.FlowId}");
await socket.SendAsync(Helper.FalseArray).ConfigureAwait(false);
socket.SafeClose();
return;
@@ -102,7 +106,7 @@ namespace linker.messenger.relay.server
if (relayMessage.Type == RelayMessengerType.Ask && relayServerNodeTransfer.Validate(relayCache) == false)
{
if (LoggerHelper.Instance.LoggerLevel <= LoggerTypes.DEBUG)
LoggerHelper.Instance.Error($"relay {relayMessage.Type} validate false,flowid:{relayMessage.FlowId}");
LoggerHelper.Instance.Error($"relay server {relayMessage.Type} validate false,flowid:{relayMessage.FlowId}");
await socket.SendAsync(Helper.FalseArray).ConfigureAwait(false);
socket.SafeClose();
return;
@@ -122,14 +126,17 @@ namespace linker.messenger.relay.server
}
TaskCompletionSource<Socket> tcs = new TaskCompletionSource<Socket>(TaskCreationOptions.RunContinuationsAsynchronously);
Socket answerSocket = null;
IPEndPoint fromep = socket.RemoteEndPoint as IPEndPoint,toep = null;
try
{
await socket.SendAsync(Helper.TrueArray).ConfigureAwait(false);
relayDic.TryAdd(relayCache.FlowId, tcs);
Socket answerSocket = await tcs.Task.WaitAsync(TimeSpan.FromMilliseconds(15000)).ConfigureAwait(false);
answerSocket = await tcs.Task.WaitAsync(TimeSpan.FromMilliseconds(15000)).ConfigureAwait(false);
await answerSocket.SendAsync(Helper.TrueArray).ConfigureAwait(false);
toep = answerSocket.RemoteEndPoint as IPEndPoint;
LoggerHelper.Instance.Error($"relay start {socket.RemoteEndPoint} to {answerSocket.RemoteEndPoint}");
LoggerHelper.Instance.Info($"relay server start {fromep} to {toep}");
string flowKey = relayMessage.Type == RelayMessengerType.Ask ? $"{relayMessage.FromId}->{relayMessage.ToId}" : $"{relayMessage.ToId}->{relayMessage.FromId}";
RelayTrafficCacheInfo trafficCacheInfo = new RelayTrafficCacheInfo { Cache = relayCache, Sendt = 0, Limit = new RelaySpeedLimit(), Key = flowKey };
@@ -138,26 +145,26 @@ namespace linker.messenger.relay.server
await Task.WhenAll(CopyToAsync(trafficCacheInfo, socket, answerSocket), CopyToAsync(trafficCacheInfo, answerSocket, socket)).ConfigureAwait(false);
relayServerNodeTransfer.DecrementConnectionNum();
relayServerNodeTransfer.RemoveTrafficCache(trafficCacheInfo);
LoggerHelper.Instance.Error($"relay end {socket.RemoteEndPoint} to {answerSocket.RemoteEndPoint}");
}
catch (Exception ex)
{
tcs.TrySetResult(null);
if (LoggerHelper.Instance.LoggerLevel <= LoggerTypes.DEBUG)
LoggerHelper.Instance.Error($"{ex},flowid:{relayMessage.FlowId}");
LoggerHelper.Instance.Error($"relay server error {ex},flowid:{relayMessage.FlowId}");
}
finally
{
LoggerHelper.Instance.Info($"relay server end {fromep} to {toep}");
relayDic.TryRemove(relayCache.FlowId, out _);
socket.SafeClose();
socket?.SafeClose();
answerSocket?.SafeClose();
}
}
catch (Exception ex)
{
if (LoggerHelper.Instance.LoggerLevel <= LoggerTypes.DEBUG)
LoggerHelper.Instance.Error(ex);
socket.SafeClose();
socket?.SafeClose();
}
}
private async Task CopyToAsync(RelayTrafficCacheInfo trafficCacheInfo, Socket source, Socket destination)

View File

@@ -31,7 +31,7 @@ namespace linker.tunnel.transport
public bool SSL => true;
public bool DisableSSL => false;
public bool DisableSSL => true;
public byte Order => 0;
@@ -70,21 +70,21 @@ namespace linker.tunnel.transport
List<RelayServerNodeStoreInfo> nodes = ask.Nodes;
if (ask.Nodes.Count == 0)
{
throw new Exception("relay ask fail,no relay nodes");
throw new Exception("relay client ask fail,no relay nodes");
}
//连接中继节点服务器
Socket socket = await ConnectNodeServer(tunnelTransportInfo, ask).ConfigureAwait(false);
if(socket == null)
{
throw new Exception("connect relay node server fail");
throw new Exception("relay client connect node server fail");
}
tunnelTransportInfo.TransactionTag = ask.Info.ToJson();
//让对方确认中继
if (await tunnelMessengerAdapter.SendConnectBegin(tunnelTransportInfo).ConfigureAwait(false) == false)
{
throw new Exception("relay begin fail");
throw new Exception("relay client begin fail");
}
//成功建立连接,
@@ -182,7 +182,7 @@ namespace linker.tunnel.transport
}
if (LoggerHelper.Instance.LoggerLevel <= LoggerTypes.DEBUG)
LoggerHelper.Instance.Debug($"connect relay server {ep}");
LoggerHelper.Instance.Debug($"relay client connect server {ep}");
//连接中继服务器
Socket socket = new Socket(ep.AddressFamily, SocketType.Stream, System.Net.Sockets.ProtocolType.Tcp);
@@ -191,7 +191,7 @@ namespace linker.tunnel.transport
await socket.ConnectAsync(ep).WaitAsync(TimeSpan.FromMilliseconds(5000)).ConfigureAwait(false);
if (LoggerHelper.Instance.LoggerLevel <= LoggerTypes.DEBUG)
{
LoggerHelper.Instance.Debug($"relay connected {ep}");
LoggerHelper.Instance.Debug($"relay client connected {ep}");
}
//建立关联
@@ -254,10 +254,15 @@ namespace linker.tunnel.transport
await socket.SendAsync(buffer.Memory.Slice(0, sendBytes.Length + 5)).ConfigureAwait(false);
int length = await socket.ReceiveAsync(buffer.Memory.Slice(0, 1)).AsTask().WaitAsync(TimeSpan.FromMilliseconds(5000)).ConfigureAwait(false);
return length == 1 && buffer.Memory.Span[0] == 0;
return length == 1 && buffer.Memory.Slice(0, 1).Span.SequenceEqual(Helper.TrueArray);
}
catch (Exception)
catch (Exception ex)
{
if (LoggerHelper.Instance.LoggerLevel <= LoggerTypes.DEBUG)
{
LoggerHelper.Instance.Error(ex);
}
}
return false;
}
@@ -268,7 +273,7 @@ namespace linker.tunnel.transport
{
if (tunnelTransportInfo.SSL && certificate == null)
{
LoggerHelper.Instance.Error($"{Name}->ssl Certificate not found");
LoggerHelper.Instance.Error($"relay client {Name}->ssl Certificate not found");
await tunnelMessengerAdapter.SendConnectFail(tunnelTransportInfo).ConfigureAwait(false);
return;
}
@@ -301,7 +306,7 @@ namespace linker.tunnel.transport
{
if (LoggerHelper.Instance.LoggerLevel <= LoggerTypes.DEBUG)
{
LoggerHelper.Instance.Error($"relay connect server {ep} {ex}");
LoggerHelper.Instance.Error($"relay client connect server {ep} {ex}");
}
}
}
@@ -349,7 +354,7 @@ namespace linker.tunnel.transport
{
if (LoggerHelper.Instance.LoggerLevel <= LoggerTypes.DEBUG)
{
LoggerHelper.Instance.Error($"relay wait ssl {ex}");
LoggerHelper.Instance.Error($"relay client wait ssl {ex}");
}
socket.SafeClose();
}

View File

@@ -52,7 +52,7 @@ namespace linker.messenger.serializer.memorypack
value = null;
return;
}
value = new AccessUpdateInfo() ;
value = new AccessUpdateInfo();
reader.TryReadObjectHeader(out byte count);
value.FromMachineId = reader.ReadValue<string>();
value.ToMachineId = reader.ReadValue<string>();
@@ -74,10 +74,13 @@ namespace linker.messenger.serializer.memorypack
[MemoryPackInclude]
BitArray Access => info.Access;
[MemoryPackInclude]
bool FullAccess => info.FullAccess;
[MemoryPackConstructor]
SerializableAccessBitsUpdateInfo(string fromMachineId, string toMachineId, BitArray access)
SerializableAccessBitsUpdateInfo(string fromMachineId, string toMachineId, BitArray access, bool fullAccess)
{
var info = new AccessBitsUpdateInfo { FromMachineId = fromMachineId, ToMachineId = toMachineId, Access = access };
var info = new AccessBitsUpdateInfo { FromMachineId = fromMachineId, ToMachineId = toMachineId, Access = access, FullAccess = fullAccess };
this.info = info;
}
@@ -110,10 +113,13 @@ namespace linker.messenger.serializer.memorypack
value = new AccessBitsUpdateInfo();
reader.TryReadObjectHeader(out byte count);
value.FromMachineId = reader.ReadValue<string>();
value.FromMachineId = reader.ReadValue<string>();
value.ToMachineId = reader.ReadValue<string>();
value.Access = reader.ReadValue<BitArray>();
if (count > 3)
{
value.FullAccess = reader.ReadValue<bool>();
}
}
}

View File

@@ -251,10 +251,12 @@ namespace linker.messenger.serializer.memorypack
double BandwidthRatio => info.BandwidthRatio;
[MemoryPackInclude]
IPEndPoint[] Masters => info.Masters;
[MemoryPackInclude]
string Domain => info.Domain;
[MemoryPackConstructor]
SerializableRelayServerNodeReportInfo(string nodeId, string name, TunnelProtocolType protocol, int connections, int bandwidth, int dataEachMonth,
long dataRemain, string url, string logo, string masterKey, string version, int connectionsRatio, double bandwidthRatio, IPEndPoint[] masters)
long dataRemain, string url, string logo, string masterKey, string version, int connectionsRatio, double bandwidthRatio, IPEndPoint[] masters, string domain)
{
var info = new RelayServerNodeReportInfo
{
@@ -271,7 +273,8 @@ namespace linker.messenger.serializer.memorypack
Version = version,
ConnectionsRatio = connectionsRatio,
BandwidthRatio = bandwidthRatio,
Masters = masters
Masters = masters,
Domain = domain
};
this.info = info;
}
@@ -319,6 +322,7 @@ namespace linker.messenger.serializer.memorypack
value.ConnectionsRatio = reader.ReadValue<int>();
value.BandwidthRatio = reader.ReadValue<double>();
value.Masters = reader.ReadValue<IPEndPoint[]>();
value.Domain = reader.ReadValue<string>();
}
}
@@ -357,7 +361,9 @@ namespace linker.messenger.serializer.memorypack
[MemoryPackInclude]
double BandwidthRatio => info.BandwidthRatio;
[MemoryPackInclude]
IPEndPoint[] Servers => info.Masters;
IPEndPoint[] Masters => info.Masters;
[MemoryPackInclude]
string Domain => info.Domain;
[MemoryPackInclude]
@@ -376,7 +382,7 @@ namespace linker.messenger.serializer.memorypack
[MemoryPackConstructor]
SerializableRelayServerNodeStoreInfo(string nodeId, string name, TunnelProtocolType protocol, int connections, int bandwidth, int dataEachMonth,
long dataRemain, string url, string logo, string masterKey, string version, int connectionsRatio, double bandwidthRatio, IPEndPoint[] servers,
long dataRemain, string url, string logo, string masterKey, string version, int connectionsRatio, double bandwidthRatio, IPEndPoint[] masters, string domain,
int id, string host, int bandwidthEachConnection, bool Public, long lastTicks, bool manageable)
{
var info = new RelayServerNodeStoreInfo
@@ -394,7 +400,8 @@ namespace linker.messenger.serializer.memorypack
Version = version,
ConnectionsRatio = connectionsRatio,
BandwidthRatio = bandwidthRatio,
Masters = servers,
Masters = masters,
Domain = domain,
Id = id,
Host = host,
BandwidthEach = bandwidthEachConnection,
@@ -448,6 +455,7 @@ namespace linker.messenger.serializer.memorypack
value.ConnectionsRatio = reader.ReadValue<int>();
value.BandwidthRatio = reader.ReadValue<double>();
value.Masters = reader.ReadValue<IPEndPoint[]>();
value.Domain = reader.ReadValue<string>();
value.Id = reader.ReadValue<int>();
value.Host = reader.ReadValue<string>();
value.BandwidthEach = reader.ReadValue<int>();

View File

@@ -244,11 +244,12 @@ namespace linker.messenger.serializer.memorypack
[MemoryPackInclude]
uint FlowId => tunnelTransportInfo.FlowId;
//[MemoryPackInclude]
//string TransactionTag => tunnelTransportInfo.TransactionTag;
[MemoryPackInclude]
string TransactionTag => tunnelTransportInfo.TransactionTag;
[MemoryPackConstructor]
SerializableTunnelTransportInfo(TunnelTransportWanPortInfo local, TunnelTransportWanPortInfo remote, string transactionId, TunnelProtocolType transportType, string transportName, TunnelDirection direction, bool ssl, byte bufferSize, uint flowid/*, string transactionTag*/)
SerializableTunnelTransportInfo(TunnelTransportWanPortInfo local, TunnelTransportWanPortInfo remote, string transactionId,
TunnelProtocolType transportType, string transportName, TunnelDirection direction, bool ssl, byte bufferSize, uint flowid, string transactionTag)
{
var tunnelTransportInfo = new TunnelTransportInfo
{
@@ -261,7 +262,7 @@ namespace linker.messenger.serializer.memorypack
SSL = ssl,
BufferSize = bufferSize,
FlowId = flowid,
// TransactionTag = transactionTag
TransactionTag = transactionTag
};
this.tunnelTransportInfo = tunnelTransportInfo;
}
@@ -293,8 +294,19 @@ namespace linker.messenger.serializer.memorypack
return;
}
var wrapped = reader.ReadPackable<SerializableTunnelTransportInfo>();
value = wrapped.tunnelTransportInfo;
value = new TunnelTransportInfo();
reader.TryReadObjectHeader(out byte count);
value.Local = reader.ReadValue<TunnelTransportWanPortInfo>();
value.Remote = reader.ReadValue<TunnelTransportWanPortInfo>();
value.TransactionId = reader.ReadValue<string>();
value.TransportType = reader.ReadValue<TunnelProtocolType>();
value.TransportName = reader.ReadValue<string>();
value.Direction = reader.ReadValue<TunnelDirection>();
value.SSL = reader.ReadValue<bool>();
value.BufferSize = reader.ReadValue<byte>();
value.FlowId = reader.ReadValue<uint>();
if (count > 9)
value.TransactionTag = reader.ReadValue<string>();
}
}

View File

@@ -25,9 +25,9 @@ namespace linker.messenger.store.file.relay
return await Task.FromResult(true).ConfigureAwait(false);
}
public async Task<bool> Delete(int id)
public async Task<bool> Delete(string nodeId)
{
return await Task.FromResult(liteCollection.Delete(id)).ConfigureAwait(false);
return await Task.FromResult(liteCollection.DeleteMany(c => c.NodeId == nodeId) > 0).ConfigureAwait(false);
}
public async Task<List<RelayServerNodeStoreInfo>> GetAll()
@@ -59,7 +59,18 @@ namespace linker.messenger.store.file.relay
MasterKey = info.MasterKey,
Masters = info.Masters,
//是我初始化的,可以管理
Manageable = false//info.MasterKey == md5
Manageable = info.MasterKey == md5
}, c => c.NodeId == info.NodeId);
return await Task.FromResult(length > 0).ConfigureAwait(false);
}
public async Task<bool> Update(RelayServerNodeStoreInfo info)
{
int length = liteCollection.UpdateMany(p => new RelayServerNodeStoreInfo
{
DataEachMonth = info.DataEachMonth,
Public = info.Public,
}, c => c.NodeId == info.NodeId);
return await Task.FromResult(length > 0).ConfigureAwait(false); ;

View File

@@ -8,9 +8,9 @@
"name": "linker.web",
"version": "0.1.0",
"dependencies": {
"@element-plus/icons-vue": "^2.3.1",
"@element-plus/icons-vue": "^2.3.2",
"core-js": "^3.38.0",
"element-plus": "^2.8.0",
"element-plus": "^2.11.9",
"moment": "^2.30.1",
"vue": "^3.4.38",
"vue-i18n": "^11.0.1",
@@ -1710,8 +1710,9 @@
}
},
"node_modules/@element-plus/icons-vue": {
"version": "2.3.1",
"license": "MIT",
"version": "2.3.2",
"resolved": "https://registry.npmjs.org/@element-plus/icons-vue/-/icons-vue-2.3.2.tgz",
"integrity": "sha512-OzIuTaIfC8QXEPmJvB4Y4kw34rSXdCJzxcD1kFStBvr8bK6X1zQAYDo0CNMjojnfTqRQCJ0I7prlErcoRiET2A==",
"peerDependencies": {
"vue": "^3.2.0"
}
@@ -2114,8 +2115,9 @@
"license": "MIT"
},
"node_modules/@types/lodash": {
"version": "4.17.0",
"license": "MIT"
"version": "4.17.21",
"resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.21.tgz",
"integrity": "sha512-FOvQ0YPD5NOfPgMzJihoT+Za5pdkDJWcbpuj1DjaKZIr/gxodQjY/uWEFlTNqW2ugXHUiL8lRQgw63dzKHZdeQ=="
},
"node_modules/@types/lodash-es": {
"version": "4.17.12",
@@ -4536,8 +4538,9 @@
"license": "MIT"
},
"node_modules/dayjs": {
"version": "1.11.10",
"license": "MIT"
"version": "1.11.19",
"resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.19.tgz",
"integrity": "sha512-t5EcLVS6QPBNqM2z8fakk/NKel+Xzshgt8FFKAn+qwlD1pzZWxh0nVCrvFK7ZDb6XucZeF9z8C7CBWTRIVApAw=="
},
"node_modules/debounce": {
"version": "1.2.1",
@@ -4896,22 +4899,22 @@
"license": "ISC"
},
"node_modules/element-plus": {
"version": "2.8.0",
"license": "MIT",
"version": "2.11.9",
"resolved": "https://registry.npmjs.org/element-plus/-/element-plus-2.11.9.tgz",
"integrity": "sha512-yTckX+fMGDGiBHVL1gpwfmjEc8P8OwuyU5ZX3f4FhMy2OdC2Y+OwQYWUXmuB+jFMukuSdnGYXYgHq6muBjSxTg==",
"dependencies": {
"@ctrl/tinycolor": "^3.4.1",
"@element-plus/icons-vue": "^2.3.1",
"@element-plus/icons-vue": "^2.3.2",
"@floating-ui/dom": "^1.0.1",
"@popperjs/core": "npm:@sxzz/popperjs-es@^2.11.7",
"@types/lodash": "^4.14.182",
"@types/lodash-es": "^4.17.6",
"@types/lodash": "^4.17.20",
"@types/lodash-es": "^4.17.12",
"@vueuse/core": "^9.1.0",
"async-validator": "^4.2.5",
"dayjs": "^1.11.3",
"escape-html": "^1.0.3",
"dayjs": "^1.11.19",
"lodash": "^4.17.21",
"lodash-es": "^4.17.21",
"lodash-unified": "^1.0.2",
"lodash-unified": "^1.0.3",
"memoize-one": "^6.0.0",
"normalize-wheel-es": "^1.2.0"
},
@@ -5020,6 +5023,7 @@
},
"node_modules/escape-html": {
"version": "1.0.3",
"dev": true,
"license": "MIT"
},
"node_modules/escape-string-regexp": {

View File

@@ -7,9 +7,9 @@
"build": "vue-cli-service build"
},
"dependencies": {
"@element-plus/icons-vue": "^2.3.1",
"@element-plus/icons-vue": "^2.3.2",
"core-js": "^3.38.0",
"element-plus": "^2.8.0",
"element-plus": "^2.11.9",
"moment": "^2.30.1",
"vue": "^3.4.38",
"vue-i18n": "^11.0.1",

View File

@@ -12,12 +12,21 @@ export const setRelaySubscribe = () => {
export const relayConnect = (data) => {
return sendWebsocketMsg('relay/Connect', data);
}
export const relayEdit = (data) => {
return sendWebsocketMsg('relay/edit', data);
export const relayUpdate= (data) => {
return sendWebsocketMsg('relay/update', data);
}
export const relayUpgrade= (data) => {
return sendWebsocketMsg('relay/upgrade', data);
}
export const relayExit = (id) => {
return sendWebsocketMsg('relay/Exit', id);
}
export const relayUpdate = (id) => {
return sendWebsocketMsg('relay/Update', id);
export const relayRemove = (id) => {
return sendWebsocketMsg('relay/Remove', id);
}
export const relayImport = (data) => {
return sendWebsocketMsg('relay/Import', data);
}
export const relayShare = (id) => {
return sendWebsocketMsg('relay/Share', id);
}

View File

@@ -148,7 +148,9 @@ a.a-line {
.mgb-0 {
margin-bottom: 0 !important;
}
.mgb-1 {
margin-bottom: 1rem;
}
.mgb-3 {
margin-bottom: 3rem;
}

View File

@@ -212,6 +212,9 @@ export default {
'server.relayExit': 'Restart',
'server.relayUpdate': 'Update',
'server.relayEdit': 'Edit',
'server.relayRemove': 'Remove',
'server.relayImport': 'Import relay node',
'server.relayShare': 'Share relay node',
'server.cdkeySecretKey': 'Cdkey secretKey',
'server.cdkeyText': 'The cdkey manager can be used when the key is correct',

View File

@@ -290,7 +290,7 @@ export default {
'server.relayName': '名称',
'server.relayFlow': '月流量',
'server.relayFlowLast': '剩余流量',
'server.relaySpeed': '带宽',
'server.relaySpeed': '单链带宽',
'server.relaySpeed1': '总带宽',
'server.relaySpeed2': '速率',
'server.relayConnection': '连接数',
@@ -308,6 +308,9 @@ export default {
'server.relayExit': '重启',
'server.relayUpdate': '更新',
'server.relayEdit': '编辑',
'server.relayRemove': '删除',
'server.relayImport': '导入中继节点',
'server.relayShare': '分享中继节点',
'server.cdkeySecretKey': 'Cdkey密钥',
'server.cdkeyText': '密钥正确时可管理cdkey',

View File

@@ -9,7 +9,7 @@ const routes = [
{
path: '/full/index.html',
name: 'FullIndex',
meta: { title: 'head.home',access:'FullIndex',icon:'home.svg' },
meta: { title: 'head.home',access:'FullManager',icon:'home.svg' },
component: () => import('@/views/layout/full/list/Index.vue')
},
{

View File

@@ -6,6 +6,9 @@
<el-col :span="8" v-if="globalData.config.Client.FullAccess">
<el-checkbox v-model="state.full" ><span class="red">满权限(顶级管理权)</span></el-checkbox>
</el-col>
<el-col :span="6">
<el-input size="small" v-model="state.search"></el-input>
</el-col>
</el-row>
<div class="access-wrap scrollbar" :style="{height:`${state.height}rem`}">
<el-checkbox-group v-model="state.checkList" @change="handleCheckedChange">
@@ -27,16 +30,17 @@ export default {
setup(props) {
const globalData = injectGlobalData();
const exclude = ['ExternalShow','Cdkey']
const access = computed(()=>{
const json = globalData.value.config.Client.Accesss;
return Object.keys(json).reduce((arr,key,index)=>{
if(globalData.value.hasAccess(key)){
if(globalData.value.hasAccess(key) && !exclude.includes(key)){
const value = json[key];
value.Key = key;
arr.push(value);
}
return arr;
},[]);
},[]).filter(c=>c.Text.includes(state.search));
});
const state = reactive({
@@ -63,7 +67,9 @@ export default {
],
checkAll:false,
full:false,
isIndeterminate:false
isIndeterminate:false,
search:''
});
const getValue = ()=>{

View File

@@ -88,7 +88,6 @@ export const provideDevices = () => {
getSignInList(devices.page.Request).then((res) => {
devices.page.Request = res.Request;
devices.page.Count = res.Count;
console.log(res);
for (let j in res.List) {
Object.assign(res.List[j], {
showDel: machineId.value != res.List[j].MachineId && res.List[j].Connected == false,

View File

@@ -106,13 +106,14 @@ export default {
const handleShowAccess = (row,access)=>{
const rowAccess = row.hook_accesss || '';
const myAccess = globalData.value.config.Client.AccessBits;
let maxLength = Math.max(myAccess.length,rowAccess.length);
let myValue = myAccess.padEnd(maxLength,'0').split('');
let rowValue = rowAccess.padEnd(maxLength,'0').split('');
let myValue = myAccess.padEnd(maxLength,'0').split('').map(c=>+c);
let rowValue = rowAccess.padEnd(maxLength,'0').split('').map(c=>+c);
return row.showAccess && access.Access
&& myValue.map((v,i)=>{
return (rowValue[i] == '1' && v == '1') || rowValue[i] == '0';
}).filter(c=>c).length > 0;
return (rowValue[i] + v >=1 && v == 1);
}).filter(c=>!c).length == 0;
}
const handleAccess = (row)=>{
devices.deviceInfo = row;

View File

@@ -49,7 +49,7 @@
import { ElMessage } from 'element-plus';
import { reactive, ref, watch } from 'vue'
import { useI18n } from 'vue-i18n';
import { relayEdit } from '@/apis/relay';
import { relayUpdate } from '@/apis/relay';
import { Refresh } from '@element-plus/icons-vue'
export default {
props: ['data','modelValue'],
@@ -57,22 +57,12 @@ export default {
components:{Refresh},
setup(props,{emit}) {
const {t} = useI18n();
const json = JSON.parse(JSON.stringify(props.data));
json.AllowTcp = (json.Protocol & 1) == 1;
json.AllowUdp = (json.Protocol & 2) == 2;
const state = reactive({
show:true,
ruleForm:{
Id:props.data.Id,
Name:props.data.Name,
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,
Logo:props.data.Logo,
AllowTcp:(props.data.Protocol & 1) == 1,
AllowUdp:(props.data.Protocol & 2) == 2,
},
ruleForm:json,
rules:{
}
});
@@ -95,7 +85,7 @@ export default {
const json = JSON.parse(JSON.stringify(state.ruleForm));
json.Protocol = (json.AllowTcp ? 1 : 0) | (json.AllowUdp ? 2 : 0);
relayEdit(json).then((res)=>{
relayUpdate(json).then((res)=>{
if(res){
ElMessage.success(t('common.oper'));
state.show = false;

View File

@@ -2,6 +2,17 @@
<div>
<el-dialog v-model="state.show" :title="$t('server.relayTitle')" width="98%" top="2vh">
<div>
<AccessShow value="ImportRelayNode">
<div class="head mgb-1" v-if="state.super">
<div class="flex">
<span class="flex-1"></span>
<div>
<el-button type="success" size="small" @click="handleImport"><el-icon><Plus /></el-icon></el-button>
</div>
<span class="flex-1"></span>
</div>
</div>
</AccessShow>
<el-table :data="state.nodes" size="small" border height="500" stripe>
<el-table-column property="Name" :label="$t('server.relayName')">
<template #default="scope">
@@ -25,7 +36,7 @@
</p>
<p class="flex">
<div>
<template v-if="state.syncData.Key == scope.row.Id">
<template v-if="state.syncData.Key == scope.row.NodeId">
<el-checkbox size="small" disabled checked>{{ $t('server.relayDefault') }}</el-checkbox>
</template>
<template v-else>
@@ -33,8 +44,12 @@
</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>
<AccessBoolean value="UpgradeRelayNode">
<template #default="{values}">
<a v-if="state.super && values.UpgradeRelayNode" href="javascript:;" class="a-line a-edit" @click="handleUpgrade(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>
</template>
</AccessBoolean>
</p>
</div>
</div>
@@ -79,11 +94,21 @@
<p>{{ scope.row.Delay }}ms</p>
</template>
</el-table-column>
<el-table-column v-if="state.super" property="Manageable" :label="$t('server.relayOper')" width="110">
<el-table-column property="Manageable" :label="$t('server.relayOper')" width="110">
<template #default="scope">
<p>
<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>
<AccessBoolean v-if="state.super" value="RemoveRelayNode,UpdateRelayNode,ShareRelayNode,RebootRelayNode">
<template #default="{values}">
<p>
<el-button v-if="scope.row.Manageable && values.RebootRelayNode" type="warning" size="small" @click="handleExit(scope.row)"><el-icon><Refresh /></el-icon></el-button>
<el-button v-if="values.UpdateRelayNode" size="small" @click="handleEdit(scope.row)"><el-icon><Edit /></el-icon></el-button>
</p>
<p>
<el-button v-if="values.RemoveRelayNode" type="danger" size="small" @click="handleRemove(scope.row)"><el-icon><CircleClose /></el-icon></el-button>
<el-button v-if="scope.row.Manageable && values.ShareRelayNode" type="info" size="small" @click="handleShare(scope.row)"><el-icon><Share /></el-icon></el-button>
</p>
</template>
</AccessBoolean>
</p>
</template>
</el-table-column>
@@ -104,19 +129,19 @@
</div>
</template>
<script>
import { getDefault,relayEdit,relayExit,relayUpdate,syncDefault } from '@/apis/relay';
import { getDefault,relayExit,relayImport,relayRemove,relayShare,relayUpgrade,syncDefault } from '@/apis/relay';
import { injectGlobalData } from '@/provide';
import { ElMessage, ElMessageBox } from 'element-plus';
import { computed, onMounted, onUnmounted, reactive, ref, watch } from 'vue'
import { useI18n } from 'vue-i18n';
import Ids from '../sync/Ids.vue';
import EditNode from './EditNode.vue';
import { Edit,ArrowDown,Refresh } from '@element-plus/icons-vue';
import { Edit,ArrowDown,Refresh,CircleClose,Plus,Share } from '@element-plus/icons-vue';
export default {
props: ['modelValue','data'],
emits: ['update:modelValue','success'],
components:{Ids,EditNode,Edit,ArrowDown,Refresh},
components:{Ids,EditNode,Edit,ArrowDown,Refresh,CircleClose,Plus,Share},
setup(props,{emit}) {
const {t} = useI18n();
const globalData = injectGlobalData();
@@ -154,7 +179,7 @@ export default {
}
const domIds = ref(null);
const handleShowSync = (row,proto)=>{
state.syncData.Key = row.Id;
state.syncData.Key = row.NodeId;
state.syncData.Value = proto;
state.showSync = true;
}
@@ -176,39 +201,29 @@ export default {
_getDefault();
}
const handleSync2Server = (row)=>{
row.Sync2Server = !row.Sync2Server;
row.AllowTcp= (row.AllowProtocol & 1) == 1,
row.AllowUdp = (row.AllowProtocol & 2) == 2,
relayEdit(row).then(res => {
ElMessage.success(t('common.oper'));
}).catch(()=>{
ElMessage.error(t('common.operFail'));
});
}
const handleExit = (row)=>{
ElMessageBox.confirm(t('server.relayExit'), t('common.confirm'), {
confirmButtonText: t('common.confirm'),
cancelButtonText: t('common.cancel'),
type: 'warning',
}).then(() => {
relayExit(row.Id).then(res => {
relayExit(row.NodeId).then(res => {
ElMessage.success(t('common.oper'));
}).catch(()=>{
ElMessage.error(t('common.operFail'));
});
}).catch(() => {
ElMessage.error(t('common.operFail'));
//ElMessage.error(t('common.operFail'));
});
}
const handleUpdate = (row)=>{
const handleUpgrade = (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:row.Id,Value:globalData.value.signin.Version}).then(res => {
relayUpgrade({Key:row.NodeId,Value:globalData.value.signin.Version}).then(res => {
ElMessage.success(t('common.oper'));
}).catch(()=>{
ElMessage.error(t('common.operFail'));
@@ -218,6 +233,52 @@ export default {
});
}
const handleRemove = (row)=>{
ElMessageBox.confirm(t('server.relayRemove'), t('common.confirm'), {
confirmButtonText: t('common.confirm'),
cancelButtonText: t('common.cancel'),
type: 'warning',
}).then(() => {
relayRemove(row.NodeId).then(res => {
ElMessage.success(t('common.oper'));
}).catch(()=>{
ElMessage.error(t('common.operFail'));
});
}).catch(() => {
//ElMessage.error(t('common.operFail'));
});
}
const handleImport = ()=>{
ElMessageBox.prompt(t('server.relayImport'), t('common.confirm'), {
confirmButtonText: t('common.confirm'),
cancelButtonText: t('common.cancel')
}).then(({ value }) => {
if(!value) return;
relayImport(value).then((res)=>{
if(res){
ElMessage.error(res);
}else{
ElMessage.success(t('common.oper'));
}
}).catch(()=>{})
}).catch(() => {
})
}
const handleShare = (row)=>{
relayShare(row.NodeId).then((res)=>{
ElMessageBox.prompt(t('server.relayShare'), t('common.tips'), {
confirmButtonText: t('common.confirm'),
cancelButtonText: t('common.cancel'),
inputValue:res
}).then(({ value }) => {
navigator.clipboard.writeText(value)
}).catch(() => {
})
}).catch(()=>{
ElMessage.error(t('common.operFail'));
});
}
onMounted(()=>{
_getDefault();
});
@@ -227,7 +288,7 @@ export default {
return {globalData,state,
handleEdit,domIds,handleShowSync,handleSync,handleCancelSync,
handleExit,handleUpdate,handleSync2Server}
handleExit,handleUpgrade,handleRemove,handleImport,handleShare}
}
}
</script>

View File

@@ -1,29 +1,29 @@
<template>
<el-dialog v-model="state.show" append-to=".app-wrap" :title="`与[${state.device.MachineName}]的链接`" top="1vh" width="350">
<div>
<el-descriptions border size="small" :column="1" column-max-width="120px" overlength-control="wrap">
<el-descriptions-item label="目标">{{ state.connection.IPEndPoint || '0.0.0.0:0' }}</el-descriptions-item>
<el-descriptions-item label="事务">{{ state.transactions[state.connection.TransactionId] }}</el-descriptions-item>
<el-descriptions-item label="协议">
<div>
<el-descriptions border size="small" :column="1" label-width="6rem" overlength-control="wrap">
<el-descriptions-item label="目标" >{{ state.connection.IPEndPoint }}</el-descriptions-item>
<el-descriptions-item label="事务" >{{ state.transactions[state.connection.TransactionId] }}</el-descriptions-item>
<el-descriptions-item label="协议" >
<div v-if="state.connection.Connected">
<p>{{ state.connection.TransportName }}({{ state.protocolTypes[state.connection.ProtocolType] }}) - {{ state.types[state.connection.Type] }}</p>
<p>{{ state.connection.SendBufferRemainingText }} - {{ state.connection.RecvBufferRemainingText }}</p>
</div>
</el-descriptions-item>
<el-descriptions-item label="SSL">{{ state.connection.SSL }}</el-descriptions-item>
<el-descriptions-item label="SSL" >{{ state.connection.SSL }}</el-descriptions-item>
<el-descriptions-item label="上传">
<el-descriptions-item label="上传" >
<div>
<p><span>{{ state.connection.SendBytesText }}</span></p>
</div>
</el-descriptions-item>
<el-descriptions-item label="下载">
<el-descriptions-item label="下载" >
<div>
<p><span>{{ state.connection.ReceiveBytesText }}</span></p>
</div>
</el-descriptions-item>
<el-descriptions-item label="中继">
<el-descriptions-item label="中继" >
<div>
<a v-if="state.connecting" href="javascript:;" class="a-line">
<span>操作中.</span><el-icon size="14" class="loading"><Loading /></el-icon>
@@ -31,7 +31,7 @@
<a v-else href="javascript:;" class="a-line" @click="handleNode">{{ state.nodesDic[state.connection.NodeId] || '选择节点' }}</a>
</div>
</el-descriptions-item>
<el-descriptions-item label="打洞">
<el-descriptions-item label="打洞" >
<div>
<a v-if="state.connecting" href="javascript:;" class="a-line">
<span>操作中.</span><el-icon size="14" class="loading"><Loading /></el-icon>
@@ -39,8 +39,8 @@
<a v-else href="javascript:;" class="a-line" @click="handlep2p">尝试打洞</a>
</div>
</el-descriptions-item>
<el-descriptions-item label="延迟">{{ state.connection.Delay }}</el-descriptions-item>
<el-descriptions-item label="操作">
<el-descriptions-item label="延迟" >{{ state.connection.Delay }}</el-descriptions-item>
<el-descriptions-item label="操作" >
<div>
<AccessShow value="TunnelRemove">
<el-popconfirm confirm-button-text="确认" cancel-button-text="取消"

View File

@@ -1,7 +1,7 @@
<template>
<el-dialog v-model="state.show" append-to=".app-wrap" :title="state.title" top="1vh" width="370">
<el-dialog v-model="state.show" append-to=".app-wrap" :title="state.title" top="1vh" width="400">
<div>
<el-descriptions border size="small" :column="1" column-max-width="120px" overlength-control="wrap">
<el-descriptions border size="small" :column="1" label-width="8rem" overlength-control="wrap">
<el-descriptions-item label="名称">{{ state.status.Info.Name }}</el-descriptions-item>
<el-descriptions-item label="带宽">
<div>