This commit is contained in:
snltty
2025-03-09 18:12:10 +08:00
parent 342dbe5e8c
commit 64cba16fe0
48 changed files with 802 additions and 124 deletions

View File

@@ -0,0 +1,57 @@
<?php
declare(strict_types=1);
namespace App\Plugin\Demo\Controller;
use App\Controller\Base\API\UserPlugin;
use App\Interceptor\Waf;
use App\Entity\CreateObjectEntity;
use App\Entity\DeleteBatchEntity;
use App\Entity\QueryTemplateEntity;
use App\Service\Query;
use App\Util\Date;
use Illuminate\Database\Eloquent\Relations\Relation;
use Kernel\Annotation\Inject;
use Kernel\Annotation\Interceptor;
use Kernel\Exception\JSONException;
use App\Model\Card;
use App\Model\Commodity;
class Api extends UserPlugin
{
#[Inject]
private Query $query;
public function check():string {
$num = (int)($_REQUEST['num'] ?? 10);
$key = $_REQUEST['key'];
if ($key != getPluginConfig("Demo")['KeyId']) {
return "fail";
}
$list = Commodity::query()->where("status", 1)->get();
foreach($list as $item)
{
try{
$delivery_message = json_decode($item["delivery_message"],true);
$commodity_id = $item["id"];
$count = Card::query()->where("commodity_id", (int)$commodity_id)->where("status", 0)->count();
if($count < $num)
{
for($i = 0; $i < $num; $i++)
{
$cardObj = new \App\Model\Card();
$cardObj->commodity_id = $commodity_id;
$cardObj->owner = 0;
$cardObj->secret = json_encode($delivery_message,JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
$cardObj->create_time = Date::current();
$cardObj->save();
}
}
}catch(\Exception $e){
}
}
return "ok";
}
}

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 48 KiB

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 48 KiB

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

After

Width:  |  Height:  |  Size: 17 KiB

View File

@@ -162,7 +162,7 @@ namespace linker.messenger.relay
return new RelayServerCdkeyTestResultInfo();
}
public async Task<bool> ImportCdkey(ApiControllerParamsInfo param)
public async Task<string> ImportCdkey(ApiControllerParamsInfo param)
{
RelayServerCdkeyImportInfo info = param.Content.DeJson<RelayServerCdkeyImportInfo>();
info.SecretKey = relayClientStore.Server.SecretKey;
@@ -173,6 +173,25 @@ namespace linker.messenger.relay
MessengerId = (ushort)RelayMessengerIds.ImportCdkey,
Payload = serializer.Serialize(info)
});
if (resp.Code == MessageResponeCodes.OK)
{
return serializer.Deserialize<string>(resp.Data.Span);
}
return "Network";
}
public async Task<bool> UpdateNode(ApiControllerParamsInfo param)
{
RelayServerNodeUpdateInfo info = param.Content.DeJson<RelayServerNodeUpdateInfo>();
var resp = await messengerSender.SendReply(new MessageRequestWrap
{
Connection = signInClientState.Connection,
MessengerId = (ushort)RelayMessengerIds.UpdateNodeForward,
Payload = serializer.Serialize(new RelayServerNodeUpdateWrapInfo
{
Info = info,
SecretKey = relayClientStore.Server.SecretKey
})
});
return resp.Code == MessageResponeCodes.OK && resp.Data.Span.SequenceEqual(Helper.TrueArray);
}
}

View File

