mirror of
https://github.com/snltty/linker.git
synced 2025-12-18 17:36:45 +08:00
cdkey
This commit is contained in:
@@ -2,6 +2,5 @@
|
|||||||
declare (strict_types=1);
|
declare (strict_types=1);
|
||||||
|
|
||||||
return [
|
return [
|
||||||
'STATUS' => '1',
|
'STATUS' => '0'
|
||||||
'KeyId' => 'FAFAB92C-DFDF-1221-DEA2-40A0E915EB10',
|
|
||||||
];
|
];
|
||||||
@@ -43,7 +43,7 @@ namespace linker.messenger.relay
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<RelayServerNodeReportInfo> Subscribe(ApiControllerParamsInfo param)
|
public List<RelayServerNodeReportInfo170> Subscribe(ApiControllerParamsInfo param)
|
||||||
{
|
{
|
||||||
relayTestTransfer.Subscribe();
|
relayTestTransfer.Subscribe();
|
||||||
return relayTestTransfer.Nodes;
|
return relayTestTransfer.Nodes;
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ namespace linker.messenger.relay
|
|||||||
private readonly ISignInClientStore signInClientStore;
|
private readonly ISignInClientStore signInClientStore;
|
||||||
private readonly IRelayClientStore relayClientStore;
|
private readonly IRelayClientStore relayClientStore;
|
||||||
|
|
||||||
public List<RelayServerNodeReportInfo> Nodes { get; private set; } = new List<RelayServerNodeReportInfo>();
|
public List<RelayServerNodeReportInfo170> Nodes { get; private set; } = new List<RelayServerNodeReportInfo170>();
|
||||||
|
|
||||||
public RelayClientTestTransfer(RelayClientTransfer relayTransfer, SignInClientState signInClientState, ISignInClientStore signInClientStore, IRelayClientStore relayClientStore)
|
public RelayClientTestTransfer(RelayClientTransfer relayTransfer, SignInClientState signInClientState, ISignInClientStore signInClientStore, IRelayClientStore relayClientStore)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ namespace linker.messenger.relay.client.transport
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="relayTestInfo"></param>
|
/// <param name="relayTestInfo"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public Task<List<RelayServerNodeReportInfo>> RelayTestAsync(RelayTestInfo170 relayTestInfo);
|
public Task<List<RelayServerNodeReportInfo170>> RelayTestAsync(RelayTestInfo170 relayTestInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ namespace linker.messenger.relay.client.transport
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
//问一下能不能中继
|
//问一下能不能中继
|
||||||
RelayAskResultInfo relayAskResultInfo = await RelayAsk(relayInfo);
|
RelayAskResultInfo170 relayAskResultInfo = await RelayAsk(relayInfo);
|
||||||
relayInfo.FlowingId = relayAskResultInfo.FlowingId;
|
relayInfo.FlowingId = relayAskResultInfo.FlowingId;
|
||||||
if (relayInfo.FlowingId == 0 || relayAskResultInfo.Nodes.Count == 0)
|
if (relayInfo.FlowingId == 0 || relayAskResultInfo.Nodes.Count == 0)
|
||||||
{
|
{
|
||||||
@@ -119,7 +119,7 @@ namespace linker.messenger.relay.client.transport
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<RelayAskResultInfo> RelayAsk(RelayInfo170 relayInfo)
|
private async Task<RelayAskResultInfo170> RelayAsk(RelayInfo170 relayInfo)
|
||||||
{
|
{
|
||||||
MessageResponeInfo resp = await messengerSender.SendReply(new MessageRequestWrap
|
MessageResponeInfo resp = await messengerSender.SendReply(new MessageRequestWrap
|
||||||
{
|
{
|
||||||
@@ -130,15 +130,15 @@ namespace linker.messenger.relay.client.transport
|
|||||||
}).ConfigureAwait(false);
|
}).ConfigureAwait(false);
|
||||||
if (resp.Code != MessageResponeCodes.OK)
|
if (resp.Code != MessageResponeCodes.OK)
|
||||||
{
|
{
|
||||||
return new RelayAskResultInfo();
|
return new RelayAskResultInfo170();
|
||||||
}
|
}
|
||||||
|
|
||||||
RelayAskResultInfo result = serializer.Deserialize<RelayAskResultInfo>(resp.Data.Span);
|
RelayAskResultInfo170 result = serializer.Deserialize<RelayAskResultInfo170>(resp.Data.Span);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
|
|
||||||
}
|
}
|
||||||
private async Task<Socket> ConnectNodeServer(RelayInfo170 relayInfo, List<RelayServerNodeReportInfo> nodes)
|
private async Task<Socket> ConnectNodeServer(RelayInfo170 relayInfo, List<RelayServerNodeReportInfo170> nodes)
|
||||||
{
|
{
|
||||||
byte[] buffer = ArrayPool<byte>.Shared.Rent(1 * 1024);
|
byte[] buffer = ArrayPool<byte>.Shared.Rent(1 * 1024);
|
||||||
|
|
||||||
@@ -306,7 +306,7 @@ namespace linker.messenger.relay.client.transport
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<List<RelayServerNodeReportInfo>> RelayTestAsync(RelayTestInfo170 relayTestInfo)
|
public async Task<List<RelayServerNodeReportInfo170>> RelayTestAsync(RelayTestInfo170 relayTestInfo)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -320,13 +320,13 @@ namespace linker.messenger.relay.client.transport
|
|||||||
|
|
||||||
if (resp.Code == MessageResponeCodes.OK)
|
if (resp.Code == MessageResponeCodes.OK)
|
||||||
{
|
{
|
||||||
return serializer.Deserialize<List<RelayServerNodeReportInfo>>(resp.Data.Span);
|
return serializer.Deserialize<List<RelayServerNodeReportInfo170>>(resp.Data.Span);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception)
|
catch (Exception)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
return new List<RelayServerNodeReportInfo>();
|
return new List<RelayServerNodeReportInfo170>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -70,15 +70,22 @@ namespace linker.messenger.relay.messenger
|
|||||||
public async Task RelayTest(IConnection connection)
|
public async Task RelayTest(IConnection connection)
|
||||||
{
|
{
|
||||||
RelayTestInfo info = serializer.Deserialize<RelayTestInfo>(connection.ReceiveRequestWrap.Payload.Span);
|
RelayTestInfo info = serializer.Deserialize<RelayTestInfo>(connection.ReceiveRequestWrap.Payload.Span);
|
||||||
await RelayTest(connection, info);
|
await RelayTest(connection, info, (validated) =>
|
||||||
|
{
|
||||||
|
List<RelayServerNodeReportInfo> list = relayServerTransfer.GetNodes(validated).Select(c => (RelayServerNodeReportInfo)c).ToList();
|
||||||
|
return serializer.Serialize(list);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
[MessengerId((ushort)RelayMessengerIds.RelayTest170)]
|
[MessengerId((ushort)RelayMessengerIds.RelayTest170)]
|
||||||
public async Task RelayTest170(IConnection connection)
|
public async Task RelayTest170(IConnection connection)
|
||||||
{
|
{
|
||||||
RelayTestInfo170 info = serializer.Deserialize<RelayTestInfo170>(connection.ReceiveRequestWrap.Payload.Span);
|
RelayTestInfo170 info = serializer.Deserialize<RelayTestInfo170>(connection.ReceiveRequestWrap.Payload.Span);
|
||||||
await RelayTest(connection, info);
|
await RelayTest(connection, info, (validated) =>
|
||||||
|
{
|
||||||
|
return serializer.Serialize(relayServerTransfer.GetNodes(validated));
|
||||||
|
});
|
||||||
}
|
}
|
||||||
private async Task RelayTest(IConnection connection, RelayTestInfo info)
|
private async Task RelayTest(IConnection connection, RelayTestInfo info, Func<bool, byte[]> data)
|
||||||
{
|
{
|
||||||
if (signCaching.TryGet(connection.Id, out SignCacheInfo cache) == false)
|
if (signCaching.TryGet(connection.Id, out SignCacheInfo cache) == false)
|
||||||
{
|
{
|
||||||
@@ -94,8 +101,7 @@ namespace linker.messenger.relay.messenger
|
|||||||
TransportName = "test",
|
TransportName = "test",
|
||||||
}, cache, null);
|
}, cache, null);
|
||||||
|
|
||||||
var nodes = relayServerTransfer.GetNodes(string.IsNullOrWhiteSpace(result));
|
connection.Write(data(string.IsNullOrWhiteSpace(result)));
|
||||||
connection.Write(serializer.Serialize(nodes));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -106,18 +112,6 @@ namespace linker.messenger.relay.messenger
|
|||||||
public async Task RelayAsk(IConnection connection)
|
public async Task RelayAsk(IConnection connection)
|
||||||
{
|
{
|
||||||
RelayInfo info = serializer.Deserialize<RelayInfo>(connection.ReceiveRequestWrap.Payload.Span);
|
RelayInfo info = serializer.Deserialize<RelayInfo>(connection.ReceiveRequestWrap.Payload.Span);
|
||||||
await RelayAsk(connection, info, new List<RelayServerCdkeyInfo>());
|
|
||||||
}
|
|
||||||
[MessengerId((ushort)RelayMessengerIds.RelayAsk170)]
|
|
||||||
public async Task RelayAsk170(IConnection connection)
|
|
||||||
{
|
|
||||||
RelayInfo170 info = serializer.Deserialize<RelayInfo170>(connection.ReceiveRequestWrap.Payload.Span);
|
|
||||||
|
|
||||||
List<RelayServerCdkeyInfo> cdkeys = (await relayServerCdkeyStore.GetAvailable(info.UserId)).Select(c => new RelayServerCdkeyInfo { Bandwidth = c.Bandwidth, CdkeyId = c.CdkeyId, LastBytes = c.LastBytes }).ToList();
|
|
||||||
await RelayAsk(connection, info, cdkeys);
|
|
||||||
}
|
|
||||||
public async Task RelayAsk(IConnection connection, RelayInfo info, List<RelayServerCdkeyInfo> cdkeys)
|
|
||||||
{
|
|
||||||
if (signCaching.TryGet(connection.Id, out SignCacheInfo cacheFrom) == false || signCaching.TryGet(info.RemoteMachineId, out SignCacheInfo cacheTo) == false || cacheFrom.GroupId != cacheTo.GroupId)
|
if (signCaching.TryGet(connection.Id, out SignCacheInfo cacheFrom) == false || signCaching.TryGet(info.RemoteMachineId, out SignCacheInfo cacheTo) == false || cacheFrom.GroupId != cacheTo.GroupId)
|
||||||
{
|
{
|
||||||
connection.Write(serializer.Serialize(new RelayAskResultInfo { }));
|
connection.Write(serializer.Serialize(new RelayAskResultInfo { }));
|
||||||
@@ -132,10 +126,39 @@ namespace linker.messenger.relay.messenger
|
|||||||
RelayAskResultInfo result = new RelayAskResultInfo();
|
RelayAskResultInfo result = new RelayAskResultInfo();
|
||||||
string error = await relayValidatorTransfer.Validate(info, cacheFrom, cacheTo);
|
string error = await relayValidatorTransfer.Validate(info, cacheFrom, cacheTo);
|
||||||
bool validated = string.IsNullOrWhiteSpace(error);
|
bool validated = string.IsNullOrWhiteSpace(error);
|
||||||
|
result.Nodes = relayServerTransfer.GetNodes(validated).Select(c => (RelayServerNodeReportInfo)c).ToList();
|
||||||
|
|
||||||
|
if (result.Nodes.Count > 0)
|
||||||
|
{
|
||||||
|
result.FlowingId = relayServerTransfer.AddRelay(cacheFrom.MachineId, cacheFrom.MachineName, cacheTo.MachineId, cacheTo.MachineName, cacheFrom.GroupId, validated, new List<RelayServerCdkeyInfo>());
|
||||||
|
}
|
||||||
|
|
||||||
|
connection.Write(serializer.Serialize(result));
|
||||||
|
}
|
||||||
|
[MessengerId((ushort)RelayMessengerIds.RelayAsk170)]
|
||||||
|
public async Task RelayAsk170(IConnection connection)
|
||||||
|
{
|
||||||
|
RelayInfo170 info = serializer.Deserialize<RelayInfo170>(connection.ReceiveRequestWrap.Payload.Span);
|
||||||
|
if (signCaching.TryGet(connection.Id, out SignCacheInfo cacheFrom) == false || signCaching.TryGet(info.RemoteMachineId, out SignCacheInfo cacheTo) == false || cacheFrom.GroupId != cacheTo.GroupId)
|
||||||
|
{
|
||||||
|
connection.Write(serializer.Serialize(new RelayAskResultInfo170 { }));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
info.RemoteMachineId = cacheTo.MachineId;
|
||||||
|
info.FromMachineId = cacheFrom.MachineId;
|
||||||
|
info.RemoteMachineName = cacheTo.MachineName;
|
||||||
|
info.FromMachineName = cacheFrom.MachineName;
|
||||||
|
|
||||||
|
RelayAskResultInfo170 result = new RelayAskResultInfo170();
|
||||||
|
string error = await relayValidatorTransfer.Validate(info, cacheFrom, cacheTo);
|
||||||
|
bool validated = string.IsNullOrWhiteSpace(error);
|
||||||
result.Nodes = relayServerTransfer.GetNodes(validated);
|
result.Nodes = relayServerTransfer.GetNodes(validated);
|
||||||
|
|
||||||
if (result.Nodes.Count > 0)
|
if (result.Nodes.Count > 0)
|
||||||
{
|
{
|
||||||
|
List<RelayServerCdkeyInfo> cdkeys = (await relayServerCdkeyStore.GetAvailable(info.UserId)).Select(c => new RelayServerCdkeyInfo { Bandwidth = c.Bandwidth, CdkeyId = c.CdkeyId, LastBytes = c.LastBytes }).ToList();
|
||||||
|
|
||||||
result.FlowingId = relayServerTransfer.AddRelay(cacheFrom.MachineId, cacheFrom.MachineName, cacheTo.MachineId, cacheTo.MachineName, cacheFrom.GroupId, validated, cdkeys);
|
result.FlowingId = relayServerTransfer.AddRelay(cacheFrom.MachineId, cacheFrom.MachineName, cacheTo.MachineId, cacheTo.MachineName, cacheFrom.GroupId, validated, cdkeys);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -240,7 +263,7 @@ namespace linker.messenger.relay.messenger
|
|||||||
[MessengerId((ushort)RelayMessengerIds.NodeReport)]
|
[MessengerId((ushort)RelayMessengerIds.NodeReport)]
|
||||||
public void NodeReport(IConnection connection)
|
public void NodeReport(IConnection connection)
|
||||||
{
|
{
|
||||||
RelayServerNodeReportInfo info = serializer.Deserialize<RelayServerNodeReportInfo>(connection.ReceiveRequestWrap.Payload.Span);
|
RelayServerNodeReportInfo170 info = serializer.Deserialize<RelayServerNodeReportInfo170>(connection.ReceiveRequestWrap.Payload.Span);
|
||||||
if (LoggerHelper.Instance.LoggerLevel <= LoggerTypes.DEBUG)
|
if (LoggerHelper.Instance.LoggerLevel <= LoggerTypes.DEBUG)
|
||||||
{
|
{
|
||||||
LoggerHelper.Instance.Debug($"relay node report : {info.ToJson()}");
|
LoggerHelper.Instance.Debug($"relay node report : {info.ToJson()}");
|
||||||
@@ -287,17 +310,26 @@ namespace linker.messenger.relay.messenger
|
|||||||
/// <param name="connection"></param>
|
/// <param name="connection"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
[MessengerId((ushort)RelayMessengerIds.TrafficReport)]
|
[MessengerId((ushort)RelayMessengerIds.TrafficReport)]
|
||||||
public async Task TrafficReport(IConnection connection)
|
public void TrafficReport(IConnection connection)
|
||||||
{
|
{
|
||||||
RelayTrafficUpdateInfo info = serializer.Deserialize<RelayTrafficUpdateInfo>(connection.ReceiveRequestWrap.Payload.Span);
|
RelayTrafficUpdateInfo info = serializer.Deserialize<RelayTrafficUpdateInfo>(connection.ReceiveRequestWrap.Payload.Span);
|
||||||
if (relayServerStore.SecretKey != info.SecretKey)
|
if (relayServerStore.SecretKey != info.SecretKey)
|
||||||
{
|
{
|
||||||
connection.Write(serializer.Serialize(new Dictionary<string, long>()));
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Dictionary<long, long> result = await relayServerTransfer.AddTraffic(info);
|
relayServerTransfer.AddTraffic(info.Dic);
|
||||||
connection.Write(serializer.Serialize(result));
|
|
||||||
}
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// 下发剩余流量
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="connection"></param>
|
||||||
|
[MessengerId((ushort)RelayMessengerIds.SendLastBytes)]
|
||||||
|
public void SendLastBytes(IConnection connection)
|
||||||
|
{
|
||||||
|
Dictionary<long, long> info = serializer.Deserialize<Dictionary<long,long>>(connection.ReceiveRequestWrap.Payload.Span);
|
||||||
|
relayServerNodeTransfer.UpdateLastBytes(info);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -35,6 +35,8 @@
|
|||||||
RelayAsk170 = 2120,
|
RelayAsk170 = 2120,
|
||||||
RelayForward170 = 2121,
|
RelayForward170 = 2121,
|
||||||
|
|
||||||
|
SendLastBytes = 2122,
|
||||||
|
|
||||||
Max = 2199
|
Max = 2199
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,7 @@
|
|||||||
namespace linker.messenger.relay.server
|
using linker.libs;
|
||||||
|
using System.Net;
|
||||||
|
|
||||||
|
namespace linker.messenger.relay.server
|
||||||
{
|
{
|
||||||
public interface IRelayServerCdkeyStore
|
public interface IRelayServerCdkeyStore
|
||||||
{
|
{
|
||||||
@@ -54,6 +57,12 @@
|
|||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public Task<bool> Traffic(Dictionary<long, long> dic);
|
public Task<bool> Traffic(Dictionary<long, long> dic);
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
/// 获取剩余流量
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="ids"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public Task<Dictionary<long, long>> GetLastBytes(List<long> ids);
|
||||||
|
/// <summary>
|
||||||
/// 分页
|
/// 分页
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="relayServerCdkeyPageRequestInfo"></param>
|
/// <param name="relayServerCdkeyPageRequestInfo"></param>
|
||||||
@@ -66,7 +75,11 @@
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 加解密密钥
|
/// 加解密密钥
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
#if DEBUG
|
||||||
|
public string SecretKey { get; set; } = Helper.GlobalString;
|
||||||
|
#else
|
||||||
public string SecretKey { get; set; } = Guid.NewGuid().ToString().ToUpper();
|
public string SecretKey { get; set; } = Guid.NewGuid().ToString().ToUpper();
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
public sealed partial class RelayServerCdkeyPageRequestInfo
|
public sealed partial class RelayServerCdkeyPageRequestInfo
|
||||||
|
|||||||
@@ -103,7 +103,7 @@ namespace linker.messenger.relay.server
|
|||||||
|
|
||||||
public string Url { get; set; } = "https://linker-doc.snltty.com";
|
public string Url { get; set; } = "https://linker-doc.snltty.com";
|
||||||
}
|
}
|
||||||
public sealed partial class RelayServerNodeReportInfo
|
public partial class RelayServerNodeReportInfo
|
||||||
{
|
{
|
||||||
public string Id { get; set; } = string.Empty;
|
public string Id { get; set; } = string.Empty;
|
||||||
public string Name { get; set; } = string.Empty;
|
public string Name { get; set; } = string.Empty;
|
||||||
@@ -124,7 +124,9 @@ namespace linker.messenger.relay.server
|
|||||||
public IPEndPoint EndPoint { get; set; }
|
public IPEndPoint EndPoint { get; set; }
|
||||||
|
|
||||||
public long LastTicks { get; set; }
|
public long LastTicks { get; set; }
|
||||||
|
}
|
||||||
|
public sealed partial class RelayServerNodeReportInfo170: RelayServerNodeReportInfo
|
||||||
|
{
|
||||||
public string Url { get; set; } = "https://linker-doc.snltty.com";
|
public string Url { get; set; } = "https://linker-doc.snltty.com";
|
||||||
|
|
||||||
[JsonIgnore]
|
[JsonIgnore]
|
||||||
@@ -138,4 +140,10 @@ namespace linker.messenger.relay.server
|
|||||||
public List<RelayServerNodeReportInfo> Nodes { get; set; } = new List<RelayServerNodeReportInfo>();
|
public List<RelayServerNodeReportInfo> Nodes { get; set; } = new List<RelayServerNodeReportInfo>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public sealed partial class RelayAskResultInfo170
|
||||||
|
{
|
||||||
|
public ulong FlowingId { get; set; }
|
||||||
|
|
||||||
|
public List<RelayServerNodeReportInfo170> Nodes { get; set; } = new List<RelayServerNodeReportInfo170>();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,8 +13,9 @@ namespace linker.messenger.relay.server
|
|||||||
{
|
{
|
||||||
|
|
||||||
private ulong relayFlowingId = 0;
|
private ulong relayFlowingId = 0;
|
||||||
private readonly ConcurrentDictionary<string, RelayServerNodeReportInfo> reports = new ConcurrentDictionary<string, RelayServerNodeReportInfo>();
|
private readonly ConcurrentDictionary<string, RelayServerNodeReportInfo170> reports = new ConcurrentDictionary<string, RelayServerNodeReportInfo170>();
|
||||||
private readonly ConcurrentQueue<Dictionary<long, long>> trafficQueue = new ConcurrentQueue<Dictionary<long, long>>();
|
private readonly ConcurrentQueue<Dictionary<long, long>> trafficQueue = new ConcurrentQueue<Dictionary<long, long>>();
|
||||||
|
private readonly ConcurrentQueue<List<long>> trafficIdsQueue = new ConcurrentQueue<List<long>>();
|
||||||
|
|
||||||
private readonly IRelayServerCaching relayCaching;
|
private readonly IRelayServerCaching relayCaching;
|
||||||
private readonly ISerializer serializer;
|
private readonly ISerializer serializer;
|
||||||
@@ -61,7 +62,7 @@ namespace linker.messenger.relay.server
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="ep"></param>
|
/// <param name="ep"></param>
|
||||||
/// <param name="data"></param>
|
/// <param name="data"></param>
|
||||||
public void SetNodeReport(IConnection connection, RelayServerNodeReportInfo info)
|
public void SetNodeReport(IConnection connection, RelayServerNodeReportInfo170 info)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -93,7 +94,7 @@ namespace linker.messenger.relay.server
|
|||||||
{
|
{
|
||||||
if (RelayServerNodeInfo.MASTER_NODE_ID == info.Id) return;
|
if (RelayServerNodeInfo.MASTER_NODE_ID == info.Id) return;
|
||||||
|
|
||||||
if (reports.TryGetValue(info.Id, out RelayServerNodeReportInfo cache))
|
if (reports.TryGetValue(info.Id, out RelayServerNodeReportInfo170 cache))
|
||||||
{
|
{
|
||||||
await messengerSender.SendOnly(new MessageRequestWrap
|
await messengerSender.SendOnly(new MessageRequestWrap
|
||||||
{
|
{
|
||||||
@@ -109,7 +110,7 @@ namespace linker.messenger.relay.server
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="validated">是否已认证</param>
|
/// <param name="validated">是否已认证</param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public List<RelayServerNodeReportInfo> GetNodes(bool validated)
|
public List<RelayServerNodeReportInfo170> GetNodes(bool validated)
|
||||||
{
|
{
|
||||||
var result = reports.Values
|
var result = reports.Values
|
||||||
.Where(c => c.Public || validated)
|
.Where(c => c.Public || validated)
|
||||||
@@ -134,7 +135,7 @@ namespace linker.messenger.relay.server
|
|||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public bool NodeValidate(string nodeId)
|
public bool NodeValidate(string nodeId)
|
||||||
{
|
{
|
||||||
return reports.TryGetValue(nodeId, out RelayServerNodeReportInfo relayNodeReportInfo) && relayNodeReportInfo.Public == false;
|
return reports.TryGetValue(nodeId, out RelayServerNodeReportInfo170 relayNodeReportInfo) && relayNodeReportInfo.Public == false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -142,16 +143,10 @@ namespace linker.messenger.relay.server
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="relayTrafficUpdateInfo"></param>
|
/// <param name="relayTrafficUpdateInfo"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public async Task<Dictionary<long, long>> AddTraffic(RelayTrafficUpdateInfo relayTrafficUpdateInfo)
|
public void AddTraffic(Dictionary<long,long> dic)
|
||||||
{
|
{
|
||||||
if (relayTrafficUpdateInfo.Dic.Count > 0)
|
if (dic.Count > 0)
|
||||||
trafficQueue.Enqueue(relayTrafficUpdateInfo.Dic);
|
trafficQueue.Enqueue(dic);
|
||||||
|
|
||||||
if (relayTrafficUpdateInfo.Ids == null || relayTrafficUpdateInfo.Ids.Count == 0)
|
|
||||||
{
|
|
||||||
return new Dictionary<long, long>();
|
|
||||||
}
|
|
||||||
return (await relayServerCdkeyStore.Get(relayTrafficUpdateInfo.Ids)).ToDictionary(c => c.CdkeyId, c => c.LastBytes);
|
|
||||||
}
|
}
|
||||||
private void TrafficTask()
|
private void TrafficTask()
|
||||||
{
|
{
|
||||||
@@ -159,10 +154,50 @@ namespace linker.messenger.relay.server
|
|||||||
{
|
{
|
||||||
while (trafficQueue.TryDequeue(out Dictionary<long, long> dic))
|
while (trafficQueue.TryDequeue(out Dictionary<long, long> dic))
|
||||||
{
|
{
|
||||||
await relayServerCdkeyStore.Traffic(dic).ConfigureAwait(false);
|
try
|
||||||
|
{
|
||||||
|
await relayServerCdkeyStore.Traffic(dic).ConfigureAwait(false);
|
||||||
|
|
||||||
|
var ids = dic.Keys.ToList();
|
||||||
|
while (ids.Count > 0)
|
||||||
|
{
|
||||||
|
var id = ids.Take(100).ToList();
|
||||||
|
trafficIdsQueue.Enqueue(id);
|
||||||
|
ids.RemoveRange(0, id.Count);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
LoggerHelper.Instance.Error(ex);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}, 3000);
|
}, 500);
|
||||||
|
TimerHelper.SetIntervalLong(async () =>
|
||||||
|
{
|
||||||
|
while (trafficIdsQueue.TryDequeue(out List<long> ids))
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Dictionary<long, long> id2last = await relayServerCdkeyStore.GetLastBytes(ids).ConfigureAwait(false);
|
||||||
|
if (id2last.Count == 0) continue;
|
||||||
|
byte[] bytes = serializer.Serialize(id2last);
|
||||||
|
|
||||||
|
await Task.WhenAll(reports.Values.Select(c => messengerSender.SendOnly(new MessageRequestWrap
|
||||||
|
{
|
||||||
|
Connection = c.Connection,
|
||||||
|
MessengerId = (ushort)RelayMessengerIds.SendLastBytes,
|
||||||
|
Payload = bytes,
|
||||||
|
})).ToList());
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
LoggerHelper.Instance.Error(ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}, 500);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ namespace linker.messenger.relay.server
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public class RelayServerNodeTransfer
|
public class RelayServerNodeTransfer
|
||||||
{
|
{
|
||||||
public string Id=>relayServerNodeStore.Node.Id;
|
public string Id => relayServerNodeStore.Node.Id;
|
||||||
|
|
||||||
private uint connectionNum = 0;
|
private uint connectionNum = 0;
|
||||||
private IConnection localConnection;
|
private IConnection localConnection;
|
||||||
@@ -23,7 +23,6 @@ namespace linker.messenger.relay.server
|
|||||||
private long lastBytes = 0;
|
private long lastBytes = 0;
|
||||||
private RelaySpeedLimit limitTotal = new RelaySpeedLimit();
|
private RelaySpeedLimit limitTotal = new RelaySpeedLimit();
|
||||||
private readonly ConcurrentDictionary<ulong, RelayTrafficCacheInfo> trafficDict = new ConcurrentDictionary<ulong, RelayTrafficCacheInfo>();
|
private readonly ConcurrentDictionary<ulong, RelayTrafficCacheInfo> trafficDict = new ConcurrentDictionary<ulong, RelayTrafficCacheInfo>();
|
||||||
private readonly ConcurrentDictionary<long, long> cdkeyLastBytes = new ConcurrentDictionary<long, long>();
|
|
||||||
|
|
||||||
private readonly ISerializer serializer;
|
private readonly ISerializer serializer;
|
||||||
private readonly IRelayServerNodeStore relayServerNodeStore;
|
private readonly IRelayServerNodeStore relayServerNodeStore;
|
||||||
@@ -169,10 +168,6 @@ namespace linker.messenger.relay.server
|
|||||||
public void RemoveTrafficCache(RelayTrafficCacheInfo relayCache)
|
public void RemoveTrafficCache(RelayTrafficCacheInfo relayCache)
|
||||||
{
|
{
|
||||||
trafficDict.TryRemove(relayCache.Cache.FlowId, out _);
|
trafficDict.TryRemove(relayCache.Cache.FlowId, out _);
|
||||||
foreach (var item in relayCache.Cache.Cdkey)
|
|
||||||
{
|
|
||||||
cdkeyLastBytes.TryRemove(item.CdkeyId, out _);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 消耗流量
|
/// 消耗流量
|
||||||
@@ -211,23 +206,40 @@ namespace linker.messenger.relay.server
|
|||||||
|
|
||||||
RelayServerCdkeyInfo currentCdkey = relayCache.Cache.Cdkey.Where(c => c.LastBytes > 0).OrderByDescending(c => c.Bandwidth).FirstOrDefault();
|
RelayServerCdkeyInfo currentCdkey = relayCache.Cache.Cdkey.Where(c => c.LastBytes > 0).OrderByDescending(c => c.Bandwidth).FirstOrDefault();
|
||||||
//有cdkey,且带宽大于节点带宽,就用cdkey的带宽
|
//有cdkey,且带宽大于节点带宽,就用cdkey的带宽
|
||||||
if (currentCdkey != null && (currentCdkey.Bandwidth == 0 || currentCdkey.Bandwidth > relayServerNodeStore.Node.MaxBandwidth))
|
if (currentCdkey != null && (currentCdkey.Bandwidth == 0 || currentCdkey.Bandwidth >= relayServerNodeStore.Node.MaxBandwidth || relayServerNodeStore.Node.MaxGbTotalLastBytes == 0))
|
||||||
{
|
{
|
||||||
relayCache.CurrentCdkey = currentCdkey;
|
relayCache.CurrentCdkey = currentCdkey;
|
||||||
relayCache.Limit.SetLimit((uint)Math.Ceiling((relayCache.CurrentCdkey.Bandwidth * 1024 * 1024) / 8.0));
|
relayCache.Limit.SetLimit((uint)Math.Ceiling((relayCache.CurrentCdkey.Bandwidth * 1024 * 1024) / 8.0));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
relayCache.CurrentCdkey = null;
|
relayCache.CurrentCdkey = null;
|
||||||
relayCache.Limit.SetLimit((uint)Math.Ceiling((relayServerNodeStore.Node.MaxBandwidth * 1024 * 1024) / 8.0));
|
relayCache.Limit.SetLimit((uint)Math.Ceiling((relayServerNodeStore.Node.MaxBandwidth * 1024 * 1024) / 8.0));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 更新剩余流量
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="dic"></param>
|
||||||
|
public void UpdateLastBytes(Dictionary<long, long> dic)
|
||||||
|
{
|
||||||
|
if (dic.Count == 0) return;
|
||||||
|
|
||||||
|
Dictionary<long, RelayServerCdkeyInfo> cdkeys = trafficDict.Values.SelectMany(c => c.Cache.Cdkey).ToDictionary(c => c.CdkeyId, c => c);
|
||||||
|
//更新剩余流量
|
||||||
|
foreach (KeyValuePair<long, long> item in dic)
|
||||||
|
{
|
||||||
|
if (cdkeys.TryGetValue(item.Key, out RelayServerCdkeyInfo info))
|
||||||
|
{
|
||||||
|
info.LastBytes = item.Value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
private void ResetNodeBytes()
|
private void ResetNodeBytes()
|
||||||
{
|
{
|
||||||
foreach (var cache in trafficDict.Values.Where(c => c.CurrentCdkey == null))
|
foreach (var cache in trafficDict.Values.Where(c => c.CurrentCdkey == null))
|
||||||
{
|
{
|
||||||
long length = cache.Sendt;
|
long length = Interlocked.Exchange(ref cache.Sendt, 0);
|
||||||
Interlocked.Exchange(ref cache.Sendt, 0);
|
|
||||||
if (relayServerNodeStore.Node.MaxGbTotalLastBytes >= length)
|
if (relayServerNodeStore.Node.MaxGbTotalLastBytes >= length)
|
||||||
relayServerNodeStore.SetMaxGbTotalLastBytes(relayServerNodeStore.Node.MaxGbTotalLastBytes - length);
|
relayServerNodeStore.SetMaxGbTotalLastBytes(relayServerNodeStore.Node.MaxGbTotalLastBytes - length);
|
||||||
else relayServerNodeStore.SetMaxGbTotalLastBytes(0);
|
else relayServerNodeStore.SetMaxGbTotalLastBytes(0);
|
||||||
@@ -239,106 +251,56 @@ namespace linker.messenger.relay.server
|
|||||||
}
|
}
|
||||||
relayServerNodeStore.Confirm();
|
relayServerNodeStore.Confirm();
|
||||||
}
|
}
|
||||||
private void DownloadBytes()
|
private async Task UploadBytes()
|
||||||
{
|
{
|
||||||
TimerHelper.Async(async () =>
|
var cdkeys = trafficDict.Values.Where(c => c.CurrentCdkey != null && c.Sendt > 0).ToList();
|
||||||
{
|
Dictionary<long, long> id2sent = cdkeys.GroupBy(c => c.CurrentCdkey.CdkeyId).ToDictionary(c => c.Key, d => d.Sum(d => { d.SendtCache = d.Sendt; return d.SendtCache; }));
|
||||||
List<long> ids = trafficDict.Values.SelectMany(c => c.Cache.Cdkey).Select(c => c.CdkeyId).Distinct().ToList();
|
if (id2sent.Count == 0) return;
|
||||||
while (ids.Count > 0)
|
|
||||||
{
|
|
||||||
//分批更新,可能数量很大
|
|
||||||
List<long> id = ids.Take(100).ToList();
|
|
||||||
ids.RemoveRange(0, id.Count);
|
|
||||||
|
|
||||||
MessageResponeInfo resp = await messengerSender.SendReply(new MessageRequestWrap
|
bool result = await messengerSender.SendOnly(new MessageRequestWrap
|
||||||
{
|
{
|
||||||
Connection = relayServerNodeStore.Node.Id == RelayServerNodeInfo.MASTER_NODE_ID ? localConnection : remoteConnection,
|
Connection = relayServerNodeStore.Node.Id == RelayServerNodeInfo.MASTER_NODE_ID ? localConnection : remoteConnection,
|
||||||
MessengerId = (ushort)RelayMessengerIds.TrafficReport,
|
MessengerId = (ushort)RelayMessengerIds.TrafficReport,
|
||||||
Payload = serializer.Serialize(new RelayTrafficUpdateInfo
|
Payload = serializer.Serialize(new RelayTrafficUpdateInfo
|
||||||
{
|
{
|
||||||
Dic = [],
|
Dic = id2sent,
|
||||||
Ids = id,
|
SecretKey = relayServerNodeStore.Node.Id == RelayServerNodeInfo.MASTER_NODE_ID
|
||||||
SecretKey = relayServerNodeStore.Node.Id == RelayServerNodeInfo.MASTER_NODE_ID
|
|
||||||
? relayServerMasterStore.Master.SecretKey
|
? relayServerMasterStore.Master.SecretKey
|
||||||
: relayServerNodeStore.Node.MasterSecretKey
|
: relayServerNodeStore.Node.MasterSecretKey
|
||||||
}),
|
}),
|
||||||
Timeout = 4000
|
Timeout = 4000
|
||||||
});
|
|
||||||
|
|
||||||
if (resp.Code == MessageResponeCodes.OK && resp.Data.Length > 0)
|
|
||||||
{
|
|
||||||
Dictionary<long, long> dic = serializer.Deserialize<Dictionary<long, long>>(resp.Data.Span);
|
|
||||||
//更新剩余流量
|
|
||||||
foreach (KeyValuePair<long, long> item in dic)
|
|
||||||
{
|
|
||||||
cdkeyLastBytes.AddOrUpdate(item.Key, item.Value, (a, b) => item.Value);
|
|
||||||
}
|
|
||||||
//查不到的,归零
|
|
||||||
foreach (long item in id.Except(dic.Keys))
|
|
||||||
{
|
|
||||||
cdkeyLastBytes.AddOrUpdate(item, 0, (a, b) => 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
|
||||||
private void UploadBytes()
|
if (result)
|
||||||
{
|
|
||||||
TimerHelper.Async(async () =>
|
|
||||||
{
|
{
|
||||||
MessageResponeInfo resp = await messengerSender.SendReply(new MessageRequestWrap
|
//成功报告了流量,就重新计数
|
||||||
|
foreach (var cache in cdkeys)
|
||||||
{
|
{
|
||||||
Connection = relayServerNodeStore.Node.Id == RelayServerNodeInfo.MASTER_NODE_ID ? localConnection : remoteConnection,
|
Interlocked.Add(ref cache.Sendt, -cache.SendtCache);
|
||||||
MessengerId = (ushort)RelayMessengerIds.TrafficReport,
|
Interlocked.Exchange(ref cache.SendtCache, 0);
|
||||||
Payload = serializer.Serialize(new RelayTrafficUpdateInfo
|
//当前cdkey流量用完了,就重新找找新的cdkey
|
||||||
{
|
if (cache.CurrentCdkey.LastBytes <= 0)
|
||||||
Dic = trafficDict.Values.Where(c => c.CurrentCdkey != null && c.Sendt > 0).GroupBy(c => c.CurrentCdkey.CdkeyId).ToDictionary(c => c.Key, d => d.Sum(d => d.Sendt)),
|
|
||||||
Ids = [],
|
|
||||||
SecretKey = relayServerNodeStore.Node.Id == RelayServerNodeInfo.MASTER_NODE_ID
|
|
||||||
? relayServerMasterStore.Master.SecretKey
|
|
||||||
: relayServerNodeStore.Node.MasterSecretKey
|
|
||||||
}),
|
|
||||||
Timeout = 4000
|
|
||||||
});
|
|
||||||
|
|
||||||
if (resp.Code == MessageResponeCodes.OK)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
serializer.Deserialize<Dictionary<string, ulong>>(resp.Data.Span);
|
|
||||||
//成功报告了流量,就重新计数
|
|
||||||
foreach (var cache in trafficDict.Values.Where(c => c.CurrentCdkey != null))
|
|
||||||
{
|
|
||||||
Interlocked.Exchange(ref cache.Sendt, 0);
|
|
||||||
//检查一下是不是需要更新剩余流量
|
|
||||||
if (cdkeyLastBytes.TryGetValue(cache.CurrentCdkey.CdkeyId, out long value))
|
|
||||||
{
|
|
||||||
cache.CurrentCdkey.LastBytes = value;
|
|
||||||
}
|
|
||||||
//当前cdkey流量用完了,就重新找找新的cdkey
|
|
||||||
if (cache.CurrentCdkey.LastBytes <= 0)
|
|
||||||
{
|
|
||||||
SetLimit(cache);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception)
|
|
||||||
{
|
{
|
||||||
|
SetLimit(cache);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
}
|
}
|
||||||
private void TrafficTask()
|
private void TrafficTask()
|
||||||
{
|
{
|
||||||
TimerHelper.SetIntervalLong(() =>
|
TimerHelper.SetIntervalLong(async () =>
|
||||||
{
|
{
|
||||||
UploadBytes();
|
try
|
||||||
DownloadBytes();
|
{
|
||||||
|
ResetNodeBytes();
|
||||||
ResetNodeBytes();
|
await UploadBytes();
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
LoggerHelper.Instance.Error(ex);
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}, 5000);
|
}, 3000);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ReportTask()
|
private void ReportTask()
|
||||||
@@ -377,7 +339,7 @@ namespace linker.messenger.relay.server
|
|||||||
IConnection connection = node.Id == RelayServerNodeInfo.MASTER_NODE_ID ? localConnection : remoteConnection;
|
IConnection connection = node.Id == RelayServerNodeInfo.MASTER_NODE_ID ? localConnection : remoteConnection;
|
||||||
IPEndPoint endPoint = await NetworkHelper.GetEndPointAsync(node.Host, relayServerNodeStore.ServicePort) ?? new IPEndPoint(IPAddress.Any, relayServerNodeStore.ServicePort);
|
IPEndPoint endPoint = await NetworkHelper.GetEndPointAsync(node.Host, relayServerNodeStore.ServicePort) ?? new IPEndPoint(IPAddress.Any, relayServerNodeStore.ServicePort);
|
||||||
|
|
||||||
RelayServerNodeReportInfo relayNodeReportInfo = new RelayServerNodeReportInfo
|
RelayServerNodeReportInfo170 relayNodeReportInfo = new RelayServerNodeReportInfo170
|
||||||
{
|
{
|
||||||
Id = node.Id,
|
Id = node.Id,
|
||||||
Name = node.Name,
|
Name = node.Name,
|
||||||
@@ -389,7 +351,8 @@ namespace linker.messenger.relay.server
|
|||||||
MaxGbTotalLastBytes = node.MaxGbTotalLastBytes,
|
MaxGbTotalLastBytes = node.MaxGbTotalLastBytes,
|
||||||
MaxConnection = node.MaxConnection,
|
MaxConnection = node.MaxConnection,
|
||||||
ConnectionRatio = Math.Round(connectionNum / 2.0),
|
ConnectionRatio = Math.Round(connectionNum / 2.0),
|
||||||
EndPoint = endPoint
|
EndPoint = endPoint,
|
||||||
|
Url = node.Url
|
||||||
};
|
};
|
||||||
|
|
||||||
await messengerSender.SendOnly(new MessageRequestWrap
|
await messengerSender.SendOnly(new MessageRequestWrap
|
||||||
@@ -465,10 +428,6 @@ namespace linker.messenger.relay.server
|
|||||||
/// cdkey id 和 流量
|
/// cdkey id 和 流量
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Dictionary<long, long> Dic { get; set; }
|
public Dictionary<long, long> Dic { get; set; }
|
||||||
/// <summary>
|
|
||||||
/// 需要知道哪些cdkey的剩余流量
|
|
||||||
/// </summary>
|
|
||||||
public List<long> Ids { get; set; }
|
|
||||||
public string SecretKey { get; set; }
|
public string SecretKey { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -104,9 +104,14 @@ namespace linker.messenger.relay.server
|
|||||||
}
|
}
|
||||||
relayWrap.Tcs.SetResult();
|
relayWrap.Tcs.SetResult();
|
||||||
|
|
||||||
RelaySpeedLimit limit = new RelaySpeedLimit();
|
RelayTrafficCacheInfo trafficCacheInfo = new RelayTrafficCacheInfo { Cache = relayCache, Sendt = 0, Limit = new RelaySpeedLimit() };
|
||||||
_ = CopyToAsync(relayCache, limit, socket, relayWrap.Socket);
|
relayServerNodeTransfer.AddTrafficCache(trafficCacheInfo);
|
||||||
_ = CopyToAsync(relayCache, limit, relayWrap.Socket, socket);
|
relayServerNodeTransfer.IncrementConnectionNum();
|
||||||
|
_ = Task.WhenAll(CopyToAsync(trafficCacheInfo, socket, relayWrap.Socket), CopyToAsync(trafficCacheInfo, relayWrap.Socket, socket)).ContinueWith((result) =>
|
||||||
|
{
|
||||||
|
relayServerNodeTransfer.DecrementConnectionNum();
|
||||||
|
relayServerNodeTransfer.RemoveTrafficCache(trafficCacheInfo);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@@ -139,15 +144,11 @@ namespace linker.messenger.relay.server
|
|||||||
ArrayPool<byte>.Shared.Return(buffer);
|
ArrayPool<byte>.Shared.Return(buffer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
private async Task CopyToAsync(RelayCacheInfo cache, RelaySpeedLimit limit, Socket source, Socket destination)
|
private async Task CopyToAsync(RelayTrafficCacheInfo trafficCacheInfo, Socket source, Socket destination)
|
||||||
{
|
{
|
||||||
RelayTrafficCacheInfo trafficCacheInfo = new RelayTrafficCacheInfo { Cache = cache, Sendt = 0, Limit = limit };
|
|
||||||
byte[] buffer = new byte[8 * 1024];
|
byte[] buffer = new byte[8 * 1024];
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
relayServerNodeTransfer.IncrementConnectionNum();
|
|
||||||
relayServerNodeTransfer.AddTrafficCache(trafficCacheInfo);
|
|
||||||
|
|
||||||
int bytesRead;
|
int bytesRead;
|
||||||
while ((bytesRead = await source.ReceiveAsync(buffer.AsMemory(), SocketFlags.None).ConfigureAwait(false)) != 0)
|
while ((bytesRead = await source.ReceiveAsync(buffer.AsMemory(), SocketFlags.None).ConfigureAwait(false)) != 0)
|
||||||
{
|
{
|
||||||
@@ -170,19 +171,19 @@ namespace linker.messenger.relay.server
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
//单个速度
|
//单个速度
|
||||||
if (limit.NeedLimit())
|
if (trafficCacheInfo.Limit.NeedLimit())
|
||||||
{
|
{
|
||||||
int length = bytesRead;
|
int length = bytesRead;
|
||||||
limit.TryLimit(ref length);
|
trafficCacheInfo.Limit.TryLimit(ref length);
|
||||||
while (length > 0)
|
while (length > 0)
|
||||||
{
|
{
|
||||||
await Task.Delay(30).ConfigureAwait(false);
|
await Task.Delay(30).ConfigureAwait(false);
|
||||||
limit.TryLimit(ref length);
|
trafficCacheInfo.Limit.TryLimit(ref length);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
AddReceive(cache.FromId, cache.FromName, cache.ToName, cache.GroupId, bytesRead);
|
AddReceive(trafficCacheInfo.Cache.FromId, trafficCacheInfo.Cache.FromName, trafficCacheInfo.Cache.ToName, trafficCacheInfo.Cache.GroupId, bytesRead);
|
||||||
AddSendt(cache.FromId, cache.FromName, cache.ToName, cache.GroupId, bytesRead);
|
AddSendt(trafficCacheInfo.Cache.FromId, trafficCacheInfo.Cache.FromName, trafficCacheInfo.Cache.ToName, trafficCacheInfo.Cache.GroupId, bytesRead);
|
||||||
await destination.SendAsync(buffer.AsMemory(0, bytesRead), SocketFlags.None).ConfigureAwait(false);
|
await destination.SendAsync(buffer.AsMemory(0, bytesRead), SocketFlags.None).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -191,8 +192,6 @@ namespace linker.messenger.relay.server
|
|||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
relayServerNodeTransfer.DecrementConnectionNum();
|
|
||||||
relayServerNodeTransfer.RemoveTrafficCache(trafficCacheInfo);
|
|
||||||
source.SafeClose();
|
source.SafeClose();
|
||||||
destination.SafeClose();
|
destination.SafeClose();
|
||||||
}
|
}
|
||||||
@@ -264,6 +263,7 @@ namespace linker.messenger.relay.server
|
|||||||
public sealed class RelayTrafficCacheInfo
|
public sealed class RelayTrafficCacheInfo
|
||||||
{
|
{
|
||||||
public long Sendt;
|
public long Sendt;
|
||||||
|
public long SendtCache;
|
||||||
public RelaySpeedLimit Limit { get; set; }
|
public RelaySpeedLimit Limit { get; set; }
|
||||||
public RelayCacheInfo Cache { get; set; }
|
public RelayCacheInfo Cache { get; set; }
|
||||||
public RelayServerCdkeyInfo CurrentCdkey { get; set; }
|
public RelayServerCdkeyInfo CurrentCdkey { get; set; }
|
||||||
|
|||||||
@@ -55,7 +55,9 @@ namespace linker.messenger.serializer.memorypack
|
|||||||
MemoryPackFormatterProvider.Register(new RelayInfo170Formatter());
|
MemoryPackFormatterProvider.Register(new RelayInfo170Formatter());
|
||||||
MemoryPackFormatterProvider.Register(new RelayServerNodeUpdateInfoFormatter());
|
MemoryPackFormatterProvider.Register(new RelayServerNodeUpdateInfoFormatter());
|
||||||
MemoryPackFormatterProvider.Register(new RelayServerNodeReportInfoFormatter());
|
MemoryPackFormatterProvider.Register(new RelayServerNodeReportInfoFormatter());
|
||||||
|
MemoryPackFormatterProvider.Register(new RelayServerNodeReportInfo170Formatter());
|
||||||
MemoryPackFormatterProvider.Register(new RelayAskResultInfoFormatter());
|
MemoryPackFormatterProvider.Register(new RelayAskResultInfoFormatter());
|
||||||
|
MemoryPackFormatterProvider.Register(new RelayAskResultInfo170Formatter());
|
||||||
MemoryPackFormatterProvider.Register(new RelayCacheInfoFormatter());
|
MemoryPackFormatterProvider.Register(new RelayCacheInfoFormatter());
|
||||||
MemoryPackFormatterProvider.Register(new RelayMessageInfoFormatter());
|
MemoryPackFormatterProvider.Register(new RelayMessageInfoFormatter());
|
||||||
MemoryPackFormatterProvider.Register(new RelayServerCdkeyInfoFormatter());
|
MemoryPackFormatterProvider.Register(new RelayServerCdkeyInfoFormatter());
|
||||||
|
|||||||
@@ -456,8 +456,6 @@ namespace linker.messenger.serializer.memorypack
|
|||||||
IPEndPoint EndPoint => info.EndPoint;
|
IPEndPoint EndPoint => info.EndPoint;
|
||||||
[MemoryPackInclude]
|
[MemoryPackInclude]
|
||||||
long LastTicks => info.LastTicks;
|
long LastTicks => info.LastTicks;
|
||||||
[MemoryPackInclude]
|
|
||||||
string Url => info.Url;
|
|
||||||
|
|
||||||
|
|
||||||
[MemoryPackConstructor]
|
[MemoryPackConstructor]
|
||||||
@@ -467,7 +465,7 @@ namespace linker.messenger.serializer.memorypack
|
|||||||
double maxGbTotal, long maxGbTotalLastBytes,
|
double maxGbTotal, long maxGbTotalLastBytes,
|
||||||
double connectionRatio, double bandwidthRatio,
|
double connectionRatio, double bandwidthRatio,
|
||||||
bool Public, int delay,
|
bool Public, int delay,
|
||||||
IPEndPoint endPoint, long lastTicks, string url)
|
IPEndPoint endPoint, long lastTicks)
|
||||||
{
|
{
|
||||||
var info = new RelayServerNodeReportInfo
|
var info = new RelayServerNodeReportInfo
|
||||||
{
|
{
|
||||||
@@ -483,8 +481,7 @@ namespace linker.messenger.serializer.memorypack
|
|||||||
MaxGbTotal = maxGbTotal,
|
MaxGbTotal = maxGbTotal,
|
||||||
MaxGbTotalLastBytes = maxGbTotalLastBytes,
|
MaxGbTotalLastBytes = maxGbTotalLastBytes,
|
||||||
Name = name,
|
Name = name,
|
||||||
Public = Public,
|
Public = Public
|
||||||
Url = url
|
|
||||||
};
|
};
|
||||||
this.info = info;
|
this.info = info;
|
||||||
}
|
}
|
||||||
@@ -521,7 +518,102 @@ namespace linker.messenger.serializer.memorypack
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[MemoryPackable]
|
||||||
|
public readonly partial struct SerializableRelayServerNodeReportInfo170
|
||||||
|
{
|
||||||
|
[MemoryPackIgnore]
|
||||||
|
public readonly RelayServerNodeReportInfo170 info;
|
||||||
|
|
||||||
|
[MemoryPackInclude]
|
||||||
|
string Id => info.Id;
|
||||||
|
[MemoryPackInclude]
|
||||||
|
string Name => info.Name;
|
||||||
|
[MemoryPackInclude]
|
||||||
|
int MaxConnection => info.MaxConnection;
|
||||||
|
[MemoryPackInclude]
|
||||||
|
double MaxBandwidth => info.MaxBandwidth;
|
||||||
|
[MemoryPackInclude]
|
||||||
|
double MaxBandwidthTotal => info.MaxBandwidthTotal;
|
||||||
|
[MemoryPackInclude]
|
||||||
|
double MaxGbTotal => info.MaxGbTotal;
|
||||||
|
[MemoryPackInclude]
|
||||||
|
long MaxGbTotalLastBytes => info.MaxGbTotalLastBytes;
|
||||||
|
[MemoryPackInclude]
|
||||||
|
double ConnectionRatio => info.ConnectionRatio;
|
||||||
|
[MemoryPackInclude]
|
||||||
|
double BandwidthRatio => info.BandwidthRatio;
|
||||||
|
[MemoryPackInclude]
|
||||||
|
bool Public => info.Public;
|
||||||
|
[MemoryPackInclude]
|
||||||
|
int Delay => info.Delay;
|
||||||
|
[MemoryPackInclude, MemoryPackAllowSerialize]
|
||||||
|
IPEndPoint EndPoint => info.EndPoint;
|
||||||
|
[MemoryPackInclude]
|
||||||
|
long LastTicks => info.LastTicks;
|
||||||
|
[MemoryPackInclude]
|
||||||
|
string Url => info.Url;
|
||||||
|
|
||||||
|
|
||||||
|
[MemoryPackConstructor]
|
||||||
|
SerializableRelayServerNodeReportInfo170(
|
||||||
|
string id, string name,
|
||||||
|
int maxConnection, double maxBandwidth, double maxBandwidthTotal,
|
||||||
|
double maxGbTotal, long maxGbTotalLastBytes,
|
||||||
|
double connectionRatio, double bandwidthRatio,
|
||||||
|
bool Public, int delay,
|
||||||
|
IPEndPoint endPoint, long lastTicks, string url)
|
||||||
|
{
|
||||||
|
var info = new RelayServerNodeReportInfo170
|
||||||
|
{
|
||||||
|
BandwidthRatio = bandwidthRatio,
|
||||||
|
ConnectionRatio = connectionRatio,
|
||||||
|
Delay = delay,
|
||||||
|
EndPoint = endPoint,
|
||||||
|
Id = id,
|
||||||
|
LastTicks = lastTicks,
|
||||||
|
MaxBandwidth = maxBandwidth,
|
||||||
|
MaxBandwidthTotal = maxBandwidthTotal,
|
||||||
|
MaxConnection = maxConnection,
|
||||||
|
MaxGbTotal = maxGbTotal,
|
||||||
|
MaxGbTotalLastBytes = maxGbTotalLastBytes,
|
||||||
|
Name = name,
|
||||||
|
Public = Public,
|
||||||
|
Url = url
|
||||||
|
};
|
||||||
|
this.info = info;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SerializableRelayServerNodeReportInfo170(RelayServerNodeReportInfo170 info)
|
||||||
|
{
|
||||||
|
this.info = info;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public class RelayServerNodeReportInfo170Formatter : MemoryPackFormatter<RelayServerNodeReportInfo170>
|
||||||
|
{
|
||||||
|
public override void Serialize<TBufferWriter>(ref MemoryPackWriter<TBufferWriter> writer, scoped ref RelayServerNodeReportInfo170 value)
|
||||||
|
{
|
||||||
|
if (value == null)
|
||||||
|
{
|
||||||
|
writer.WriteNullObjectHeader();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
writer.WritePackable(new SerializableRelayServerNodeReportInfo170(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Deserialize(ref MemoryPackReader reader, scoped ref RelayServerNodeReportInfo170 value)
|
||||||
|
{
|
||||||
|
if (reader.PeekIsNull())
|
||||||
|
{
|
||||||
|
reader.Advance(1); // skip null block
|
||||||
|
value = null;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var wrapped = reader.ReadPackable<SerializableRelayServerNodeReportInfo170>();
|
||||||
|
value = wrapped.info;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
[MemoryPackable]
|
[MemoryPackable]
|
||||||
@@ -576,6 +668,57 @@ namespace linker.messenger.serializer.memorypack
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
[MemoryPackable]
|
||||||
|
public readonly partial struct SerializableRelayAskResultInfo170
|
||||||
|
{
|
||||||
|
[MemoryPackIgnore]
|
||||||
|
public readonly RelayAskResultInfo170 info;
|
||||||
|
|
||||||
|
[MemoryPackInclude]
|
||||||
|
ulong FlowingId => info.FlowingId;
|
||||||
|
[MemoryPackInclude]
|
||||||
|
List<RelayServerNodeReportInfo170> Nodes => info.Nodes;
|
||||||
|
|
||||||
|
[MemoryPackConstructor]
|
||||||
|
SerializableRelayAskResultInfo170(ulong flowingId, List<RelayServerNodeReportInfo170> nodes)
|
||||||
|
{
|
||||||
|
var info = new RelayAskResultInfo170 { FlowingId = flowingId, Nodes = nodes };
|
||||||
|
this.info = info;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SerializableRelayAskResultInfo170(RelayAskResultInfo170 info)
|
||||||
|
{
|
||||||
|
this.info = info;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public class RelayAskResultInfo170Formatter : MemoryPackFormatter<RelayAskResultInfo170>
|
||||||
|
{
|
||||||
|
public override void Serialize<TBufferWriter>(ref MemoryPackWriter<TBufferWriter> writer, scoped ref RelayAskResultInfo170 value)
|
||||||
|
{
|
||||||
|
if (value == null)
|
||||||
|
{
|
||||||
|
writer.WriteNullObjectHeader();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
writer.WritePackable(new SerializableRelayAskResultInfo170(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Deserialize(ref MemoryPackReader reader, scoped ref RelayAskResultInfo170 value)
|
||||||
|
{
|
||||||
|
if (reader.PeekIsNull())
|
||||||
|
{
|
||||||
|
reader.Advance(1); // skip null block
|
||||||
|
value = null;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var wrapped = reader.ReadPackable<SerializableRelayAskResultInfo170>();
|
||||||
|
value = wrapped.info;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
[MemoryPackable]
|
[MemoryPackable]
|
||||||
public readonly partial struct SerializableRelayCacheInfo
|
public readonly partial struct SerializableRelayCacheInfo
|
||||||
@@ -1150,17 +1293,14 @@ namespace linker.messenger.serializer.memorypack
|
|||||||
[MemoryPackInclude]
|
[MemoryPackInclude]
|
||||||
Dictionary<long, long> Dic => info.Dic;
|
Dictionary<long, long> Dic => info.Dic;
|
||||||
[MemoryPackInclude]
|
[MemoryPackInclude]
|
||||||
List<long> Ids => info.Ids;
|
|
||||||
[MemoryPackInclude]
|
|
||||||
string SecretKey => info.SecretKey;
|
string SecretKey => info.SecretKey;
|
||||||
|
|
||||||
[MemoryPackConstructor]
|
[MemoryPackConstructor]
|
||||||
SerializableRelayTrafficUpdateInfo(Dictionary<long, long> dic, List<long> ids, string secretKey)
|
SerializableRelayTrafficUpdateInfo(Dictionary<long, long> dic, string secretKey)
|
||||||
{
|
{
|
||||||
var info = new RelayTrafficUpdateInfo
|
var info = new RelayTrafficUpdateInfo
|
||||||
{
|
{
|
||||||
Dic = dic,
|
Dic = dic,
|
||||||
Ids = ids,
|
|
||||||
SecretKey = secretKey
|
SecretKey = secretKey
|
||||||
};
|
};
|
||||||
this.info = info;
|
this.info = info;
|
||||||
|
|||||||
@@ -168,10 +168,14 @@ namespace linker.messenger.store.file.relay
|
|||||||
}
|
}
|
||||||
return await Task.FromResult(true);
|
return await Task.FromResult(true);
|
||||||
}
|
}
|
||||||
|
public async Task<Dictionary<long,long>> GetLastBytes(List<long> ids)
|
||||||
|
{
|
||||||
|
return await Task.FromResult(liteCollection.Find(c => ids.Contains(c.CdkeyId)).ToDictionary(c => c.CdkeyId, c => c.LastBytes));
|
||||||
|
}
|
||||||
|
|
||||||
public async Task<List<RelayServerCdkeyStoreInfo>> GetAvailable(string userid)
|
public async Task<List<RelayServerCdkeyStoreInfo>> GetAvailable(string userid)
|
||||||
{
|
{
|
||||||
return await Task.FromResult(liteCollection.Find(x => x.UserId == userid && x.LastBytes > 0 && x.StartTime <= DateTime.Now && x.EndTime < DateTime.Now && x.Deleted == false).ToList());
|
return await Task.FromResult(liteCollection.Find(x => x.UserId == userid && x.LastBytes > 0 && x.StartTime <= DateTime.Now && x.EndTime >= DateTime.Now && x.Deleted == false).ToList());
|
||||||
}
|
}
|
||||||
public async Task<List<RelayServerCdkeyStoreInfo>> Get(List<long> ids)
|
public async Task<List<RelayServerCdkeyStoreInfo>> Get(List<long> ids)
|
||||||
{
|
{
|
||||||
@@ -184,11 +188,11 @@ namespace linker.messenger.store.file.relay
|
|||||||
|
|
||||||
if (info.Flag.HasFlag(RelayServerCdkeyPageRequestFlag.TimeIn))
|
if (info.Flag.HasFlag(RelayServerCdkeyPageRequestFlag.TimeIn))
|
||||||
{
|
{
|
||||||
query = query.Where(x => x.EndTime > DateTime.Now);
|
query = query.Where(x => x.StartTime <= DateTime.Now && x.EndTime >= DateTime.Now);
|
||||||
}
|
}
|
||||||
if (info.Flag.HasFlag(RelayServerCdkeyPageRequestFlag.TimeOut))
|
if (info.Flag.HasFlag(RelayServerCdkeyPageRequestFlag.TimeOut))
|
||||||
{
|
{
|
||||||
query = query.Where(x => x.EndTime < DateTime.Now);
|
query = query.Where(x =>x.StartTime > DateTime.Now || x.EndTime < DateTime.Now);
|
||||||
}
|
}
|
||||||
if (info.Flag.HasFlag(RelayServerCdkeyPageRequestFlag.BytesIn))
|
if (info.Flag.HasFlag(RelayServerCdkeyPageRequestFlag.BytesIn))
|
||||||
{
|
{
|
||||||
|
|||||||
1
src/linker.web/public/archlinux.svg
Normal file
1
src/linker.web/public/archlinux.svg
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1741539824301" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="3477" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><path d="M511.904 0c-45.588 111.744-73.08 184.84-123.836 293.26 31.12 32.98 69.316 71.384 131.348 114.76-66.692-27.436-112.18-54.984-146.176-83.568C308.28 459.968 206.52 653 0 1024c162.316-93.688 288.14-151.452 405.4-173.492a297.056 297.056 0 0 1-7.704-69.512l0.196-5.2c2.576-103.968 56.672-183.92 120.752-178.496 64.08 5.428 113.892 94.168 111.32 198.14-0.488 19.56-2.696 38.384-6.552 55.84C739.404 873.96 863.88 931.576 1024 1024c-31.572-58.116-59.752-110.504-86.664-160.4-42.392-32.848-86.608-75.6-176.8-121.88 61.992 16.1 106.38 34.68 140.976 55.452C627.892 287.832 605.736 220.152 511.904 0z" fill="#1793D1" p-id="3478"></path></svg>
|
||||||
|
After Width: | Height: | Size: 962 B |
@@ -1,6 +1,5 @@
|
|||||||
import { getTunnelInfo, refreshTunnel } from "@/apis/tunnel";
|
import { getTunnelInfo, refreshTunnel } from "@/apis/tunnel";
|
||||||
import { injectGlobalData } from "@/provide";
|
import { injectGlobalData } from "@/provide";
|
||||||
import { ElMessage } from "element-plus";
|
|
||||||
import { inject, provide, ref } from "vue";
|
import { inject, provide, ref } from "vue";
|
||||||
|
|
||||||
const tunnelSymbol = Symbol();
|
const tunnelSymbol = Symbol();
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ export const provideTuntap = () => {
|
|||||||
provide(tuntapSymbol, tuntap);
|
provide(tuntapSymbol, tuntap);
|
||||||
|
|
||||||
const systems = {
|
const systems = {
|
||||||
linux: ['debian', 'ubuntu', 'alpine', 'rocky', 'centos', 'fedora'],
|
linux: ['debian', 'ubuntu', 'alpine', 'rocky', 'centos', 'fedora', 'archlinux'],
|
||||||
openwrt: ['openwrt'],
|
openwrt: ['openwrt'],
|
||||||
ubuntu: ['ubuntu'],
|
ubuntu: ['ubuntu'],
|
||||||
windows: ['windows'],
|
windows: ['windows'],
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
<div>
|
<div>
|
||||||
<el-form ref="ruleFormRef" :model="state.ruleForm" :rules="state.rules" label-width="auto">
|
<el-form ref="ruleFormRef" :model="state.ruleForm" :rules="state.rules" label-width="auto">
|
||||||
<el-form-item :label="$t('server.relayCdkeyUserId')" prop="UserId">
|
<el-form-item :label="$t('server.relayCdkeyUserId')" prop="UserId">
|
||||||
<el-input maxlength="32" show-word-limit v-model="state.ruleForm.UserId" />
|
<el-input maxlength="36" show-word-limit v-model="state.ruleForm.UserId" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item :label="$t('server.relayCdkeyBandwidth')" prop="Bandwidth">
|
<el-form-item :label="$t('server.relayCdkeyBandwidth')" prop="Bandwidth">
|
||||||
<el-input-number size="small" v-model="state.ruleForm.Bandwidth" :min="1" :max="102400" />Mbps
|
<el-input-number size="small" v-model="state.ruleForm.Bandwidth" :min="1" :max="102400" />Mbps
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
v1.6.9
|
v1.6.9
|
||||||
2025-03-09 18:12:09
|
2025-03-10 17:55:18
|
||||||
1. 优化linux下路由跟踪问题
|
1. 优化linux下路由跟踪问题
|
||||||
2. 优化linux下获取本机IP问题
|
2. 优化linux下获取本机IP问题
|
||||||
3. 增加ICS,让win7+、win server2008+支持NAT
|
3. 增加ICS,让win7+、win server2008+支持NAT
|
||||||
|
|||||||
Reference in New Issue
Block a user