@@ -43,7 +43,7 @@ namespace linker.messenger.relay
IRelayClientTransport transport = relayTransfer.Transports.FirstOrDefault(d => d.Type == relayClientStore.Server.RelayType);
if (transport != null)
{
Nodes = await transport.RelayTestAsync(new RelayTestInfo
Nodes = await transport.RelayTestAsync(new RelayTestInfo170
{
MachineId = signInClientStore.Id,
SecretKey = relayClientStore.Server.SecretKey,

View File

@@ -78,7 +78,7 @@ namespace linker.messenger.relay.client
return null;
}
transport.RelayInfo relayInfo = new transport.RelayInfo
transport.RelayInfo170 relayInfo = new transport.RelayInfo170
{
FlowingId = 0,
FromMachineId = fromMachineId,
@@ -126,7 +126,7 @@ namespace linker.messenger.relay.client
/// </summary>
/// <param name="relayInfo"></param>
/// <returns></returns>
public async Task<bool> OnBeginAsync(transport.RelayInfo relayInfo)
public async Task<bool> OnBeginAsync(transport.RelayInfo170 relayInfo)
{
if (connectingDic.TryAdd(relayInfo.FromMachineId, true) == false)
{
@@ -173,7 +173,7 @@ namespace linker.messenger.relay.client
/// </summary>
/// <param name="relayInfo"></param>
/// <param name="connection"></param>
private void ConnectedCallback(transport.RelayInfo relayInfo, ITunnelConnection connection)
private void ConnectedCallback(transport.RelayInfo170 relayInfo, ITunnelConnection connection)
{
if (OnConnected.TryGetValue(Helper.GlobalString, out List<Action<ITunnelConnection>> callbacks))
{

View File

@@ -34,37 +34,51 @@ namespace linker.messenger.relay.client.transport
/// </summary>
/// <param name="relayInfo"></param>
/// <returns></returns>
public Task<ITunnelConnection> RelayAsync(RelayInfo relayInfo);
public Task<ITunnelConnection> RelayAsync(RelayInfo170 relayInfo);
/// <summary>
/// 收到别人的中继请求
/// </summary>
/// <param name="relayInfo"></param>
/// <returns></returns>
public Task<bool> OnBeginAsync(RelayInfo relayInfo, Action<ITunnelConnection> callback);
public Task<bool> OnBeginAsync(RelayInfo170 relayInfo, Action<ITunnelConnection> callback);
/// <summary>
/// 测试一下中继通不通
/// </summary>
/// <param name="relayTestInfo"></param>
/// <returns></returns>
public Task<List<RelayServerNodeReportInfo>> RelayTestAsync(RelayTestInfo relayTestInfo);
public Task<List<RelayServerNodeReportInfo>> RelayTestAsync(RelayTestInfo170 relayTestInfo);
}
/// <summary>
/// 中继测试
/// </summary>
public sealed partial class RelayTestInfo
public partial class RelayTestInfo
{
public string MachineId { get; set; }
public string SecretKey { get; set; }
public IPEndPoint Server { get; set; }
}
public sealed partial class RelayTestInfo170: RelayTestInfo
{
/// <summary>
/// UserId
/// </summary>
public string UserId { get; set; }
}
public partial class RelayInfo170 : RelayInfo
{
/// <summary>
/// UserId
/// </summary>
public string UserId { get; set; }
}
/// <summary>
/// 中继交换数据
/// </summary>
public sealed partial class RelayInfo
public partial class RelayInfo
{
/// <summary>
/// 自己的id
@@ -114,10 +128,7 @@ namespace linker.messenger.relay.client.transport
/// </summary>
public bool SSL { get; set; } = true;
/// <summary>
/// UserId
/// </summary>
public string UserId { get; set; }
}

View File

@@ -38,7 +38,7 @@ namespace linker.messenger.relay.client.transport
this.messengerStore = messengerStore;
}
public async Task<ITunnelConnection> RelayAsync(RelayInfo relayInfo)
public async Task<ITunnelConnection> RelayAsync(RelayInfo170 relayInfo)
{
byte[] buffer = ArrayPool<byte>.Shared.Rent(1024);
try
@@ -119,12 +119,12 @@ namespace linker.messenger.relay.client.transport
return null;
}
private async Task<RelayAskResultInfo> RelayAsk(RelayInfo relayInfo)
private async Task<RelayAskResultInfo> RelayAsk(RelayInfo170 relayInfo)
{
MessageResponeInfo resp = await messengerSender.SendReply(new MessageRequestWrap
{
Connection = signInClientState.Connection,
MessengerId = (ushort)RelayMessengerIds.RelayAsk,
MessengerId = (ushort)RelayMessengerIds.RelayAsk170,
Payload = serializer.Serialize(relayInfo),
Timeout = 2000
}).ConfigureAwait(false);
@@ -138,7 +138,7 @@ namespace linker.messenger.relay.client.transport
return result;
}
private async Task<Socket> ConnectNodeServer(RelayInfo relayInfo, List<RelayServerNodeReportInfo> nodes)
private async Task<Socket> ConnectNodeServer(RelayInfo170 relayInfo, List<RelayServerNodeReportInfo> nodes)
{
byte[] buffer = ArrayPool<byte>.Shared.Rent(1 * 1024);
@@ -211,13 +211,13 @@ namespace linker.messenger.relay.client.transport
}
return null;
}
private async Task<bool> RelayConfirm(RelayInfo relayInfo)
private async Task<bool> RelayConfirm(RelayInfo170 relayInfo)
{
//通知对方去确认中继
var resp = await messengerSender.SendReply(new MessageRequestWrap
{
Connection = signInClientState.Connection,
MessengerId = (ushort)RelayMessengerIds.RelayForward,
MessengerId = (ushort)RelayMessengerIds.RelayForward170,
Payload = serializer.Serialize(relayInfo),
});
return resp.Code == MessageResponeCodes.OK && resp.Data.Span.SequenceEqual(Helper.TrueArray);
@@ -228,7 +228,7 @@ namespace linker.messenger.relay.client.transport
{
return true;
}
public async Task<bool> OnBeginAsync(RelayInfo relayInfo, Action<ITunnelConnection> callback)
public async Task<bool> OnBeginAsync(RelayInfo170 relayInfo, Action<ITunnelConnection> callback)
{
try
{
@@ -267,7 +267,7 @@ namespace linker.messenger.relay.client.transport
return false;
}
private async Task<TunnelConnectionTcp> WaitSSL(Socket socket, RelayInfo relayInfo)
private async Task<TunnelConnectionTcp> WaitSSL(Socket socket, RelayInfo170 relayInfo)
{
try
{
@@ -306,14 +306,14 @@ namespace linker.messenger.relay.client.transport
return null;
}
public async Task<List<RelayServerNodeReportInfo>> RelayTestAsync(RelayTestInfo relayTestInfo)
public async Task<List<RelayServerNodeReportInfo>> RelayTestAsync(RelayTestInfo170 relayTestInfo)
{
try
{
MessageResponeInfo resp = await messengerSender.SendReply(new MessageRequestWrap
{
Connection = signInClientState.Connection,
MessengerId = (ushort)RelayMessengerIds.RelayTest,
MessengerId = (ushort)RelayMessengerIds.RelayTest170,
Payload = serializer.Serialize(relayTestInfo),
Timeout = 2000
}).ConfigureAwait(false);

View File

@@ -30,7 +30,7 @@ namespace linker.messenger.relay.messenger
[MessengerId((ushort)RelayMessengerIds.Relay)]
public async Task Relay(IConnection connection)
{
client.transport.RelayInfo info = serializer.Deserialize<client.transport.RelayInfo>(connection.ReceiveRequestWrap.Payload.Span);
client.transport.RelayInfo170 info = serializer.Deserialize<client.transport.RelayInfo170>(connection.ReceiveRequestWrap.Payload.Span);
bool res = await relayTransfer.OnBeginAsync(info).ConfigureAwait(false);
connection.Write(res ? Helper.TrueArray : Helper.FalseArray);
}
@@ -48,8 +48,9 @@ namespace linker.messenger.relay.messenger
private readonly ISerializer serializer;
private readonly IRelayServerCdkeyStore relayServerCdkeyStore;
private readonly IRelayServerStore relayServerStore;
private readonly RelayServerNodeTransfer relayServerNodeTransfer;
public RelayServerMessenger(IMessengerSender messengerSender, SignInServerCaching signCaching, ISerializer serializer, RelayServerMasterTransfer relayServerTransfer, RelayServerValidatorTransfer relayValidatorTransfer, IRelayServerCdkeyStore relayServerCdkeyStore, IRelayServerStore relayServerStore)
public RelayServerMessenger(IMessengerSender messengerSender, SignInServerCaching signCaching, ISerializer serializer, RelayServerMasterTransfer relayServerTransfer, RelayServerValidatorTransfer relayValidatorTransfer, IRelayServerCdkeyStore relayServerCdkeyStore, IRelayServerStore relayServerStore, RelayServerNodeTransfer relayServerNodeTransfer)
{
this.messengerSender = messengerSender;
this.signCaching = signCaching;
@@ -58,6 +59,7 @@ namespace linker.messenger.relay.messenger
this.serializer = serializer;
this.relayServerCdkeyStore = relayServerCdkeyStore;
this.relayServerStore = relayServerStore;
this.relayServerNodeTransfer = relayServerNodeTransfer;
}
/// <summary>
@@ -68,6 +70,16 @@ namespace linker.messenger.relay.messenger
public async Task RelayTest(IConnection connection)
{
RelayTestInfo info = serializer.Deserialize<RelayTestInfo>(connection.ReceiveRequestWrap.Payload.Span);
await RelayTest(connection, info);
}
[MessengerId((ushort)RelayMessengerIds.RelayTest170)]
public async Task RelayTest170(IConnection connection)
{
RelayTestInfo170 info = serializer.Deserialize<RelayTestInfo170>(connection.ReceiveRequestWrap.Payload.Span);
await RelayTest(connection, info);
}
private async Task RelayTest(IConnection connection, RelayTestInfo info)
{
if (signCaching.TryGet(connection.Id, out SignCacheInfo cache) == false)
{
connection.Write(Helper.FalseArray);
@@ -86,7 +98,6 @@ namespace linker.messenger.relay.messenger
connection.Write(serializer.Serialize(nodes));
}
/// <summary>
/// 请求中继
/// </summary>
@@ -95,6 +106,18 @@ namespace linker.messenger.relay.messenger
public async Task RelayAsk(IConnection connection)
{
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)
{
connection.Write(serializer.Serialize(new RelayAskResultInfo { }));
@@ -111,11 +134,9 @@ namespace linker.messenger.relay.messenger
bool validated = string.IsNullOrWhiteSpace(error);
result.Nodes = relayServerTransfer.GetNodes(validated);
List<RelayServerCdkeyStoreInfo> cdkeys = await relayServerCdkeyStore.GetAvailable(info.UserId);
if (result.Nodes.Count > 0)
{
result.FlowingId = relayServerTransfer.AddRelay(cacheFrom.MachineId, cacheFrom.MachineName, cacheTo.MachineId, cacheTo.MachineName, cacheFrom.GroupId, validated, cdkeys.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);
}
connection.Write(serializer.Serialize(result));
@@ -129,7 +150,23 @@ namespace linker.messenger.relay.messenger
[MessengerId((ushort)RelayMessengerIds.RelayForward)]
public async Task RelayForward(IConnection connection)
{
client.transport.RelayInfo info = serializer.Deserialize<client.transport.RelayInfo>(connection.ReceiveRequestWrap.Payload.Span);
RelayInfo info = serializer.Deserialize<RelayInfo>(connection.ReceiveRequestWrap.Payload.Span);
await RelayForward(connection, info, () =>
{
return serializer.Serialize(info);
});
}
[MessengerId((ushort)RelayMessengerIds.RelayForward170)]
public async Task RelayForward170(IConnection connection)
{
RelayInfo170 info = serializer.Deserialize<RelayInfo170>(connection.ReceiveRequestWrap.Payload.Span);
await RelayForward(connection, info, () =>
{
return serializer.Serialize(info);
});
}
public async Task RelayForward(IConnection connection, RelayInfo info, Func<byte[]> data)
{
if (signCaching.TryGet(connection.Id, out SignCacheInfo cacheFrom) == false || signCaching.TryGet(info.RemoteMachineId, out SignCacheInfo cacheTo) == false || cacheFrom.GroupId != cacheTo.GroupId)
{
connection.Write(Helper.FalseArray);
@@ -161,7 +198,7 @@ namespace linker.messenger.relay.messenger
{
Connection = cacheTo.Connection,
MessengerId = (ushort)RelayMessengerIds.Relay,
Payload = serializer.Serialize(info)
Payload = data()
}).ConfigureAwait(false);
if (resp.Code == MessageResponeCodes.OK && resp.Data.Span.SequenceEqual(Helper.TrueArray))
{
@@ -210,6 +247,40 @@ namespace linker.messenger.relay.messenger
}
relayServerTransfer.SetNodeReport(connection, info);
}
/// <summary>
/// 更新节点
/// </summary>
/// <param name="connection"></param>
/// <returns></returns>
[MessengerId((ushort)RelayMessengerIds.UpdateNode)]
public void UpdateNode(IConnection connection)
{
RelayServerNodeUpdateInfo info = serializer.Deserialize<RelayServerNodeUpdateInfo>(connection.ReceiveRequestWrap.Payload.Span);
if (relayServerNodeTransfer.Id == info.Id)
{
relayServerNodeTransfer.UpdateNode(info);
}
}
/// <summary>
/// 更新节点转发
/// </summary>
/// <param name="connection"></param>
/// <returns></returns>
[MessengerId((ushort)RelayMessengerIds.UpdateNodeForward)]
public async Task UpdateNodeForward(IConnection connection)
{
RelayServerNodeUpdateWrapInfo info = serializer.Deserialize<RelayServerNodeUpdateWrapInfo>(connection.ReceiveRequestWrap.Payload.Span);
if (info.SecretKey == relayServerStore.SecretKey)
{
await relayServerTransfer.UpdateNodeReport(info.Info);
connection.Write(Helper.TrueArray);
}
else
{
connection.Write(Helper.FalseArray);
}
}
/// <summary>
/// 消耗流量报告
/// </summary>
@@ -283,7 +354,7 @@ namespace linker.messenger.relay.messenger
}
else
{
await relayServerCdkeyStore.Del(info.CdkeyId,info.UserId);
await relayServerCdkeyStore.Del(info.CdkeyId, info.UserId);
}
connection.Write(Helper.TrueArray);
}
@@ -351,8 +422,8 @@ namespace linker.messenger.relay.messenger
connection.Write(Helper.FalseArray);
return;
}
bool result = await relayServerCdkeyStore.Import(info);
connection.Write(result ? Helper.TrueArray : Helper.FalseArray);
string result = await relayServerCdkeyStore.Import(info);
connection.Write(serializer.Serialize(result));
}
}
}

View File

@@ -29,6 +29,11 @@
ImportCdkey = 2116,
UpdateNode = 2117,
UpdateNodeForward = 2118,
RelayTest170 = 2119,
RelayAsk170 = 2120,
RelayForward170 = 2121,
Max = 2199
}

View File

@@ -33,7 +33,7 @@
/// </summary>
/// <param name="base64"></param>
/// <returns></returns>
public Task<bool> Import(RelayServerCdkeyImportInfo info);
public Task<string> Import(RelayServerCdkeyImportInfo info);
/// <summary>
/// 获取有效的CDKEY
@@ -249,5 +249,6 @@
/// </summary>
public int Count { get; set; }
public string Type { get; set; }
}
}

View File

@@ -1,6 +1,7 @@
using linker.libs;
using System.Net;
using linker.libs.extends;
using System.Text.Json.Serialization;
namespace linker.messenger.relay.server
{
@@ -80,10 +81,17 @@ namespace linker.messenger.relay.server
#else
public string MasterSecretKey { get; set; } = string.Empty;
#endif
public string Url { get; set; } = "https://linker-doc.snltty.com";
}
public sealed partial class RelayServerNodeUpdateWrapInfo
{
public string SecretKey { get; set; }
public RelayServerNodeUpdateInfo Info { get; set; }
}
public sealed partial class RelayServerNodeUpdateInfo
{
public string Id { get; set; } = string.Empty;
public string Name { get; set; } = string.Empty;
public int MaxConnection { get; set; }
@@ -92,6 +100,8 @@ namespace linker.messenger.relay.server
public double MaxGbTotal { get; set; }
public long MaxGbTotalLastBytes { get; set; }
public bool Public { get; set; }
public string Url { get; set; } = "https://linker-doc.snltty.com";
}
public sealed partial class RelayServerNodeReportInfo
{
@@ -114,6 +124,11 @@ namespace linker.messenger.relay.server
public IPEndPoint EndPoint { get; set; }
public long LastTicks { get; set; }
public string Url { get; set; } = "https://linker-doc.snltty.com";
[JsonIgnore]
public IConnection Connection { get; set; }
}
public sealed partial class RelayAskResultInfo

View File

@@ -1,4 +1,5 @@
using linker.libs;
using linker.messenger.relay.messenger;
using linker.messenger.relay.server.caching;
using System.Collections.Concurrent;
using System.Net;
@@ -18,11 +19,14 @@ namespace linker.messenger.relay.server
private readonly IRelayServerCaching relayCaching;
private readonly ISerializer serializer;
private readonly IRelayServerCdkeyStore relayServerCdkeyStore;
public RelayServerMasterTransfer(IRelayServerCaching relayCaching, ISerializer serializer, IRelayServerMasterStore relayServerMasterStore, IRelayServerCdkeyStore relayServerCdkeyStore)
private readonly IMessengerSender messengerSender;
public RelayServerMasterTransfer(IRelayServerCaching relayCaching, ISerializer serializer, IRelayServerMasterStore relayServerMasterStore, IRelayServerCdkeyStore relayServerCdkeyStore, IMessengerSender messengerSender)
{
this.relayCaching = relayCaching;
this.serializer = serializer;
this.relayServerCdkeyStore = relayServerCdkeyStore;
this.messengerSender = messengerSender;
TrafficTask();
}
@@ -70,6 +74,7 @@ namespace linker.messenger.relay.server
info.EndPoint.Address = connection.Address.Address;
}
info.LastTicks = Environment.TickCount64;
info.Connection = connection;
reports.AddOrUpdate(info.Id, info, (a, b) => info);
}
catch (Exception ex)
@@ -80,6 +85,25 @@ namespace linker.messenger.relay.server
}
}
}
/// <summary>
/// 更新节点
/// </summary>
/// <param name="info"></param>
public async Task UpdateNodeReport(RelayServerNodeUpdateInfo info)
{
if (RelayServerNodeInfo.MASTER_NODE_ID == info.Id) return;
if (reports.TryGetValue(info.Id, out RelayServerNodeReportInfo cache))
{
await messengerSender.SendOnly(new MessageRequestWrap
{
Connection = cache.Connection,
MessengerId = (ushort)RelayMessengerIds.UpdateNode,
Payload = serializer.Serialize(info)
});
}
}
/// <summary>
/// 获取节点列表
/// </summary>
@@ -90,7 +114,7 @@ namespace linker.messenger.relay.server
var result = reports.Values
.Where(c => c.Public || validated)
.Where(c => Environment.TickCount64 - c.LastTicks < 15000)
.Where(c => c.ConnectionRatio < 100 && (c.MaxGbTotal == 0 || (c.MaxGbTotal > 0 && c.MaxGbTotalLastBytes > 0)))
.Where(c => validated || (c.ConnectionRatio < 100 && (c.MaxGbTotal == 0 || (c.MaxGbTotal > 0 && c.MaxGbTotalLastBytes > 0))))
.OrderByDescending(c => c.LastTicks);
return result.OrderByDescending(x => x.MaxConnection == 0 ? int.MaxValue : x.MaxConnection)
@@ -113,7 +137,11 @@ namespace linker.messenger.relay.server
return reports.TryGetValue(nodeId, out RelayServerNodeReportInfo relayNodeReportInfo) && relayNodeReportInfo.Public == false;
}
/// <summary>
/// 消耗流量
/// </summary>
/// <param name="relayTrafficUpdateInfo"></param>
/// <returns></returns>
public async Task<Dictionary<long, long>> AddTraffic(RelayTrafficUpdateInfo relayTrafficUpdateInfo)
{
if (relayTrafficUpdateInfo.Dic.Count > 0)
@@ -134,7 +162,7 @@ namespace linker.messenger.relay.server
await relayServerCdkeyStore.Traffic(dic).ConfigureAwait(false);
}
return true;
},3000);
}, 3000);
}
}
}

View File

@@ -13,6 +13,8 @@ namespace linker.messenger.relay.server
/// </summary>
public class RelayServerNodeTransfer
{
public string Id=>relayServerNodeStore.Node.Id;
private uint connectionNum = 0;
private IConnection localConnection;
private IConnection remoteConnection;
@@ -70,6 +72,11 @@ namespace linker.messenger.relay.server
return null;
}
public void UpdateNode(RelayServerNodeUpdateInfo info)
{
relayServerNodeStore.UpdateInfo(info);
}
/// <summary>
/// 无效请求
/// </summary>

View File

@@ -50,7 +50,9 @@ namespace linker.messenger.serializer.memorypack
MemoryPackFormatterProvider.Register(new RelayTestInfoFormatter());
MemoryPackFormatterProvider.Register(new RelayTestInfo170Formatter());
MemoryPackFormatterProvider.Register(new RelayInfoFormatter());
MemoryPackFormatterProvider.Register(new RelayInfo170Formatter());
MemoryPackFormatterProvider.Register(new RelayServerNodeUpdateInfoFormatter());
MemoryPackFormatterProvider.Register(new RelayServerNodeReportInfoFormatter());
MemoryPackFormatterProvider.Register(new RelayAskResultInfoFormatter());
@@ -67,6 +69,9 @@ namespace linker.messenger.serializer.memorypack
MemoryPackFormatterProvider.Register(new RelayServerCdkeyTestResultInfoFormatter());
MemoryPackFormatterProvider.Register(new RelayServerCdkeyOrderInfoFormatter());
MemoryPackFormatterProvider.Register(new RelayServerNodeUpdateInfoFormatter());
MemoryPackFormatterProvider.Register(new RelayServerNodeUpdateWrapInfoFormatter());
MemoryPackFormatterProvider.Register(new AccessUpdateInfoFormatter());
MemoryPackFormatterProvider.Register(new AccessInfoFormatter());

View File

@@ -2,6 +2,7 @@
using linker.messenger.relay.server;
using MemoryPack;
using System.Net;
using System.Xml.Linq;
namespace linker.messenger.serializer.memorypack
{
@@ -18,13 +19,11 @@ namespace linker.messenger.serializer.memorypack
[MemoryPackInclude, MemoryPackAllowSerialize]
IPEndPoint Server => info.Server;
[MemoryPackInclude]
string UserId => info.UserId;
[MemoryPackConstructor]
SerializableRelayTestInfo(string machineId, string secretKey, IPEndPoint server, string userid)
SerializableRelayTestInfo(string machineId, string secretKey, IPEndPoint server)
{
var info = new RelayTestInfo { MachineId = machineId, SecretKey = secretKey, Server = server, UserId = userid };
var info = new RelayTestInfo { MachineId = machineId, SecretKey = secretKey, Server = server };
this.info = info;
}
@@ -61,6 +60,62 @@ namespace linker.messenger.serializer.memorypack
}
[MemoryPackable]
public readonly partial struct SerializableRelayTestInfo170
{
[MemoryPackIgnore]
public readonly RelayTestInfo170 info;
[MemoryPackInclude]
string MachineId => info.MachineId;
[MemoryPackInclude]
string SecretKey => info.SecretKey;
[MemoryPackInclude, MemoryPackAllowSerialize]
IPEndPoint Server => info.Server;
[MemoryPackInclude]
string UserId => info.UserId;
[MemoryPackConstructor]
SerializableRelayTestInfo170(string machineId, string secretKey, IPEndPoint server, string userid)
{
var info = new RelayTestInfo170 { MachineId = machineId, SecretKey = secretKey, Server = server, UserId = userid };
this.info = info;
}
public SerializableRelayTestInfo170(RelayTestInfo170 info)
{
this.info = info;
}
}
public class RelayTestInfo170Formatter : MemoryPackFormatter<RelayTestInfo170>
{
public override void Serialize<TBufferWriter>(ref MemoryPackWriter<TBufferWriter> writer, scoped ref RelayTestInfo170 value)
{
if (value == null)
{
writer.WriteNullObjectHeader();
return;
}
writer.WritePackable(new SerializableRelayTestInfo170(value));
}
public override void Deserialize(ref MemoryPackReader reader, scoped ref RelayTestInfo170 value)
{
if (reader.PeekIsNull())
{
reader.Advance(1); // skip null block
value = null;
return;
}
var wrapped = reader.ReadPackable<SerializableRelayTestInfo170>();
value = wrapped.info;
}
}
[MemoryPackable]
public readonly partial struct SerializableRelayInfo
@@ -91,14 +146,12 @@ namespace linker.messenger.serializer.memorypack
[MemoryPackInclude]
bool SSL => info.SSL;
[MemoryPackInclude]
string UserId => info.UserId;
[MemoryPackConstructor]
SerializableRelayInfo(string fromMachineId, string fromMachineName,
string remoteMachineId, string remoteMachineName,
string transactionId, string secretKey, string transportName, ulong flowingId,
string nodeId, IPEndPoint server, bool ssl, string userid)
string nodeId, IPEndPoint server, bool ssl)
{
var info = new RelayInfo
{
@@ -112,8 +165,7 @@ namespace linker.messenger.serializer.memorypack
TransactionId = transactionId,
TransportName = transportName,
SecretKey = secretKey,
Server = server,
UserId = userid
Server = server
};
this.info = info;
}
@@ -150,12 +202,103 @@ namespace linker.messenger.serializer.memorypack
}
}
[MemoryPackable]
public readonly partial struct SerializableRelayInfo170
{
[MemoryPackIgnore]
public readonly RelayInfo170 info;
[MemoryPackInclude]
string FromMachineId => info.FromMachineId;
[MemoryPackInclude]
string FromMachineName => info.FromMachineName;
[MemoryPackInclude]
string RemoteMachineId => info.RemoteMachineId;
[MemoryPackInclude]
string RemoteMachineName => info.RemoteMachineName;
[MemoryPackInclude]
string TransactionId => info.TransactionId;
[MemoryPackInclude]
string SecretKey => info.SecretKey;
[MemoryPackInclude]
string TransportName => info.TransportName;
[MemoryPackInclude]
ulong FlowingId => info.FlowingId;
[MemoryPackInclude]
string NodeId => info.NodeId;
[MemoryPackInclude, MemoryPackAllowSerialize]
IPEndPoint Server => info.Server;
[MemoryPackInclude]
bool SSL => info.SSL;
[MemoryPackInclude]
string UserId => info.UserId;
[MemoryPackConstructor]
SerializableRelayInfo170(string fromMachineId, string fromMachineName,
string remoteMachineId, string remoteMachineName,
string transactionId, string secretKey, string transportName, ulong flowingId,
string nodeId, IPEndPoint server, bool ssl, string userid)
{
var info = new RelayInfo170
{
FlowingId = flowingId,
FromMachineId = fromMachineId,
FromMachineName = fromMachineName,
NodeId = nodeId,
RemoteMachineId = remoteMachineId,
RemoteMachineName = remoteMachineName,
SSL = ssl,
TransactionId = transactionId,
TransportName = transportName,
SecretKey = secretKey,
Server = server,
UserId = userid
};
this.info = info;
}
public SerializableRelayInfo170(RelayInfo170 relayInfo)
{
this.info = relayInfo;
}
}
public class RelayInfo170Formatter : MemoryPackFormatter<RelayInfo170>
{
public override void Serialize<TBufferWriter>(ref MemoryPackWriter<TBufferWriter> writer, scoped ref RelayInfo170 value)
{
if (value == null)
{
writer.WriteNullObjectHeader();
return;
}
writer.WritePackable(new SerializableRelayInfo170(value));
}
public override void Deserialize(ref MemoryPackReader reader, scoped ref RelayInfo170 value)
{
if (reader.PeekIsNull())
{
reader.Advance(1); // skip null block
value = null;
return;
}
var wrapped = reader.ReadPackable<SerializableRelayInfo170>();
value = wrapped.info;
}
}
[MemoryPackable]
public readonly partial struct SerializableRelayServerNodeUpdateInfo
{
[MemoryPackIgnore]
public readonly RelayServerNodeUpdateInfo info;
[MemoryPackInclude]
string Id => info.Id;
[MemoryPackInclude]
string Name => info.Name;
[MemoryPackInclude]
@@ -170,23 +313,27 @@ namespace linker.messenger.serializer.memorypack
long MaxGbTotalLastBytes => info.MaxGbTotalLastBytes;
[MemoryPackInclude]
bool Public => info.Public;
[MemoryPackInclude]
string Url => info.Url;
[MemoryPackConstructor]
SerializableRelayServerNodeUpdateInfo(
string name,
string id, string name,
int maxConnection, double maxBandwidth, double maxBandwidthTotal,
double maxGbTotal, long maxGbTotalLastBytes,
bool Public)
bool Public, string url)
{
var info = new RelayServerNodeUpdateInfo
{
Id = id,
MaxBandwidth = maxBandwidth,
MaxBandwidthTotal = maxBandwidthTotal,
MaxConnection = maxConnection,
MaxGbTotal = maxGbTotal,
MaxGbTotalLastBytes = maxGbTotalLastBytes,
Name = name,
Public = Public
Public = Public,
Url = url
};
this.info = info;
}
@@ -222,6 +369,59 @@ namespace linker.messenger.serializer.memorypack
value = wrapped.info;
}
}
[MemoryPackable]
public readonly partial struct SerializableRelayServerNodeUpdateWrapInfo
{
[MemoryPackIgnore]
public readonly RelayServerNodeUpdateWrapInfo info;
[MemoryPackInclude]
string SecretKey => info.SecretKey;
[MemoryPackInclude, MemoryPackAllowSerialize]
RelayServerNodeUpdateInfo Info => info.Info;
[MemoryPackConstructor]
SerializableRelayServerNodeUpdateWrapInfo(
string secretKey, RelayServerNodeUpdateInfo info)
{
this.info = new RelayServerNodeUpdateWrapInfo
{
SecretKey = secretKey,
Info = info
};
}
public SerializableRelayServerNodeUpdateWrapInfo(RelayServerNodeUpdateWrapInfo info)
{
this.info = info;
}
}
public class RelayServerNodeUpdateWrapInfoFormatter : MemoryPackFormatter<RelayServerNodeUpdateWrapInfo>
{
public override void Serialize<TBufferWriter>(ref MemoryPackWriter<TBufferWriter> writer, scoped ref RelayServerNodeUpdateWrapInfo value)
{
if (value == null)
{
writer.WriteNullObjectHeader();
return;
}
writer.WritePackable(new SerializableRelayServerNodeUpdateWrapInfo(value));
}
public override void Deserialize(ref MemoryPackReader reader, scoped ref RelayServerNodeUpdateWrapInfo value)
{
if (reader.PeekIsNull())
{
reader.Advance(1); // skip null block
value = null;
return;
}
var wrapped = reader.ReadPackable<SerializableRelayServerNodeUpdateWrapInfo>();
value = wrapped.info;
}
}
[MemoryPackable]
@@ -256,6 +456,8 @@ namespace linker.messenger.serializer.memorypack
IPEndPoint EndPoint => info.EndPoint;
[MemoryPackInclude]
long LastTicks => info.LastTicks;
[MemoryPackInclude]
string Url => info.Url;
[MemoryPackConstructor]
@@ -265,7 +467,7 @@ namespace linker.messenger.serializer.memorypack
double maxGbTotal, long maxGbTotalLastBytes,
double connectionRatio, double bandwidthRatio,
bool Public, int delay,
IPEndPoint endPoint, long lastTicks)
IPEndPoint endPoint, long lastTicks, string url)
{
var info = new RelayServerNodeReportInfo
{
@@ -281,7 +483,8 @@ namespace linker.messenger.serializer.memorypack
MaxGbTotal = maxGbTotal,
MaxGbTotalLastBytes = maxGbTotalLastBytes,
Name = name,
Public = Public
Public = Public,
Url = url
};
this.info = info;
}
@@ -824,7 +1027,7 @@ namespace linker.messenger.serializer.memorypack
RelayServerCdkeyPageRequestFlag Flag => info.Flag;
[MemoryPackConstructor]
SerializableRelayServerCdkeyPageRequestInfo(int page, int size, string order, string sort, string userid, string remark, string orderid, string contact, string secretKey,RelayServerCdkeyPageRequestFlag flag)
SerializableRelayServerCdkeyPageRequestInfo(int page, int size, string order, string sort, string userid, string remark, string orderid, string contact, string secretKey, RelayServerCdkeyPageRequestFlag flag)
{
var info = new RelayServerCdkeyPageRequestInfo
{
@@ -1141,10 +1344,12 @@ namespace linker.messenger.serializer.memorypack
double PayPrice => info.PayPrice;
[MemoryPackInclude]
int Count => info.Count;
[MemoryPackInclude]
string Type => info.Type;
[MemoryPackConstructor]
SerializableRelayServerCdkeyOrderInfo(int gb, int speed, string time, string widgetUserId, string orderId, string contact, double costPrice, double price, double userPrice, double payPrice, int count)
SerializableRelayServerCdkeyOrderInfo(int gb, int speed, string time, string widgetUserId, string orderId, string contact, double costPrice, double price, double userPrice, double payPrice, int count, string type)
{
var info = new RelayServerCdkeyOrderInfo
{
@@ -1158,7 +1363,8 @@ namespace linker.messenger.serializer.memorypack
Price = price,
UserPrice = userPrice,
PayPrice = payPrice,
Count = count
Count = count,
Type = type
};
this.info = info;
}

View File

@@ -61,6 +61,11 @@ namespace linker.messenger.store.file.relay
RelayServerCdkeyOrderInfo order = result.Cdkey.DeJson<RelayServerCdkeyOrderInfo>();
result.Order = order;
if(order.Type != "Relay" || string.IsNullOrWhiteSpace(order.Type))
{
error.Add("Relay");
}
if (order.WidgetUserId != info.UserId || string.IsNullOrWhiteSpace(order.WidgetUserId))
{
error.Add("UserId");
@@ -98,13 +103,26 @@ namespace linker.messenger.store.file.relay
return await Task.FromResult(result);
}
public async Task<bool> Import(RelayServerCdkeyImportInfo info)
public async Task<string> Import(RelayServerCdkeyImportInfo info)
{
RelayServerCdkeyTestResultInfo test = await Test(info);
if (test.Field.Count > 0)
{
return false;
if (test.Field.Contains("Parse"))
{
return "Parse";
}
else
{
return "Field";
}
}
if (liteCollection.Count(c => c.OrderId == test.Order.OrderId) > 0)
{
return "OrderId";
}
RelayServerCdkeyOrderInfo order = test.Order;
var time = Regex.Match(order.Time, regex).Groups;
RelayServerCdkeyStoreInfo store = new RelayServerCdkeyStoreInfo
@@ -120,8 +138,8 @@ namespace linker.messenger.store.file.relay
.AddHours(int.Parse(time[4].Value))
.AddMinutes(int.Parse(time[5].Value))
.AddSeconds(int.Parse(time[6].Value)),
LastBytes = order.Speed * 1024 * 1024 * 1024 * order.Count,
MaxBytes = order.Speed * 1024 * 1024 * 1024 * order.Count,
LastBytes = (long)order.GB * 1024 * 1024 * 1024 * order.Count,
MaxBytes = (long)order.GB * 1024 * 1024 * 1024 * order.Count,
Price = order.Price,
Remark = "order",
StartTime = DateTime.Now,
@@ -134,7 +152,7 @@ namespace linker.messenger.store.file.relay
Id = ObjectId.NewObjectId().ToString()
};
liteCollection.Insert(store);
return await Task.FromResult(true);
return await Task.FromResult(string.Empty);
}
public async Task<bool> Traffic(Dictionary<long, long> dic)

View File

@@ -31,6 +31,7 @@ namespace linker.messenger.store.file.relay
config.Data.Server.Relay.Distributed.Node.MaxGbTotal = update.MaxGbTotal;
config.Data.Server.Relay.Distributed.Node.MaxGbTotalLastBytes = update.MaxGbTotalLastBytes;
config.Data.Server.Relay.Distributed.Node.Public = update.Public;
config.Data.Server.Relay.Distributed.Node.Url = update.Url;
}
public void SetMaxGbTotalLastBytes(long value)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 28 KiB

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 48 KiB

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 36 KiB

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 48 KiB

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 36 KiB

After

Width:  |  Height:  |  Size: 32 KiB

View File

@@ -26,4 +26,10 @@ export const relayCdkeyMy = (data) => {
}
export const relayCdkeyTest = (data) => {
return sendWebsocketMsg('relay/TestCdkey', data);
}
export const relayCdkeyImport = (data) => {
return sendWebsocketMsg('relay/ImportCdkey', data);
}
export const relayUpdateNode = (data) => {
return sendWebsocketMsg('relay/UpdateNode', data);
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 48 KiB

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 36 KiB

After

Width:  |  Height:  |  Size: 32 KiB

View File

@@ -51,6 +51,10 @@ export default {
'status.groupDelConfirm': 'Are you sure to delete?',
'status.support': 'Support',
'status.website': 'Website',
'status.doc': 'Document',
'status.cdkey': 'CDKEY store',
'status.export': 'Export',
'status.exportText': 'Export the configuration to run elsewhere',
'status.exportSingle': 'Single',
@@ -126,6 +130,7 @@ export default {
'server.relayConnection': 'Conn',
'server.relayDelay': 'Delay',
'server.relayPublic': 'Public',
'server.relayUrl': 'Url',
'server.relayOper': 'Oper',
'server.relayUse': 'Use',
'server.relayMyCdkey': 'My CDKEY',
@@ -169,6 +174,35 @@ export default {
'server.relayCdkeyFlagDeleted': 'Deleted',
'server.relayCdkeyFlagUnDeleted': 'Not deleted',
'server.relayCdkeyTestTitle': 'Test CDKEY',
'server.relayCdkeyTestKey': 'CDKEY',
'server.relayCdkeyTestGB': 'GB',
'server.relayCdkeyTestGBError': 'Must > 0',
'server.relayCdkeyTestSpeed': 'Mbps',
'server.relayCdkeyTestSpeedError': 'Must > 0',
'server.relayCdkeyTestTime': 'Time',
'server.relayCdkeyTestTimeError': 'Format error',
'server.relayCdkeyTestUserId': 'UserId',
'server.relayCdkeyTestUserIdError': 'UserId error',
'server.relayCdkeyTestOrderId': 'OrderNo',
'server.relayCdkeyTestOrderIdError': 'OrderNo is empty',
'server.relayCdkeyTestContact': 'Contact',
'server.relayCdkeyTestCostPrice': 'Cost',
'server.relayCdkeyTestPrice': 'Price',
'server.relayCdkeyTestUserPrice': 'User price',
'server.relayCdkeyTestPayPrice': 'Pay',
'server.relayCdkeyTestCount': 'Count',
'server.relayCdkeyTestCountError': 'Must > 0',
'server.relayCdkeyTestType': 'Type',
'server.relayCdkeyTestTypeError': 'Must be relay',
'server.relayCdkeyTestParseError': 'decode fail',
'server.relayCdkeyImport': 'Import CDKEY',
'server.relayCdkeyImportParse': 'Decode fail',
'server.relayCdkeyImportField': 'Field invalid',
'server.relayCdkeyImportNetwork': 'Network error',
'server.relayCdkeyImportOrderId': 'OrderNo has exists',
'server.sforwardSecretKey': 'Server forward secretKey',
'server.sforwardText': 'The server forward can be used when the key is correct',

View File

@@ -51,6 +51,9 @@ export default {
'status.groupDelConfirm': '确认删除吗?',
'status.support': '赞助',
'status.website': '官网',
'status.doc': '文档',
'status.cdkey': 'CDKEY商城',
'status.export': '导出配置',
'status.exportText': '导出配置作为子设备运行如果使用docker容器映射configs文件夹即可',
@@ -123,12 +126,14 @@ export default {
'server.relayTitle': '中继节点',
'server.relayName': '名称',
'server.relayFlow': '月流量',
'server.relayFlowLast': '剩余流量',
'server.relaySpeed': '带宽',
'server.relaySpeed1': '总带宽',
'server.relaySpeed2': '速率',
'server.relayConnection': '连接数',
'server.relayDelay': '延迟',
'server.relayPublic': '公开',
'server.relayUrl': 'Url',
'server.relayOper': '操作',
'server.relayUse': '使用',
'server.relayMyCdkey': '我的CDKEY',
@@ -191,8 +196,16 @@ export default {
'server.relayCdkeyTestPayPrice': '支付',
'server.relayCdkeyTestCount': '数量',
'server.relayCdkeyTestCountError': '数量要大于0',
'server.relayCdkeyTestType': '类别',
'server.relayCdkeyTestTypeError': '类别应该是Relay',
'server.relayCdkeyTestParseError': '解密失败',
'server.relayCdkeyImport': '导入CDKEY',
'server.relayCdkeyImportParse': '解密失败',
'server.relayCdkeyImportField': '字段有误',
'server.relayCdkeyImportNetwork': '网络错误',
'server.relayCdkeyImportOrderId': '订单号已存在',
'server.sforwardSecretKey': '服务器穿透密钥',
'server.sforwardText': '当密钥正确是可用',

View File

@@ -61,7 +61,11 @@
<el-dialog v-model="state.showNodes" :title="$t('server.relayTitle')" width="760" top="2vh">
<div>
<el-table :data="state.nodes" size="small" border height="600">
<el-table-column property="Name" :label="$t('server.relayName')"></el-table-column>
<el-table-column property="Name" :label="$t('server.relayName')">
<template #default="scope">
<a :href="scope.row.Url" class="a-line blue" target="_blank">{{ scope.row.Name }}</a>
</template>
</el-table-column>
<el-table-column property="MaxGbTotal" :label="$t('server.relayFlow')" width="160">
<template #default="scope">
<span v-if="scope.row.MaxGbTotal == 0">--</span>
@@ -78,7 +82,7 @@
</el-table-column>
<el-table-column property="MaxBandwidthTotal" :label="$t('server.relaySpeed1')" width="80">
<template #default="scope">
<span v-if="scope.row.MaxBandwidthTotal == 0">无限制</span>
<span v-if="scope.row.MaxBandwidthTotal == 0">--</span>
<span v-else>{{ scope.row.MaxBandwidthTotal }}Mbps</span>
</template>
</el-table-column>
@@ -215,4 +219,7 @@ export default {
<style lang="stylus" scoped>
.head{padding-bottom:1rem}
.blue {
color: #409EFF;
}
</style>

View File

@@ -0,0 +1,106 @@
<template>
<el-dialog class="options-center" :title="$t('server.relayTitle')" destroy-on-close v-model="state.show" width="30rem" top="2vh">
<div>
<el-form ref="ruleFormRef" :model="state.ruleForm" :rules="state.rules" label-width="auto">
<el-form-item :label="$t('server.relayName')" prop="Name">
<el-input minlength="1" maxlength="32" show-word-limit v-model="state.ruleForm.Name" />
</el-form-item>
<el-form-item :label="$t('server.relayConnection')" prop="MaxConnection">
<el-input-number v-model="state.ruleForm.MaxConnection" :min="0" :max="65535"/>
</el-form-item>
<el-form-item :label="$t('server.relaySpeed')" prop="MaxBandwidth">
<el-input-number v-model="state.ruleForm.MaxBandwidth" :min="0"/>Mbps
</el-form-item>
<el-form-item :label="$t('server.relaySpeed1')" prop="MaxBandwidthTotal">
<el-input-number v-model="state.ruleForm.MaxBandwidthTotal" :min="0"/>Mbps
</el-form-item>
<el-form-item :label="$t('server.relayFlow')" prop="MaxGbTotal">
<el-input-number v-model="state.ruleForm.MaxGbTotal" :min="0"/>GB <el-button size="small" @click="handleRefresh"><el-icon><Refresh /></el-icon></el-button>
</el-form-item>
<el-form-item :label="$t('server.relayFlowLast')" prop="MaxGbTotalLastBytes">
<el-input-number v-model="state.ruleForm.MaxGbTotalLastBytes" :min="0" />byte
</el-form-item>
<el-form-item :label="$t('server.relayUrl')" prop="Url">
<el-input v-model="state.ruleForm.Url" />
</el-form-item>
<el-form-item :label="$t('server.relayPublic')" prop="Public">
<el-switch v-model="state.ruleForm.Public " size="small" />
</el-form-item>
<el-form-item></el-form-item>
<el-form-item label="" prop="Btns">
<div class="t-c w-100">
<el-button @click="state.show = false">{{$t('common.cancel')}}</el-button>
<el-button type="primary" @click="handleSave">{{$t('common.confirm')}}</el-button>
</div>
</el-form-item>
</el-form>
</div>
</el-dialog>
</template>
<script>
import { ElMessage } from 'element-plus';
import { reactive, ref, watch } from 'vue'
import { useI18n } from 'vue-i18n';
import { relayUpdateNode } from '@/apis/relay';
import { Refresh } from '@element-plus/icons-vue'
export default {
props: ['data','modelValue'],
emits: ['update:modelValue','success'],
components:{Refresh},
setup(props,{emit}) {
const {t} = useI18n();
const state = reactive({
show:true,
ruleForm:{
Id:props.data.Id,
Name:props.data.Name,
MaxConnection:props.data.MaxConnection,
MaxBandwidth:props.data.MaxBandwidth,
MaxBandwidthTotal:props.data.MaxBandwidthTotal,
MaxGbTotal:props.data.MaxGbTotal,
MaxGbTotalLastBytes:props.data.MaxGbTotalLastBytes,
Public:props.data.Public,
Url:props.data.Url,
},
rules:{
}
});
watch(() => state.show, (val) => {
if (!val) {
setTimeout(() => {
emit('update:modelValue', val);
}, 300);
}
});
const handleRefresh = ()=>{
state.ruleForm.MaxGbTotalLastBytes = state.ruleForm.MaxGbTotal * 1024*1024*1024;
}
const ruleFormRef = ref(null);
const handleSave = ()=>{
ruleFormRef.value.validate((valid) => {
if (!valid) return;
const json = JSON.parse(JSON.stringify(state.ruleForm));
relayUpdateNode(json).then((res)=>{
if(res){
ElMessage.success(t('common.oper'));
state.show = false;
emit('success');
}else{
ElMessage.error(t('common.operFail'));
}
}).catch(()=>{
ElMessage.error(t('common.operFail'));
});
});
}
return {state,ruleFormRef,handleRefresh,handleSave}
}
}
</script>
<style lang="stylus" scoped>
.el-form-item{margin-bottom:1rem}
.el-input-number--small{width:10rem !important}
</style>

View File

@@ -1,24 +1,32 @@
<template>
<el-form-item :label="$t('server.relaySecretKey')">
<div class="flex">
<el-input class="flex-1" type="password" show-password v-model="state.list.SecretKey" maxlength="36" @change="handleSave" />
<Sync class="mgl-1" name="RelaySecretKey"></Sync>
<div class="mgl-1">
<el-checkbox class="mgr-1" v-model="state.list.SSL" :label="$t('server.relaySSL')" @change="handleSave" />
<el-checkbox v-model="state.list.Disabled" :label="$t('server.relayDisable')" @change="handleSave" />
<div >
<div class="flex">
<el-input class="flex-1" type="password" show-password v-model="state.list.SecretKey" maxlength="36" @change="handleSave" />
<Sync class="mgl-1" name="RelaySecretKey"></Sync>
</div>
<div class="flex">
<div class="mgr-1">
<el-checkbox class="mgr-1" v-model="state.list.SSL" :label="$t('server.relaySSL')" @change="handleSave" />
<el-checkbox v-model="state.list.Disabled" :label="$t('server.relayDisable')" @change="handleSave" />
</div>
<a href="javascript:;" @click="state.show=true" class="mgl-1 delay a-line" :class="{red:state.nodes.length==0,green:state.nodes.length>0}">
{{$t('server.relayNodes')}} : {{state.nodes.length}}
</a>
<RelayCdkey></RelayCdkey>
</div>
<a href="javascript:;" @click="state.show=true" class="mgl-1 delay a-line" :class="{red:state.nodes.length==0,green:state.nodes.length>0}">
{{$t('server.relayNodes')}} : {{state.nodes.length}}
</a>
<RelayCdkey></RelayCdkey>
</div>
</el-form-item>
</el-form-item>
<el-dialog v-model="state.show" :title="$t('server.relayTitle')" width="760" top="2vh">
<div>
<el-table :data="state.nodes" size="small" border height="500">
<el-table-column property="Name" :label="$t('server.relayName')"></el-table-column>
<el-table-column property="Name" :label="$t('server.relayName')">
<template #default="scope">
<a :href="scope.row.Url" class="a-line blue" target="_blank">{{ scope.row.Name }}</a>
<a v-if="state.hasRelayCdkey" href="javascript:;" class="a-line" @click="handleEdit(scope.row)"><el-icon><Edit /></el-icon></a>
</template>
</el-table-column>
<el-table-column property="MaxGbTotal" :label="$t('server.relayFlow')" width="160">
<template #default="scope">
<span v-if="scope.row.MaxGbTotal == 0">--</span>
@@ -59,17 +67,20 @@
</el-table>
</div>
</el-dialog>
<EditNode v-if="state.showEdit" v-model="state.showEdit" :data="state.current"></EditNode>
</template>
<script>
import { setRelayServers, setRelaySubscribe } from '@/apis/relay';
import { relayCdkeyAccess, setRelayServers, setRelaySubscribe } from '@/apis/relay';
import { injectGlobalData } from '@/provide';
import { ElMessage } from 'element-plus';
import { onMounted, onUnmounted, reactive, watch } from 'vue'
import { useI18n } from 'vue-i18n';
import Sync from '../sync/Index.vue'
import RelayCdkey from './relayCdkey/Index.vue'
import EditNode from './EditNode.vue';
import { Edit } from '@element-plus/icons-vue';
export default {
components:{Sync,RelayCdkey},
components:{Sync,RelayCdkey,EditNode,Edit},
setup(props) {
const {t} = useI18n();
const globalData = injectGlobalData();
@@ -77,11 +88,19 @@ export default {
list:globalData.value.config.Client.Relay.Server,
show:false,
nodes:[],
timer:0
timer:0,
showEdit:false,
current:{},
hasRelayCdkey:false
});
watch(()=>globalData.value.config.Client.Relay.Server,()=>{
state.list.Delay = globalData.value.config.Client.Relay.Server.Delay;
})
});
const handleEdit = (row)=>{
state.current = row;
state.showEdit = true;
}
const handleSave = ()=>{
setRelayServers(state.list).then(()=>{
@@ -91,7 +110,6 @@ export default {
ElMessage.error(t('common.operFail'));
});;
}
const _setRelaySubscribe = ()=>{
setRelaySubscribe().then((res)=>{
state.nodes = res;
@@ -102,14 +120,20 @@ export default {
}
onMounted(()=>{
_setRelaySubscribe();
relayCdkeyAccess().then(res=>{
state.hasRelayCdkey = res;
}).catch(()=>{})
});
onUnmounted(()=>{
clearTimeout(state.timer);
})
return {state,handleSave}
return {state,handleSave,handleEdit}
}
}
</script>
<style lang="stylus" scoped>
.blue {
color: #409EFF;
}
</style>

View File

@@ -20,7 +20,7 @@ export default {
const state = reactive({
hasRelayCdkey:false,
showManager:false,
showMy:true
showMy:false
});
onMounted(()=>{

View File

@@ -11,6 +11,11 @@
<el-icon><Search /></el-icon>
</el-button>
</div>
<div>
<el-button size="small" type="success" @click="handleImport">
<el-icon><Plus /></el-icon>
</el-button>
</div>
</div>
<Flags @change="handleFlagsChange"></Flags>
</div>
@@ -77,8 +82,9 @@ import { injectGlobalData } from '@/provide';
import { onMounted, reactive, watch } from 'vue'
import { Delete,Plus,Search } from '@element-plus/icons-vue';
import { useI18n } from 'vue-i18n';
import {relayCdkeyMy,relayCdkeyDel } from '@/apis/relay';
import {relayCdkeyMy,relayCdkeyDel, relayCdkeyImport } from '@/apis/relay';
import Flags from './Flags.vue';
import { ElMessage, ElMessageBox } from 'element-plus';
export default {
props: ['modelValue'],
emits: ['update:modelValue'],
@@ -144,11 +150,34 @@ export default {
handleSearch();
}).catch(()=>{})
}
const handleImport = ()=>{
ElMessageBox.prompt(t('server.relayCdkeyImport'), t('common.tips'), {
confirmButtonText: t('common.confirm'),
cancelButtonText: t('common.cancel')
}).then(({ value }) => {
if(!value){
handleImport();
return;
}
relayCdkeyImport({Base64:value}).then((res)=>{
if(res){
ElMessage.error(t(`server.relayCdkeyImport${res}`));
handleImport();
}else{
ElMessage.success(t('common.oper'));
handleSearch();
}
}).catch(()=>{})
}).catch(() => {
})
}
onMounted(()=>{
handleSearch();
})
return {state,parseSpeed,handleSort,handleFlagsChange,handleSearch,handlePageChange,handleDel}
return {state,parseSpeed,handleSort,handleFlagsChange,handleSearch,handlePageChange,handleDel,handleImport}
}
}
</script>

View File

@@ -11,126 +11,137 @@
</div>
</el-form-item>
<el-form-item :label="$t('server.relayCdkeyTestGB')" prop="GB">
<el-row>
<el-col :span="18">
<el-row class="w-100">
<el-col :span="15">
<el-input v-model="state.ruleForm.Order.GB" />
</el-col>
<el-col :span="6">
<el-col :span="9">
<span class="red" v-if="state.ruleForm.Field.indexOf('GB')>=0">{{$t('server.relayCdkeyTestGBError')}}</span>
<span v-else class="green">success</span>
</el-col>
</el-row>
</el-form-item>
<el-form-item :label="$t('server.relayCdkeyTestSpeed')" prop="Speed">
<el-row>
<el-col :span="18">
<el-row class="w-100">
<el-col :span="15">
<el-input v-model="state.ruleForm.Order.Speed" />
</el-col>
<el-col :span="6">
<el-col :span="9">
<span class="red" v-if="state.ruleForm.Field.indexOf('Speed')>=0">{{$t('server.relayCdkeyTestSpeedError')}}</span>
<span v-else class="green">success</span>
</el-col>
</el-row>
</el-form-item>
<el-form-item :label="$t('server.relayCdkeyTestTime')" prop="Time">
<el-row>
<el-col :span="18">
<el-row class="w-100">
<el-col :span="15">
<el-input v-model="state.ruleForm.Order.Time" />
</el-col>
<el-col :span="6">
<el-col :span="9">
<span class="red" v-if="state.ruleForm.Field.indexOf('Time')>=0">{{$t('server.relayCdkeyTestTimeError')}}</span>
<span v-else class="green">success</span>
</el-col>
</el-row>
</el-form-item>
<el-form-item :label="$t('server.relayCdkeyTestUserId')" prop="WidgetUserId">
<el-row>
<el-col :span="18">
<el-row class="w-100">
<el-col :span="15">
<el-input v-model="state.ruleForm.Order.WidgetUserId" />
</el-col>
<el-col :span="6">
<el-col :span="9">
<span class="red" v-if="state.ruleForm.Field.indexOf('UserId')>=0">{{$t('server.relayCdkeyTestUserIdError')}}</span>
<span v-else class="green">success</span>
</el-col>
</el-row>
</el-form-item>
<el-form-item :label="$t('server.relayCdkeyTestOrderId')" prop="OrderId">
<el-row>
<el-col :span="18">
<el-row class="w-100">
<el-col :span="15">
<el-input v-model="state.ruleForm.Order.OrderId" />
</el-col>
<el-col :span="6">
<el-col :span="9">
<span class="red" v-if="state.ruleForm.Field.indexOf('OrderId')>=0">{{$t('server.relayCdkeyTestOrderIdError')}}</span>
<span v-else class="green">success</span>
</el-col>
</el-row>
</el-form-item>
<el-form-item :label="$t('server.relayCdkeyTestContact')" prop="Contact">
<el-row>
<el-col :span="18">
<el-row class="w-100">
<el-col :span="15">
<el-input v-model="state.ruleForm.Order.Contact" />
</el-col>
<el-col :span="6">
<el-col :span="9">
<span class="red" v-if="state.ruleForm.Field.indexOf('Contact')>=0">{{$t('server.relayCdkeyTestContactError')}}</span>
<span v-else class="green">success</span>
</el-col>
</el-row>
</el-form-item>
<el-form-item :label="$t('server.relayCdkeyTestCostPrice')" prop="CostPrice">
<el-row>
<el-col :span="18">
<el-row class="w-100">
<el-col :span="15">
<el-input v-model="state.ruleForm.Order.CostPrice" />
</el-col>
<el-col :span="6">
<el-col :span="9">
<span class="red" v-if="state.ruleForm.Field.indexOf('CostPrice')>=0">{{$t('server.relayCdkeyTestCostPriceError')}}</span>
<span v-else class="green">success</span>
</el-col>
</el-row>
</el-form-item>
<el-form-item :label="$t('server.relayCdkeyTestPrice')" prop="Price">
<el-row>
<el-col :span="18">
<el-row class="w-100">
<el-col :span="15">
<el-input v-model="state.ruleForm.Order.Price" />
</el-col>
<el-col :span="6">
<el-col :span="9">
<span class="red" v-if="state.ruleForm.Field.indexOf('Price')>=0">{{$t('server.relayCdkeyTestPriceError')}}</span>
<span v-else class="green">success</span>
</el-col>
</el-row>
</el-form-item>
<el-form-item :label="$t('server.relayCdkeyTestUserPrice')" prop="UserPrice">
<el-row>
<el-col :span="18">
<el-row class="w-100">
<el-col :span="15">
<el-input v-model="state.ruleForm.Order.UserPrice" />
</el-col>
<el-col :span="6">
<el-col :span="9">
<span class="red" v-if="state.ruleForm.Field.indexOf('UserPrice')>=0">{{$t('server.relayCdkeyTestUserPriceError')}}</span>
<span v-else class="green">success</span>
</el-col>
</el-row>
</el-form-item>
<el-form-item :label="$t('server.relayCdkeyTestPayPrice')" prop="PayPrice">
<el-row>
<el-col :span="18">
<el-row class="w-100">
<el-col :span="15">
<el-input v-model="state.ruleForm.Order.PayPrice" />
</el-col>
<el-col :span="6">
<el-col :span="9">
<span class="red" v-if="state.ruleForm.Field.indexOf('PayPrice')>=0">{{$t('server.relayCdkeyTestPayPriceError')}}</span>
<span v-else class="green">success</span>
</el-col>
</el-row>
</el-form-item>
<el-form-item :label="$t('server.relayCdkeyTestCount')" prop="Count">
<el-row>
<el-col :span="18">
<el-row class="w-100">
<el-col :span="15">
<el-input v-model="state.ruleForm.Order.Count" />
</el-col>
<el-col :span="6">
<el-col :span="9">
<span class="red" v-if="state.ruleForm.Field.indexOf('Count')>=0">{{$t('server.relayCdkeyTestCountError')}}</span>
<span v-else class="green">success</span>
</el-col>
</el-row>
</el-form-item>
<el-form-item :label="$t('server.relayCdkeyTestType')" prop="Type">
<el-row class="w-100">
<el-col :span="15">
<el-input v-model="state.ruleForm.Order.Type" />
</el-col>
<el-col :span="9">
<span class="red" v-if="state.ruleForm.Field.indexOf('Type')>=0 || state.ruleForm.Order.Type !='Relay' ">{{$t('server.relayCdkeyTestTypeError')}}</span>
<span v-else class="green">success</span>
</el-col>
</el-row>
</el-form-item>
<el-form-item label="" prop="Btns">
<div class="t-c w-100">
<el-button @click="state.show = false">{{$t('common.cancel')}}</el-button>
@@ -155,7 +166,7 @@ export default {
const {t} = useI18n();
const state = reactive({
show:true,
Base64:'qn1vYOBtu81DkBI10nTTw7h/Vzi1Do3X1HI2+P5fflINL2wNPxrUYQPeOxUqgT+RcZSKLGF3dCMOyYBB+1VKmuI6ZaN86Whr1Xux2dY25tI5/3i/x/K1S78E6+E70ruh61phQZT3QLLVAHnIa2HpFhtPLKZaWc++ReSzixBqkW/sTT/l2iDqG2rl/zKynRM6srXWJkJr+2Msme1u5/Qu/0o6VaJ3ylv71HlB4zubNybQX5WMsOWrjN4/ruRSVF0LcayshqEfwlpeGR44nn5jMxpgQhxxpk/1flVImF00cC4=',
Base64:'',
ruleForm:{
Order:{},
Cdkey:'',

View File

@@ -4,8 +4,12 @@
<a href="javascript:;" class="memory" :title="$t('status.support')" @click="state.showPay = true">
<img src="@/assets/coin.svg" alt="memory" />
<span>{{$t('status.support')}}</span>
<span>©linker {{ self.Version }}</span>
</a>
<a href="https://github.com/snltty/linker" target="_blank">©linker {{ self.Version }}</a>
<a href="https://github.com/snltty/linker" target="_blank">Github</a>
<a href="https://linker.snltty.com" target="_blank">{{$t('status.website')}}</a>
<a href="https://linker-doc.snltty.com" target="_blank">{{$t('status.doc')}}</a>
<a href="https://v.netzo123.com" target="_blank">{{$t('status.cdkey')}}</a>
</div>
<div class="flex-1"></div>
<div class="export"><Export :config="config"></Export></div>
@@ -59,7 +63,7 @@ export default {
.copy{
padding-left:.5rem;
a{color:#555;}
a{color:#555;margin-right:1rem}
}
a.memory{

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

After

Width:  |  Height:  |  Size: 17 KiB

View File

@@ -1,5 +1,5 @@
v1.6.9
2025-03-08 19:25:04
2025-03-09 18:12:09
1. 优化linux下路由跟踪问题
2. 优化linux下获取本机IP问题
3. 增加ICS让win7+、win server2008+支持NAT