mirror of
https://github.com/snltty/linker.git
synced 2025-10-08 10:30:08 +08:00
sync
This commit is contained in:
2
.github/workflows/dotnet.yml
vendored
2
.github/workflows/dotnet.yml
vendored
@@ -37,7 +37,7 @@ jobs:
|
|||||||
release_name: v1.4.4.${{ steps.date.outputs.today }}
|
release_name: v1.4.4.${{ steps.date.outputs.today }}
|
||||||
draft: false
|
draft: false
|
||||||
prerelease: false
|
prerelease: false
|
||||||
body: 1. 增加流量统计(暂时显示服务端流量)
|
body: "1. 总览,和详细流量统计,一眼知道服务器流量花在哪里\r\n2. 优化信标。减少流量,没有操作时尽量不产生流量"
|
||||||
- name: upload-win-x86-oss
|
- name: upload-win-x86-oss
|
||||||
id: upload-win-x86-oss
|
id: upload-win-x86-oss
|
||||||
uses: tvrcgo/oss-action@v0.1.1
|
uses: tvrcgo/oss-action@v0.1.1
|
||||||
|
45
linker.libs/LastTicksManager.cs
Normal file
45
linker.libs/LastTicksManager.cs
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace linker.libs
|
||||||
|
{
|
||||||
|
public sealed class LastTicksManager
|
||||||
|
{
|
||||||
|
private long ticks = Environment.TickCount64;
|
||||||
|
|
||||||
|
public void Update()
|
||||||
|
{
|
||||||
|
ticks = Environment.TickCount64;
|
||||||
|
}
|
||||||
|
public bool Less(long ms)
|
||||||
|
{
|
||||||
|
return Environment.TickCount64 - ticks <= ms;
|
||||||
|
}
|
||||||
|
public bool Greater(long ms)
|
||||||
|
{
|
||||||
|
return Environment.TickCount64 - ticks > ms;
|
||||||
|
}
|
||||||
|
public bool Equal(long ms)
|
||||||
|
{
|
||||||
|
return ticks == ms;
|
||||||
|
}
|
||||||
|
public bool NotEqual(long ms)
|
||||||
|
{
|
||||||
|
return ticks != ms;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long Diff()
|
||||||
|
{
|
||||||
|
return Environment.TickCount64 - ticks;
|
||||||
|
}
|
||||||
|
public bool Timeout(long ms)
|
||||||
|
{
|
||||||
|
return ticks == 0 || Environment.TickCount64 - ticks > ms;
|
||||||
|
}
|
||||||
|
public void Clear()
|
||||||
|
{
|
||||||
|
ticks = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@@ -1,4 +1,5 @@
|
|||||||
using System.Net;
|
using linker.libs;
|
||||||
|
using System.Net;
|
||||||
|
|
||||||
namespace linker.tunnel.connection
|
namespace linker.tunnel.connection
|
||||||
{
|
{
|
||||||
@@ -139,7 +140,7 @@ namespace linker.tunnel.connection
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 最后通信时间
|
/// 最后通信时间
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public long LastTicks { get; }
|
public LastTicksManager LastTicks { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 发送ping
|
/// 发送ping
|
||||||
|
@@ -32,12 +32,12 @@ namespace linker.tunnel.connection
|
|||||||
|
|
||||||
public byte BufferSize { get; init; } = 3;
|
public byte BufferSize { get; init; } = 3;
|
||||||
|
|
||||||
public bool Connected => Stream != null && Stream.CanWrite && LastTicks > 0;
|
public bool Connected => Stream != null && Stream.CanWrite && LastTicks.NotEqual(0);
|
||||||
public int Delay { get; private set; }
|
public int Delay { get; private set; }
|
||||||
public long SendBytes { get; private set; }
|
public long SendBytes { get; private set; }
|
||||||
public long ReceiveBytes { get; private set; }
|
public long ReceiveBytes { get; private set; }
|
||||||
|
|
||||||
public long LastTicks { get; private set; } = Environment.TickCount64;
|
public LastTicksManager LastTicks { get; private set; } = new LastTicksManager();
|
||||||
|
|
||||||
[JsonIgnore]
|
[JsonIgnore]
|
||||||
public QuicStream Stream { get; init; }
|
public QuicStream Stream { get; init; }
|
||||||
@@ -56,7 +56,7 @@ namespace linker.tunnel.connection
|
|||||||
private bool framing;
|
private bool framing;
|
||||||
private ReceiveDataBuffer bufferCache = new ReceiveDataBuffer();
|
private ReceiveDataBuffer bufferCache = new ReceiveDataBuffer();
|
||||||
|
|
||||||
private long pingStart = Environment.TickCount64;
|
private LastTicksManager pingTicks = new();
|
||||||
private byte[] pingBytes = Encoding.UTF8.GetBytes($"{Helper.GlobalString}.tcp.ping");
|
private byte[] pingBytes = Encoding.UTF8.GetBytes($"{Helper.GlobalString}.tcp.ping");
|
||||||
private byte[] pongBytes = Encoding.UTF8.GetBytes($"{Helper.GlobalString}.tcp.pong");
|
private byte[] pongBytes = Encoding.UTF8.GetBytes($"{Helper.GlobalString}.tcp.pong");
|
||||||
private bool pong = true;
|
private bool pong = true;
|
||||||
@@ -148,7 +148,7 @@ namespace linker.tunnel.connection
|
|||||||
private async Task CallbackPacket(Memory<byte> packet)
|
private async Task CallbackPacket(Memory<byte> packet)
|
||||||
{
|
{
|
||||||
ReceiveBytes += packet.Length;
|
ReceiveBytes += packet.Length;
|
||||||
LastTicks = Environment.TickCount64;
|
LastTicks.Update();
|
||||||
if (packet.Length == pingBytes.Length && (packet.Span.SequenceEqual(pingBytes) || packet.Span.SequenceEqual(pongBytes)))
|
if (packet.Length == pingBytes.Length && (packet.Span.SequenceEqual(pingBytes) || packet.Span.SequenceEqual(pongBytes)))
|
||||||
{
|
{
|
||||||
if (packet.Span.SequenceEqual(pingBytes))
|
if (packet.Span.SequenceEqual(pingBytes))
|
||||||
@@ -157,7 +157,7 @@ namespace linker.tunnel.connection
|
|||||||
}
|
}
|
||||||
else if (packet.Span.SequenceEqual(pongBytes))
|
else if (packet.Span.SequenceEqual(pongBytes))
|
||||||
{
|
{
|
||||||
Delay = (int)(Environment.TickCount64 - pingStart);
|
Delay = (int)pingTicks.Diff();
|
||||||
pong = true;
|
pong = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -179,9 +179,9 @@ namespace linker.tunnel.connection
|
|||||||
{
|
{
|
||||||
while (cancellationTokenSource.IsCancellationRequested == false)
|
while (cancellationTokenSource.IsCancellationRequested == false)
|
||||||
{
|
{
|
||||||
if (Environment.TickCount64 - LastTicks > 3000)
|
if (LastTicks.Greater(3000))
|
||||||
{
|
{
|
||||||
pingStart = Environment.TickCount64;
|
pingTicks.Update();
|
||||||
await SendPingPong(pingBytes).ConfigureAwait(false);
|
await SendPingPong(pingBytes).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
await Task.Delay(3000).ConfigureAwait(false);
|
await Task.Delay(3000).ConfigureAwait(false);
|
||||||
@@ -223,7 +223,7 @@ namespace linker.tunnel.connection
|
|||||||
{
|
{
|
||||||
if (pong == false) return;
|
if (pong == false) return;
|
||||||
pong = false;
|
pong = false;
|
||||||
pingStart = Environment.TickCount64;
|
pingTicks.Update();
|
||||||
await SendPingPong(pingBytes).ConfigureAwait(false);
|
await SendPingPong(pingBytes).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
private SemaphoreSlim semaphoreSlim = new SemaphoreSlim(1);
|
private SemaphoreSlim semaphoreSlim = new SemaphoreSlim(1);
|
||||||
@@ -254,7 +254,7 @@ namespace linker.tunnel.connection
|
|||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
LastTicks = 0;
|
LastTicks.Clear();
|
||||||
|
|
||||||
if (LoggerHelper.Instance.LoggerLevel <= LoggerTypes.DEBUG)
|
if (LoggerHelper.Instance.LoggerLevel <= LoggerTypes.DEBUG)
|
||||||
LoggerHelper.Instance.Error($"tunnel connection writer offline {ToString()}");
|
LoggerHelper.Instance.Error($"tunnel connection writer offline {ToString()}");
|
||||||
|
@@ -27,12 +27,12 @@ namespace linker.tunnel.connection
|
|||||||
public IPEndPoint IPEndPoint { get; init; }
|
public IPEndPoint IPEndPoint { get; init; }
|
||||||
public bool SSL { get; init; }
|
public bool SSL { get; init; }
|
||||||
public byte BufferSize { get; init; } = 3;
|
public byte BufferSize { get; init; } = 3;
|
||||||
public bool Connected => Socket != null && LastTicks > 0 && Environment.TickCount64 - LastTicks < 15000;
|
public bool Connected => Socket != null && LastTicks.Timeout(15000) == false;
|
||||||
public int Delay { get; private set; }
|
public int Delay { get; private set; }
|
||||||
public long SendBytes { get; private set; }
|
public long SendBytes { get; private set; }
|
||||||
public long ReceiveBytes { get; private set; }
|
public long ReceiveBytes { get; private set; }
|
||||||
|
|
||||||
public long LastTicks { get; private set; } = Environment.TickCount64;
|
public LastTicksManager LastTicks { get; private set; } = new LastTicksManager();
|
||||||
|
|
||||||
[JsonIgnore]
|
[JsonIgnore]
|
||||||
public SslStream Stream { get; init; }
|
public SslStream Stream { get; init; }
|
||||||
@@ -47,7 +47,7 @@ namespace linker.tunnel.connection
|
|||||||
private bool framing;
|
private bool framing;
|
||||||
private ReceiveDataBuffer bufferCache = new ReceiveDataBuffer();
|
private ReceiveDataBuffer bufferCache = new ReceiveDataBuffer();
|
||||||
|
|
||||||
private long pingStart = Environment.TickCount64;
|
private LastTicksManager pingTicks = new LastTicksManager();
|
||||||
private byte[] pingBytes = Encoding.UTF8.GetBytes($"{Helper.GlobalString}.tcp.ping");
|
private byte[] pingBytes = Encoding.UTF8.GetBytes($"{Helper.GlobalString}.tcp.ping");
|
||||||
private byte[] pongBytes = Encoding.UTF8.GetBytes($"{Helper.GlobalString}.tcp.pong");
|
private byte[] pongBytes = Encoding.UTF8.GetBytes($"{Helper.GlobalString}.tcp.pong");
|
||||||
private bool pong = true;
|
private bool pong = true;
|
||||||
@@ -157,7 +157,7 @@ namespace linker.tunnel.connection
|
|||||||
private async Task CallbackPacket(Memory<byte> packet)
|
private async Task CallbackPacket(Memory<byte> packet)
|
||||||
{
|
{
|
||||||
ReceiveBytes += packet.Length;
|
ReceiveBytes += packet.Length;
|
||||||
LastTicks = Environment.TickCount64;
|
LastTicks.Update();
|
||||||
if (packet.Length == pingBytes.Length)
|
if (packet.Length == pingBytes.Length)
|
||||||
{
|
{
|
||||||
if (packet.Span.SequenceEqual(pingBytes))
|
if (packet.Span.SequenceEqual(pingBytes))
|
||||||
@@ -166,7 +166,7 @@ namespace linker.tunnel.connection
|
|||||||
}
|
}
|
||||||
else if (packet.Span.SequenceEqual(pongBytes))
|
else if (packet.Span.SequenceEqual(pongBytes))
|
||||||
{
|
{
|
||||||
Delay = (int)(Environment.TickCount64 - pingStart);
|
Delay = (int)pingTicks.Diff();
|
||||||
pong = true;
|
pong = true;
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
@@ -192,9 +192,9 @@ namespace linker.tunnel.connection
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Environment.TickCount64 - LastTicks > 3000)
|
if (LastTicks.Greater(3000))
|
||||||
{
|
{
|
||||||
pingStart = Environment.TickCount64;
|
pingTicks.Update();
|
||||||
await SendPingPong(pingBytes).ConfigureAwait(false);
|
await SendPingPong(pingBytes).ConfigureAwait(false);
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -246,7 +246,7 @@ namespace linker.tunnel.connection
|
|||||||
{
|
{
|
||||||
if (pong == false) return;
|
if (pong == false) return;
|
||||||
pong = false;
|
pong = false;
|
||||||
pingStart = Environment.TickCount64;
|
pingTicks.Update();
|
||||||
await SendPingPong(pingBytes).ConfigureAwait(false);
|
await SendPingPong(pingBytes).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
public async Task<bool> SendAsync(ReadOnlyMemory<byte> data)
|
public async Task<bool> SendAsync(ReadOnlyMemory<byte> data)
|
||||||
@@ -286,7 +286,7 @@ namespace linker.tunnel.connection
|
|||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
LastTicks = 0;
|
LastTicks.Clear();
|
||||||
if (LoggerHelper.Instance.LoggerLevel <= LoggerTypes.DEBUG)
|
if (LoggerHelper.Instance.LoggerLevel <= LoggerTypes.DEBUG)
|
||||||
LoggerHelper.Instance.Error($"tunnel connection {this.GetHashCode()} writer offline {ToString()}");
|
LoggerHelper.Instance.Error($"tunnel connection {this.GetHashCode()} writer offline {ToString()}");
|
||||||
|
|
||||||
|
@@ -27,11 +27,11 @@ namespace linker.tunnel.connection
|
|||||||
public bool SSL { get; init; }
|
public bool SSL { get; init; }
|
||||||
public byte BufferSize { get; init; } = 3;
|
public byte BufferSize { get; init; } = 3;
|
||||||
|
|
||||||
public bool Connected => UdpClient != null && LastTicks > 0 && Environment.TickCount64 - LastTicks < 15000;
|
public bool Connected => UdpClient != null && LastTicks.Timeout(15000) == false;
|
||||||
public int Delay { get; private set; }
|
public int Delay { get; private set; }
|
||||||
public long SendBytes { get; private set; }
|
public long SendBytes { get; private set; }
|
||||||
public long ReceiveBytes { get; private set; }
|
public long ReceiveBytes { get; private set; }
|
||||||
public long LastTicks { get; private set; } = Environment.TickCount64;
|
public LastTicksManager LastTicks { get; private set; } = new LastTicksManager();
|
||||||
|
|
||||||
public bool Receive { get; init; }
|
public bool Receive { get; init; }
|
||||||
|
|
||||||
@@ -56,7 +56,7 @@ namespace linker.tunnel.connection
|
|||||||
private CancellationTokenSource cancellationTokenSource;
|
private CancellationTokenSource cancellationTokenSource;
|
||||||
private object userToken;
|
private object userToken;
|
||||||
|
|
||||||
private long pingStart = Environment.TickCount64;
|
private LastTicksManager pingTicks = new LastTicksManager();
|
||||||
private byte[] pingBytes = Encoding.UTF8.GetBytes($"{Helper.GlobalString}.udp.ping");
|
private byte[] pingBytes = Encoding.UTF8.GetBytes($"{Helper.GlobalString}.udp.ping");
|
||||||
private byte[] pongBytes = Encoding.UTF8.GetBytes($"{Helper.GlobalString}.udp.pong");
|
private byte[] pongBytes = Encoding.UTF8.GetBytes($"{Helper.GlobalString}.udp.pong");
|
||||||
private byte[] finBytes = Encoding.UTF8.GetBytes($"{Helper.GlobalString}.udp.fing");
|
private byte[] finBytes = Encoding.UTF8.GetBytes($"{Helper.GlobalString}.udp.fing");
|
||||||
@@ -129,7 +129,7 @@ namespace linker.tunnel.connection
|
|||||||
private async Task CallbackPacket(Memory<byte> packet)
|
private async Task CallbackPacket(Memory<byte> packet)
|
||||||
{
|
{
|
||||||
ReceiveBytes += packet.Length;
|
ReceiveBytes += packet.Length;
|
||||||
LastTicks = Environment.TickCount64;
|
LastTicks.Update();
|
||||||
|
|
||||||
Memory<byte> memory = packet.Slice(4);
|
Memory<byte> memory = packet.Slice(4);
|
||||||
if (memory.Length == pingBytes.Length && memory.Span.Slice(0, pingBytes.Length - 4).SequenceEqual(pingBytes.AsSpan(0, pingBytes.Length - 4)))
|
if (memory.Length == pingBytes.Length && memory.Span.Slice(0, pingBytes.Length - 4).SequenceEqual(pingBytes.AsSpan(0, pingBytes.Length - 4)))
|
||||||
@@ -140,7 +140,7 @@ namespace linker.tunnel.connection
|
|||||||
}
|
}
|
||||||
else if (memory.Span.SequenceEqual(pongBytes))
|
else if (memory.Span.SequenceEqual(pongBytes))
|
||||||
{
|
{
|
||||||
Delay = (int)(Environment.TickCount64 - pingStart);
|
Delay = (int)pingTicks.Diff();
|
||||||
pong = true;
|
pong = true;
|
||||||
}
|
}
|
||||||
else if (memory.Span.SequenceEqual(finBytes))
|
else if (memory.Span.SequenceEqual(finBytes))
|
||||||
@@ -178,9 +178,9 @@ namespace linker.tunnel.connection
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Environment.TickCount64 - LastTicks > 3000)
|
if (LastTicks.Greater(3000))
|
||||||
{
|
{
|
||||||
pingStart = Environment.TickCount64;
|
pingTicks.Update();
|
||||||
await SendPingPong(pingBytes).ConfigureAwait(false);
|
await SendPingPong(pingBytes).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
await Task.Delay(3000).ConfigureAwait(false);
|
await Task.Delay(3000).ConfigureAwait(false);
|
||||||
@@ -218,7 +218,7 @@ namespace linker.tunnel.connection
|
|||||||
{
|
{
|
||||||
if (pong == false) return;
|
if (pong == false) return;
|
||||||
pong = false;
|
pong = false;
|
||||||
pingStart = Environment.TickCount64;
|
pingTicks.Update();
|
||||||
await SendPingPong(pingBytes).ConfigureAwait(false);
|
await SendPingPong(pingBytes).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -258,7 +258,7 @@ namespace linker.tunnel.connection
|
|||||||
|
|
||||||
SendPingPong(finBytes).ContinueWith((result) =>
|
SendPingPong(finBytes).ContinueWith((result) =>
|
||||||
{
|
{
|
||||||
LastTicks = 0;
|
LastTicks.Clear();
|
||||||
if (Receive == true)
|
if (Receive == true)
|
||||||
UdpClient?.SafeClose();
|
UdpClient?.SafeClose();
|
||||||
uUdpClient = null;
|
uUdpClient = null;
|
||||||
|
@@ -351,8 +351,7 @@ namespace linker.tunnel.transport
|
|||||||
{
|
{
|
||||||
TimerHelper.SetInterval(() =>
|
TimerHelper.SetInterval(() =>
|
||||||
{
|
{
|
||||||
long ticks = Environment.TickCount64;
|
var keys = connectionsDic.Where(c => (c.Value.Connection == null && c.Value.LastTicks.Greater(5000)) || (c.Value.Connection != null && c.Value.Connection.Connected == false)).Select(c => c.Key).ToList();
|
||||||
var keys = connectionsDic.Where(c => (c.Value.Connection == null && ticks - c.Value.LastTicks > 5000) || (c.Value.Connection != null && c.Value.Connection.Connected == false)).Select(c => c.Key).ToList();
|
|
||||||
foreach (var item in keys)
|
foreach (var item in keys)
|
||||||
{
|
{
|
||||||
connectionsDic.TryRemove(item, out _);
|
connectionsDic.TryRemove(item, out _);
|
||||||
@@ -370,7 +369,7 @@ namespace linker.tunnel.transport
|
|||||||
|
|
||||||
public sealed class ConnectionCacheInfo
|
public sealed class ConnectionCacheInfo
|
||||||
{
|
{
|
||||||
public long LastTicks { get; set; } = Environment.TickCount64;
|
public LastTicksManager LastTicks { get; set; } = new LastTicksManager();
|
||||||
public TunnelConnectionUdp Connection { get; set; }
|
public TunnelConnectionUdp Connection { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -2,4 +2,10 @@ import { sendWebsocketMsg } from './request'
|
|||||||
|
|
||||||
export const getFlows = () => {
|
export const getFlows = () => {
|
||||||
return sendWebsocketMsg('flowClient/GetFlows');
|
return sendWebsocketMsg('flowClient/GetFlows');
|
||||||
|
}
|
||||||
|
export const getMessengerFlows = () => {
|
||||||
|
return sendWebsocketMsg('flowClient/GetMessengerFlows');
|
||||||
|
}
|
||||||
|
export const getSForwardFlows = (data) => {
|
||||||
|
return sendWebsocketMsg('flowClient/GetSForwardFlows', data);
|
||||||
}
|
}
|
@@ -22,4 +22,8 @@ export const updateTuntap = (name) => {
|
|||||||
}
|
}
|
||||||
export const refreshTuntap = () => {
|
export const refreshTuntap = () => {
|
||||||
return sendWebsocketMsg('tuntapclient/refresh');
|
return sendWebsocketMsg('tuntapclient/refresh');
|
||||||
}
|
}
|
||||||
|
export const subscribePing = () => {
|
||||||
|
return sendWebsocketMsg('tuntapclient/SubscribePing');
|
||||||
|
}
|
||||||
|
|
||||||
|
@@ -30,4 +30,7 @@ export const confirmServer = (version) => {
|
|||||||
}
|
}
|
||||||
export const exitServer = () => {
|
export const exitServer = () => {
|
||||||
return sendWebsocketMsg('updaterclient/exitserver');
|
return sendWebsocketMsg('updaterclient/exitserver');
|
||||||
|
}
|
||||||
|
export const subscribeUpdater = () => {
|
||||||
|
return sendWebsocketMsg('updaterclient/Subscribe');
|
||||||
}
|
}
|
@@ -81,7 +81,7 @@ export default {
|
|||||||
handleTunnelConnections,clearConnectionsTimeout
|
handleTunnelConnections,clearConnectionsTimeout
|
||||||
} = provideConnections();
|
} = provideConnections();
|
||||||
|
|
||||||
const {_getUpdater,clearUpdaterTimeout} = provideUpdater();
|
const {_getUpdater,_subscribeUpdater,clearUpdaterTimeout} = provideUpdater();
|
||||||
|
|
||||||
const {_getAccessInfo,clearAccessTimeout} = provideAccess();
|
const {_getAccessInfo,clearAccessTimeout} = provideAccess();
|
||||||
|
|
||||||
@@ -158,6 +158,7 @@ export default {
|
|||||||
_getSForwardInfo();
|
_getSForwardInfo();
|
||||||
|
|
||||||
_getUpdater();
|
_getUpdater();
|
||||||
|
_subscribeUpdater();
|
||||||
|
|
||||||
_getAccessInfo();
|
_getAccessInfo();
|
||||||
|
|
||||||
|
@@ -9,17 +9,14 @@
|
|||||||
<el-input v-model="state.ruleForm.IP" style="width:14rem" />
|
<el-input v-model="state.ruleForm.IP" style="width:14rem" />
|
||||||
<span>/</span>
|
<span>/</span>
|
||||||
<el-input @change="handlePrefixLengthChange" v-model="state.ruleForm.PrefixLength" style="width:4rem" />
|
<el-input @change="handlePrefixLengthChange" v-model="state.ruleForm.PrefixLength" style="width:4rem" />
|
||||||
<span style="width: 3rem;"></span>
|
<span style="width: 2rem;"></span>
|
||||||
<el-checkbox v-model="state.ruleForm.ShowDelay" label="显示延迟" size="large" />
|
<el-checkbox v-model="state.ruleForm.ShowDelay" label="显示延迟" size="large" />
|
||||||
<el-popover
|
<el-checkbox v-model="state.ruleForm.AutoConnect" label="自动连接" size="large" />
|
||||||
placement="top" title="提示" :width="400" trigger="hover"
|
<!-- <el-popover placement="top" title="提示" :width="400" trigger="hover" content="当有大量客户端使用中继是,广播会使用服务器更多流量" >
|
||||||
content="在测试延迟时,如果未连接,将自动去打洞连接,当你有一百个设备时,每个设备都同时去与其它99台设备连接,这数据量不小,所以尽量不要个设备都勾选"
|
|
||||||
>
|
|
||||||
<template #reference>
|
<template #reference>
|
||||||
<el-checkbox v-model="state.ruleForm.AutoConnect" label="自动连接?" size="large" />
|
<el-checkbox v-model="state.ruleForm.Multicast" label="启用广播" size="large" />
|
||||||
</template>
|
</template>
|
||||||
</el-popover>
|
</el-popover> -->
|
||||||
|
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item prop="upgrade" style="margin-bottom:0">
|
<el-form-item prop="upgrade" style="margin-bottom:0">
|
||||||
<el-checkbox v-model="state.ruleForm.Upgrade" label="我很懂,我要使用高级功能(点对网和网对网)" size="large" />
|
<el-checkbox v-model="state.ruleForm.Upgrade" label="我很懂,我要使用高级功能(点对网和网对网)" size="large" />
|
||||||
@@ -104,6 +101,7 @@ export default {
|
|||||||
ShowDelay: tuntap.value.current.ShowDelay,
|
ShowDelay: tuntap.value.current.ShowDelay,
|
||||||
AutoConnect: tuntap.value.current.AutoConnect,
|
AutoConnect: tuntap.value.current.AutoConnect,
|
||||||
Upgrade: tuntap.value.current.Upgrade,
|
Upgrade: tuntap.value.current.Upgrade,
|
||||||
|
Multicast: tuntap.value.current.Multicast,
|
||||||
|
|
||||||
Forwards:tuntap.value.current.Forwards.length == 0 ? [
|
Forwards:tuntap.value.current.Forwards.length == 0 ? [
|
||||||
{ListenAddr:'0.0.0.0',ListenPort:0,ConnectAddr:'0.0.0.0',ConnectPort:0}
|
{ListenAddr:'0.0.0.0',ListenPort:0,ConnectAddr:'0.0.0.0',ConnectPort:0}
|
||||||
@@ -165,6 +163,7 @@ export default {
|
|||||||
json.ShowDelay = state.ruleForm.ShowDelay;
|
json.ShowDelay = state.ruleForm.ShowDelay;
|
||||||
json.AutoConnect = state.ruleForm.AutoConnect;
|
json.AutoConnect = state.ruleForm.AutoConnect;
|
||||||
json.Upgrade = state.ruleForm.Upgrade;
|
json.Upgrade = state.ruleForm.Upgrade;
|
||||||
|
json.Multicast = state.ruleForm.Multicast;
|
||||||
json.Forwards = state.ruleForm.Forwards;
|
json.Forwards = state.ruleForm.Forwards;
|
||||||
json.Forwards.forEach(c=>{
|
json.Forwards.forEach(c=>{
|
||||||
c.ListenPort=+c.ListenPort;
|
c.ListenPort=+c.ListenPort;
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
import { injectGlobalData } from "@/provide";
|
import { injectGlobalData } from "@/provide";
|
||||||
import { ElMessage } from "element-plus";
|
import { ElMessage } from "element-plus";
|
||||||
import { inject, provide, ref } from "vue"
|
import { inject, provide, ref } from "vue"
|
||||||
import { getTuntapInfo, refreshTuntap } from "@/apis/tuntap";
|
import { getTuntapInfo, refreshTuntap, subscribePing } from "@/apis/tuntap";
|
||||||
|
|
||||||
const tuntapSymbol = Symbol();
|
const tuntapSymbol = Symbol();
|
||||||
export const provideTuntap = () => {
|
export const provideTuntap = () => {
|
||||||
@@ -57,6 +57,7 @@ export const provideTuntap = () => {
|
|||||||
tuntap.value.list = res.List;
|
tuntap.value.list = res.List;
|
||||||
}
|
}
|
||||||
tuntap.value.timer = setTimeout(_getTuntapInfo, 1100);
|
tuntap.value.timer = setTimeout(_getTuntapInfo, 1100);
|
||||||
|
subscribePing();
|
||||||
}).catch((e) => {
|
}).catch((e) => {
|
||||||
tuntap.value.timer = setTimeout(_getTuntapInfo, 1100);
|
tuntap.value.timer = setTimeout(_getTuntapInfo, 1100);
|
||||||
});
|
});
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
import { getUpdater } from "@/apis/updater";
|
import { getUpdater, subscribeUpdater } from "@/apis/updater";
|
||||||
import { injectGlobalData } from "@/provide";
|
import { injectGlobalData } from "@/provide";
|
||||||
import { inject, provide, ref } from "vue";
|
import { inject, provide, ref } from "vue";
|
||||||
|
|
||||||
@@ -9,7 +9,9 @@ export const provideUpdater = () => {
|
|||||||
timer: 0,
|
timer: 0,
|
||||||
list: {},
|
list: {},
|
||||||
hashcode: 0,
|
hashcode: 0,
|
||||||
current: { Version: '', Msg: [], DateTime: '', Status: 0, Length: 0, Current: 0 }
|
current: { Version: '', Msg: [], DateTime: '', Status: 0, Length: 0, Current: 0 },
|
||||||
|
|
||||||
|
subscribeTimer: 0
|
||||||
});
|
});
|
||||||
provide(updaterSymbol, updater);
|
provide(updaterSymbol, updater);
|
||||||
const _getUpdater = () => {
|
const _getUpdater = () => {
|
||||||
@@ -36,15 +38,23 @@ export const provideUpdater = () => {
|
|||||||
updater.value.timer = setTimeout(_getUpdater, 800);
|
updater.value.timer = setTimeout(_getUpdater, 800);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
const _subscribeUpdater = () => {
|
||||||
|
subscribeUpdater().then(() => {
|
||||||
|
updater.value.subscribeTimer = setTimeout(_subscribeUpdater, 5000);
|
||||||
|
}).catch(() => {
|
||||||
|
updater.value.subscribeTimer = setTimeout(_subscribeUpdater, 5000);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
const clearUpdaterTimeout = () => {
|
const clearUpdaterTimeout = () => {
|
||||||
clearTimeout(updater.value.timer);
|
clearTimeout(updater.value.timer);
|
||||||
|
clearTimeout(updater.value.subscribeTimer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
updater, _getUpdater, clearUpdaterTimeout
|
updater, _getUpdater, _subscribeUpdater, clearUpdaterTimeout
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
export const useUpdater = () => {
|
export const useUpdater = () => {
|
||||||
|
@@ -6,7 +6,7 @@
|
|||||||
<el-dialog :title="state.time" destroy-on-close v-model="state.show" width="540">
|
<el-dialog :title="state.time" destroy-on-close v-model="state.show" width="540">
|
||||||
<div>
|
<div>
|
||||||
<el-table :data="state.list" border size="small" width="100%">
|
<el-table :data="state.list" border size="small" width="100%">
|
||||||
<el-table-column prop="id" label="类别" width="80"></el-table-column>
|
<el-table-column prop="text" label="类别" width="80"></el-table-column>
|
||||||
<el-table-column prop="sendtBytes" label="已上传" sortable>
|
<el-table-column prop="sendtBytes" label="已上传" sortable>
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
<span>{{ scope.row.sendtBytesText }}</span>
|
<span>{{ scope.row.sendtBytesText }}</span>
|
||||||
@@ -29,21 +29,24 @@
|
|||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column prop="oper" label="操作" width="64">
|
<el-table-column prop="oper" label="操作" width="64">
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
<el-button v-if="scope.row.detail" size="small">详情</el-button>
|
<el-button v-if="scope.row.detail" size="small" @click="handleShowDetail(scope.row.id)">详情</el-button>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
</el-table>
|
</el-table>
|
||||||
</div>
|
</div>
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
|
<ServerFlowMessenger :config="config" v-if="state.details.Messenger" v-model="state.details.Messenger"></ServerFlowMessenger>
|
||||||
|
<ServerFlowSForward :config="config" v-if="state.details.SForward" v-model="state.details.SForward"></ServerFlowSForward>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { getFlows } from '@/apis/flow';
|
import { getFlows } from '@/apis/flow';
|
||||||
import { getTunnelRecords } from '@/apis/tunnel';
|
|
||||||
import { onMounted, onUnmounted, reactive } from 'vue';
|
import { onMounted, onUnmounted, reactive } from 'vue';
|
||||||
|
import ServerFlowMessenger from './ServerFlowMessenger.vue';
|
||||||
|
import ServerFlowSForward from './ServerFlowSForward.vue';
|
||||||
export default {
|
export default {
|
||||||
props:['config'],
|
props:['config'],
|
||||||
|
components:{ServerFlowMessenger,ServerFlowSForward},
|
||||||
setup (props) {
|
setup (props) {
|
||||||
|
|
||||||
const state = reactive({
|
const state = reactive({
|
||||||
@@ -53,105 +56,51 @@ export default {
|
|||||||
overallReceiveSpeed: '0000.00KB',
|
overallReceiveSpeed: '0000.00KB',
|
||||||
time:'',
|
time:'',
|
||||||
list:[],
|
list:[],
|
||||||
old:null
|
old:null,
|
||||||
|
details:{
|
||||||
|
Messenger:false,
|
||||||
|
SForward:false,
|
||||||
|
}
|
||||||
});
|
});
|
||||||
const handleShow = ()=>{
|
const handleShow = ()=>{
|
||||||
state.show = true;
|
state.show = true;
|
||||||
}
|
}
|
||||||
|
const handleShowDetail = (id)=>{
|
||||||
const details = {
|
state.details[id] = true;
|
||||||
'Relay':true,
|
|
||||||
'Messenger':true,
|
|
||||||
'SForward':true,
|
|
||||||
};
|
|
||||||
const id2text = {
|
|
||||||
'External':'外网端口',
|
|
||||||
'Relay':'中继流量',
|
|
||||||
'Messenger':'信标流量',
|
|
||||||
'SForward':'内网穿透',
|
|
||||||
'0':'[信标]登入信标',
|
|
||||||
'1':'[信标]客户端列表',
|
|
||||||
'2':'[信标]客户端删除',
|
|
||||||
'4':'[信标]客户端改名(转发)',
|
|
||||||
'7':'[信标]获取服务器版本',
|
|
||||||
'8':'[信标]客户端搜索ids',
|
|
||||||
'9':'[信标]客户端id列表',
|
|
||||||
'10':'[信标]客户端排序',
|
|
||||||
'11':'[信标]客户端在线',
|
|
||||||
'12':'[信标]生成客户端id',
|
|
||||||
'13':'[信标]登入信标V_1_3_1',
|
|
||||||
|
|
||||||
'2001':'[信标]外网端口(转发)',
|
|
||||||
'2002':'[信标]外网端口(转发)',
|
|
||||||
'2003':'[信标]开始打洞(转发)',
|
|
||||||
'2004':'[信标]开始打洞(转发)',
|
|
||||||
'2005':'[信标]打洞失败(转发)',
|
|
||||||
'2006':'[信标]打洞失败(转发)',
|
|
||||||
'2007':'[信标]打洞成功(转发)',
|
|
||||||
'2008':'[信标]打洞成功(转发)',
|
|
||||||
'2009':'[信标]隧道配置(转发)',
|
|
||||||
'2010':'[信标]隧道配置(转发)',
|
|
||||||
'2012':'[信标]隧道同步(转发)',
|
|
||||||
|
|
||||||
'2101':'[信标]中继通知(转发)',
|
|
||||||
'2102':'[信标]中继通知(转发)',
|
|
||||||
'2103':'[信标]中继请求',
|
|
||||||
'2105':'[信标]中继连通测试',
|
|
||||||
|
|
||||||
'2201':'[信标]运行网卡(转发)',
|
|
||||||
'2203':'[信标]停止网卡(转发)',
|
|
||||||
'2205':'[信标]更新网卡(转发)',
|
|
||||||
'2206':'[信标]同步网卡(转发)',
|
|
||||||
'2207':'[信标]同步网卡(转发)',
|
|
||||||
|
|
||||||
'2301':'[信标]添加内网穿透',
|
|
||||||
'2302':'[信标]移除内网穿透',
|
|
||||||
'2305':'[信标]获取穿透列表(转发)',
|
|
||||||
|
|
||||||
'2401':'[信标]测试端口转发(转发)',
|
|
||||||
'2403':'[信标]获取端口转发(转发)',
|
|
||||||
|
|
||||||
'2503':'[信标]获取权限(转发)',
|
|
||||||
'2504':'[信标]获取权限(转发)',
|
|
||||||
'2506':'[信标]更新权限(转发)',
|
|
||||||
'2508':'[信标]同步密钥(转发)',
|
|
||||||
'2510':'[信标]同步服务器(转发)',
|
|
||||||
|
|
||||||
'2601':'[信标]更新信息(转发)',
|
|
||||||
'2602':'[信标]更新信息(转发)',
|
|
||||||
'2603':'[信标]确认更新(转发)',
|
|
||||||
'2604':'[信标]确认更新(转发)',
|
|
||||||
'2605':'[信标]重启(转发)',
|
|
||||||
'2607':'[信标]服务器更新信息',
|
|
||||||
'2608':'[信标]确认服务器更新',
|
|
||||||
'2609':'[信标]服务器重启',
|
|
||||||
|
|
||||||
'2701':'[信标]获取服务器流量',
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const id2text = {
|
||||||
|
'External':{text:'外网端口',detail:false},
|
||||||
|
'Relay':{text:'中继',detail:true},
|
||||||
|
'Messenger':{text:'信标',detail:true},
|
||||||
|
'SForward':{text:'内网穿透',detail:true},
|
||||||
|
};
|
||||||
const _getFlows = ()=>{
|
const _getFlows = ()=>{
|
||||||
getFlows().then(res => {
|
getFlows().then(res => {
|
||||||
const old = state.old || res;
|
const old = state.old || res;
|
||||||
|
|
||||||
let _receiveBytes = 0,_sendtBytes = 0,receiveBytes = 0,sendtBytes = 0;
|
let _receiveBytes = 0,_sendtBytes = 0,receiveBytes = 0,sendtBytes = 0;
|
||||||
for(let j in old.Resolvers){
|
for(let j in old.Items){
|
||||||
_receiveBytes+=old.Resolvers[j].ReceiveBytes;
|
_receiveBytes+=old.Items[j].ReceiveBytes;
|
||||||
_sendtBytes+=old.Resolvers[j].SendtBytes;
|
_sendtBytes+=old.Items[j].SendtBytes;
|
||||||
}
|
}
|
||||||
for(let j in res.Resolvers){
|
for(let j in res.Items){
|
||||||
receiveBytes+=res.Resolvers[j].ReceiveBytes;
|
receiveBytes+=res.Items[j].ReceiveBytes;
|
||||||
sendtBytes+=res.Resolvers[j].SendtBytes;
|
sendtBytes+=res.Items[j].SendtBytes;
|
||||||
}
|
}
|
||||||
state.overallSendtSpeed = parseSpeed(sendtBytes-_sendtBytes);
|
state.overallSendtSpeed = parseSpeed(sendtBytes-_sendtBytes);
|
||||||
state.overallReceiveSpeed = parseSpeed(receiveBytes-_receiveBytes);
|
state.overallReceiveSpeed = parseSpeed(receiveBytes-_receiveBytes);
|
||||||
|
|
||||||
state.time = `从 ${res.Start}启动 至今`;
|
state.time = `从 ${res.Start}启动 至今`;
|
||||||
const list = [];
|
const list = [];
|
||||||
for(let j in res.Resolvers){
|
for(let j in res.Items){
|
||||||
const item = res.Resolvers[j];
|
const item = res.Items[j];
|
||||||
const itemOld = old.Resolvers[j];
|
const itemOld = old.Items[j];
|
||||||
|
const text = id2text[`${j}`] || {text:'未知',detail:false};
|
||||||
list.push({
|
list.push({
|
||||||
id:id2text[`${j}`],
|
id:j,
|
||||||
detail:details[`${j}`] || false,
|
text:text.text,
|
||||||
|
detail:text.detail,
|
||||||
|
|
||||||
sendtBytes:item.SendtBytes,
|
sendtBytes:item.SendtBytes,
|
||||||
sendtBytesText:parseSpeed(item.SendtBytes),
|
sendtBytesText:parseSpeed(item.SendtBytes),
|
||||||
@@ -166,24 +115,6 @@ export default {
|
|||||||
receiveSpeedText:parseSpeed(item.ReceiveBytes-itemOld.ReceiveBytes),
|
receiveSpeedText:parseSpeed(item.ReceiveBytes-itemOld.ReceiveBytes),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
// for(let j in res.Messangers){
|
|
||||||
// const item = res.Messangers[j];
|
|
||||||
// const itemOld = old.Messangers[j];
|
|
||||||
// list.push({
|
|
||||||
// id:id2text[`${j}`] || `未知的${j}`,
|
|
||||||
// sendtBytes:item.SendtBytes,
|
|
||||||
// sendtBytesText:parseSpeed(item.SendtBytes),
|
|
||||||
|
|
||||||
// sendtSpeed:item.SendtBytes-itemOld.SendtBytes,
|
|
||||||
// sendtSpeedText:parseSpeed(item.SendtBytes-itemOld.SendtBytes),
|
|
||||||
|
|
||||||
// receiveBytes:item.ReceiveBytes,
|
|
||||||
// receiveBytesText:parseSpeed(item.ReceiveBytes),
|
|
||||||
|
|
||||||
// receiveSpeed:item.ReceiveBytes-itemOld.ReceiveBytes,
|
|
||||||
// receiveSpeedText:parseSpeed(item.ReceiveBytes-itemOld.ReceiveBytes),
|
|
||||||
// });
|
|
||||||
// }
|
|
||||||
state.list = list.filter(c=>!!c.id);
|
state.list = list.filter(c=>!!c.id);
|
||||||
|
|
||||||
state.old = res;
|
state.old = res;
|
||||||
@@ -201,18 +132,6 @@ export default {
|
|||||||
return `${num.toFixed(2)}${['B', 'KB', 'MB', 'GB', 'TB'][index]}`;
|
return `${num.toFixed(2)}${['B', 'KB', 'MB', 'GB', 'TB'][index]}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
const _getTunnelRecords = ()=>{
|
|
||||||
getTunnelRecords().then(res => {
|
|
||||||
console.log(Object.values(res).map(c=>{
|
|
||||||
c.To = Object.values(c.To).sort((a,b)=>b.Times-a.Times);
|
|
||||||
return c;
|
|
||||||
}).sort((a,b)=>b.Times-a.Times));
|
|
||||||
setTimeout(_getTunnelRecords,1000);
|
|
||||||
}).catch((e)=>{
|
|
||||||
setTimeout(_getTunnelRecords,1000);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
onMounted(()=>{
|
onMounted(()=>{
|
||||||
_getFlows();
|
_getFlows();
|
||||||
//_getTunnelRecords();
|
//_getTunnelRecords();
|
||||||
@@ -223,7 +142,7 @@ export default {
|
|||||||
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
config:props.config,state,handleShow
|
config:props.config,state,handleShow,handleShowDetail
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
189
linker.web/src/views/full/status/ServerFlowMessenger.vue
Normal file
189
linker.web/src/views/full/status/ServerFlowMessenger.vue
Normal file
@@ -0,0 +1,189 @@
|
|||||||
|
<template>
|
||||||
|
<el-dialog title="信标流量" class="options-center" top="1vh" destroy-on-close v-model="state.show" width="680">
|
||||||
|
<div>
|
||||||
|
<el-table :data="state.list" stripe border size="small" width="100%" height="60vh">
|
||||||
|
<el-table-column prop="id" label="信标id" width="200"></el-table-column>
|
||||||
|
<el-table-column prop="sendtBytes" label="已上传" sortable>
|
||||||
|
<template #default="scope">
|
||||||
|
<span>{{ scope.row.sendtBytesText }}</span>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column prop="sendtSpeed" label="上传速度" sortable>
|
||||||
|
<template #default="scope">
|
||||||
|
<span>{{ scope.row.sendtSpeedText }}/s</span>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column prop="receiveBytes" label="已下载" sortable>
|
||||||
|
<template #default="scope">
|
||||||
|
<span>{{ scope.row.receiveBytesText }}</span>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column prop="receiveSpeed" label="下载速度" sortable>
|
||||||
|
<template #default="scope">
|
||||||
|
<span>{{ scope.row.receiveSpeedText }}/s</span>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</el-table>
|
||||||
|
</div>
|
||||||
|
</el-dialog>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { getMessengerFlows } from '@/apis/flow';
|
||||||
|
import { onMounted, onUnmounted, reactive, watch } from 'vue';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
props: ['modelValue','config'],
|
||||||
|
emits: ['update:modelValue'],
|
||||||
|
setup (props,{emit}) {
|
||||||
|
|
||||||
|
const state = reactive({
|
||||||
|
show:true,
|
||||||
|
timer:0,
|
||||||
|
list:[],
|
||||||
|
old:null
|
||||||
|
});
|
||||||
|
watch(() => state.show, (val) => {
|
||||||
|
if (!val) {
|
||||||
|
setTimeout(() => {
|
||||||
|
emit('update:modelValue', val);
|
||||||
|
}, 300);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const id2text = {
|
||||||
|
'0':'登入信标',
|
||||||
|
'1':'客户端列表',
|
||||||
|
'2':'客户端删除',
|
||||||
|
'4':'客户端改名(转发)',
|
||||||
|
'7':'获取服务器版本',
|
||||||
|
'8':'客户端搜索ids',
|
||||||
|
'9':'客户端id列表',
|
||||||
|
'10':'客户端排序',
|
||||||
|
'11':'客户端在线',
|
||||||
|
'12':'生成客户端id',
|
||||||
|
'13':'登入信标V_1_3_1',
|
||||||
|
|
||||||
|
'2001':'外网端口(转发)',
|
||||||
|
'2002':'外网端口(转发)',
|
||||||
|
'2003':'开始打洞(转发)',
|
||||||
|
'2004':'开始打洞(转发)',
|
||||||
|
'2005':'打洞失败(转发)',
|
||||||
|
'2006':'打洞失败(转发)',
|
||||||
|
'2007':'打洞成功(转发)',
|
||||||
|
'2008':'打洞成功(转发)',
|
||||||
|
'2009':'隧道配置(转发)',
|
||||||
|
'2010':'隧道配置(转发)',
|
||||||
|
'2012':'隧道同步(转发)',
|
||||||
|
|
||||||
|
'2101':'中继通知(转发)',
|
||||||
|
'2102':'中继通知(转发)',
|
||||||
|
'2103':'中继请求',
|
||||||
|
'2105':'中继连通测试',
|
||||||
|
|
||||||
|
'2201':'运行网卡(转发)',
|
||||||
|
'2203':'停止网卡(转发)',
|
||||||
|
'2205':'更新网卡(转发)',
|
||||||
|
'2206':'同步网卡(转发)',
|
||||||
|
'2207':'同步网卡(转发)',
|
||||||
|
|
||||||
|
'2301':'添加内网穿透',
|
||||||
|
'2302':'移除内网穿透',
|
||||||
|
'2303':'通知内网穿透(转发)',
|
||||||
|
'2304':'通知内网穿透UDP(转发)',
|
||||||
|
'2305':'获取穿透列表(转发)',
|
||||||
|
|
||||||
|
'2401':'测试端口转发(转发)',
|
||||||
|
'2403':'获取端口转发(转发)',
|
||||||
|
|
||||||
|
'2503':'获取权限(转发)',
|
||||||
|
'2504':'获取权限(转发)',
|
||||||
|
'2506':'更新权限(转发)',
|
||||||
|
'2508':'同步密钥(转发)',
|
||||||
|
'2510':'同步服务器(转发)',
|
||||||
|
|
||||||
|
'2601':'更新信息(转发)',
|
||||||
|
'2602':'更新信息(转发)',
|
||||||
|
'2603':'确认更新(转发)',
|
||||||
|
'2604':'确认更新(转发)',
|
||||||
|
'2605':'重启(转发)',
|
||||||
|
'2607':'服务器更新信息',
|
||||||
|
'2608':'确认服务器更新',
|
||||||
|
'2609':'服务器重启',
|
||||||
|
'2610':'订阅更新信息(转发)',
|
||||||
|
'2611':'订阅更新信息(转发)',
|
||||||
|
|
||||||
|
'2701':'服务器流量',
|
||||||
|
'2702':'服务器信标流量',
|
||||||
|
'2703':'服务器中继流量',
|
||||||
|
'2704':'服务器内网穿透流量',
|
||||||
|
}
|
||||||
|
|
||||||
|
const _getMessengerFlows = ()=>{
|
||||||
|
getMessengerFlows().then(res => {
|
||||||
|
const old = state.old || res;
|
||||||
|
const list = [];
|
||||||
|
for(let j in res){
|
||||||
|
const item = res[j];
|
||||||
|
const itemOld = old[j];
|
||||||
|
const text = `[${j}]${id2text[`${j}`] || `未知`}`;
|
||||||
|
list.push({
|
||||||
|
id:text,
|
||||||
|
|
||||||
|
sendtBytes:item.SendtBytes,
|
||||||
|
sendtBytesText:parseSpeed(item.SendtBytes),
|
||||||
|
|
||||||
|
sendtSpeed:item.SendtBytes-itemOld.SendtBytes,
|
||||||
|
sendtSpeedText:parseSpeed(item.SendtBytes-itemOld.SendtBytes),
|
||||||
|
|
||||||
|
receiveBytes:item.ReceiveBytes,
|
||||||
|
receiveBytesText:parseSpeed(item.ReceiveBytes),
|
||||||
|
|
||||||
|
receiveSpeed:item.ReceiveBytes-itemOld.ReceiveBytes,
|
||||||
|
receiveSpeedText:parseSpeed(item.ReceiveBytes-itemOld.ReceiveBytes),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
state.list = list.filter(c=>!!c.id);
|
||||||
|
|
||||||
|
state.old = res;
|
||||||
|
state.timer = setTimeout(_getMessengerFlows,1000);
|
||||||
|
}).catch((e)=>{
|
||||||
|
state.timer = setTimeout(_getMessengerFlows,1000);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
const parseSpeed = (num) => {
|
||||||
|
let index = 0;
|
||||||
|
while (num >= 1024) {
|
||||||
|
num /= 1024;
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
return `${num.toFixed(2)}${['B', 'KB', 'MB', 'GB', 'TB'][index]}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(()=>{
|
||||||
|
_getMessengerFlows();
|
||||||
|
});
|
||||||
|
onUnmounted(()=>{
|
||||||
|
clearTimeout(state.timer);
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
return {
|
||||||
|
config:props.config,state
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="stylus" scoped>
|
||||||
|
a{
|
||||||
|
font-weight:bold;position:absolute;right:1rem;bottom:90%;
|
||||||
|
border:1px solid #ddd;
|
||||||
|
background-color:#fff;
|
||||||
|
z-index :9
|
||||||
|
p{
|
||||||
|
line-height:normal;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
158
linker.web/src/views/full/status/ServerFlowSForward.vue
Normal file
158
linker.web/src/views/full/status/ServerFlowSForward.vue
Normal file
@@ -0,0 +1,158 @@
|
|||||||
|
<template>
|
||||||
|
<el-dialog title="内网穿透流量" class="options-center" top="1vh" destroy-on-close v-model="state.show" width="680">
|
||||||
|
<div>
|
||||||
|
<div class="head">
|
||||||
|
<el-input v-model="state.page.Key" placeholder="域名/端口搜索"></el-input>
|
||||||
|
</div>
|
||||||
|
<el-table :data="state.list" stripe border size="small" width="100%" height="60vh" @sort-change="handleSort">
|
||||||
|
<el-table-column prop="id" label="域名/端口" width="200"></el-table-column>
|
||||||
|
<el-table-column prop="sendtBytes" label="已上传" sortable="custom">
|
||||||
|
<template #default="scope">
|
||||||
|
<span>{{ scope.row.sendtBytesText }}</span>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column prop="sendtSpeed" label="上传速度" sortable="custom">
|
||||||
|
<template #default="scope">
|
||||||
|
<span>{{ scope.row.sendtSpeedText }}/s</span>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column prop="receiveBytes" label="已下载" sortable="custom">
|
||||||
|
<template #default="scope">
|
||||||
|
<span>{{ scope.row.receiveBytesText }}</span>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column prop="receiveSpeed" label="下载速度" sortable="custom">
|
||||||
|
<template #default="scope">
|
||||||
|
<span>{{ scope.row.receiveSpeedText }}/s</span>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</el-table>
|
||||||
|
<div class="page t-c">
|
||||||
|
<div class="page-wrap">
|
||||||
|
<el-pagination small background layout="total,prev,pager, next" :total="state.page.Count"
|
||||||
|
:page-size="state.page.PageSize" :current-page="state.page.Page" @current-change="handlePageChange"/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</el-dialog>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { getSForwardFlows } from '@/apis/flow';
|
||||||
|
import { onMounted, onUnmounted, reactive, watch } from 'vue';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
props: ['modelValue','config'],
|
||||||
|
emits: ['update:modelValue'],
|
||||||
|
setup (props,{emit}) {
|
||||||
|
|
||||||
|
const state = reactive({
|
||||||
|
show:true,
|
||||||
|
timer:0,
|
||||||
|
list:[],
|
||||||
|
page:{
|
||||||
|
Key:'',
|
||||||
|
Page:1,
|
||||||
|
PageSize:15,
|
||||||
|
Count:0,
|
||||||
|
Order:1,
|
||||||
|
OrderType:0
|
||||||
|
}
|
||||||
|
});
|
||||||
|
watch(() => state.show, (val) => {
|
||||||
|
if (!val) {
|
||||||
|
setTimeout(() => {
|
||||||
|
emit('update:modelValue', val);
|
||||||
|
}, 300);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const _getSForwardFlows = ()=>{
|
||||||
|
getSForwardFlows({
|
||||||
|
Key: state.page.Key,
|
||||||
|
Page:state.page.Page,
|
||||||
|
PageSize:state.page.PageSize,
|
||||||
|
Order:state.page.Order,
|
||||||
|
OrderType:state.page.OrderType,
|
||||||
|
}).then(res => {
|
||||||
|
state.page.Page = res.Page;
|
||||||
|
state.page.PageSize = res.PageSize;
|
||||||
|
state.page.Count = res.Count;
|
||||||
|
|
||||||
|
const list = [];
|
||||||
|
|
||||||
|
const keys = Object.keys(res.Data);
|
||||||
|
console.log(res.Data);
|
||||||
|
for(let i = 0; i < keys.length; i++ ){
|
||||||
|
const item = res.Data[keys[i]];
|
||||||
|
list.push({
|
||||||
|
id:keys[i],
|
||||||
|
sendtBytes:item.SendtBytes,
|
||||||
|
sendtBytesText:parseSpeed(item.SendtBytes),
|
||||||
|
|
||||||
|
sendtSpeed:item.DiffSendtBytes,
|
||||||
|
sendtSpeedText:parseSpeed(item.DiffSendtBytes),
|
||||||
|
|
||||||
|
receiveBytes:item.ReceiveBytes,
|
||||||
|
receiveBytesText:parseSpeed(item.ReceiveBytes),
|
||||||
|
|
||||||
|
receiveSpeed:item.DiffReceiveBytes,
|
||||||
|
receiveSpeedText:parseSpeed(item.DiffReceiveBytes),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
state.list = list.filter(c=>!!c.id);
|
||||||
|
|
||||||
|
state.old = res;
|
||||||
|
state.timer = setTimeout(_getSForwardFlows,1000);
|
||||||
|
}).catch((e)=>{
|
||||||
|
state.timer = setTimeout(_getSForwardFlows,1000);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
const parseSpeed = (num) => {
|
||||||
|
let index = 0;
|
||||||
|
while (num >= 1024) {
|
||||||
|
num /= 1024;
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
return `${num.toFixed(2)}${['B', 'KB', 'MB', 'GB', 'TB'][index]}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
const handlePageChange = (page)=>{
|
||||||
|
if (page) {
|
||||||
|
state.page.Page = page;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const handleSort = (a)=>{
|
||||||
|
const orderType = {'ascending':1,'descending':0}[a.order];
|
||||||
|
const order = {'sendtBytes':1,'sendtSpeed':2,'receiveBytes':3,'receiveSpeed':4}[a.prop];
|
||||||
|
state.page.Order = order;
|
||||||
|
state.page.OrderType = orderType;
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(()=>{
|
||||||
|
_getSForwardFlows();
|
||||||
|
});
|
||||||
|
onUnmounted(()=>{
|
||||||
|
clearTimeout(state.timer);
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
return {
|
||||||
|
config:props.config,state,handlePageChange,handleSort
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="stylus" scoped>
|
||||||
|
.head{
|
||||||
|
padding-bottom:1rem;
|
||||||
|
text-align:center;
|
||||||
|
.el-input{width:20rem}
|
||||||
|
}
|
||||||
|
.page{padding-top:1rem}
|
||||||
|
.page-wrap{
|
||||||
|
display:inline-block;
|
||||||
|
}
|
||||||
|
</style>
|
@@ -52,7 +52,7 @@ export default {
|
|||||||
const {devices, machineId, _getSignList, _getSignList1,handleDeviceEdit,
|
const {devices, machineId, _getSignList, _getSignList1,handleDeviceEdit,
|
||||||
handlePageChange, handlePageSizeChange, handleDel,clearDevicesTimeout} = provideDevices();
|
handlePageChange, handlePageSizeChange, handleDel,clearDevicesTimeout} = provideDevices();
|
||||||
const {tuntap,_getTuntapInfo,handleTuntapRefresh,clearTuntapTimeout,handleTuntapEdit,sortTuntapIP} = provideTuntap();
|
const {tuntap,_getTuntapInfo,handleTuntapRefresh,clearTuntapTimeout,handleTuntapEdit,sortTuntapIP} = provideTuntap();
|
||||||
const {_getUpdater,clearUpdaterTimeout} = provideUpdater();
|
const {_getUpdater,_subscribeUpdater,clearUpdaterTimeout} = provideUpdater();
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
handlePageChange();
|
handlePageChange();
|
||||||
@@ -63,6 +63,7 @@ export default {
|
|||||||
_getTuntapInfo();
|
_getTuntapInfo();
|
||||||
|
|
||||||
_getUpdater();
|
_getUpdater();
|
||||||
|
_subscribeUpdater();
|
||||||
});
|
});
|
||||||
onUnmounted(() => {
|
onUnmounted(() => {
|
||||||
clearDevicesTimeout();
|
clearDevicesTimeout();
|
||||||
|
@@ -19,7 +19,8 @@
|
|||||||
<Title>linker</Title>
|
<Title>linker</Title>
|
||||||
<Authors>snltty</Authors>
|
<Authors>snltty</Authors>
|
||||||
<Company>snltty</Company>
|
<Company>snltty</Company>
|
||||||
<Description>1. 增加流量统计(暂时显示服务端流量)</Description>
|
<Description>1. 总览,和详细流量统计,一眼知道服务器流量花在哪里
|
||||||
|
2. 优化信标。减少流量,没有操作时尽量不产生流量</Description>
|
||||||
<Copyright>snltty</Copyright>
|
<Copyright>snltty</Copyright>
|
||||||
<PackageProjectUrl>https://github.com/snltty/linker</PackageProjectUrl>
|
<PackageProjectUrl>https://github.com/snltty/linker</PackageProjectUrl>
|
||||||
<RepositoryUrl>https://github.com/snltty/linker</RepositoryUrl>
|
<RepositoryUrl>https://github.com/snltty/linker</RepositoryUrl>
|
||||||
|
@@ -6,6 +6,8 @@ using linker.plugins.client;
|
|||||||
using linker.plugins.capi;
|
using linker.plugins.capi;
|
||||||
using linker.plugins.messenger;
|
using linker.plugins.messenger;
|
||||||
using linker.plugins.flow.messenger;
|
using linker.plugins.flow.messenger;
|
||||||
|
using linker.libs.extends;
|
||||||
|
using linker.plugins.sforward.proxy;
|
||||||
|
|
||||||
namespace linker.plugins.flow
|
namespace linker.plugins.flow
|
||||||
{
|
{
|
||||||
@@ -37,7 +39,34 @@ namespace linker.plugins.flow
|
|||||||
}
|
}
|
||||||
return new FlowInfo();
|
return new FlowInfo();
|
||||||
}
|
}
|
||||||
|
public async Task<Dictionary<ushort, FlowItemInfo>> GetMessengerFlows(ApiControllerParamsInfo param)
|
||||||
|
{
|
||||||
|
MessageResponeInfo resp = await messengerSender.SendReply(new MessageRequestWrap
|
||||||
|
{
|
||||||
|
Connection = clientSignInState.Connection,
|
||||||
|
MessengerId = (ushort)FlowMessengerIds.Messenger,
|
||||||
|
});
|
||||||
|
if (resp.Code == MessageResponeCodes.OK && resp.Data.Length > 0)
|
||||||
|
{
|
||||||
|
return MemoryPackSerializer.Deserialize<Dictionary<ushort, FlowItemInfo>>(resp.Data.Span);
|
||||||
|
}
|
||||||
|
return new Dictionary<ushort, FlowItemInfo>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<SForwardFlowResponseInfo> GetSForwardFlows(ApiControllerParamsInfo param)
|
||||||
|
{
|
||||||
|
MessageResponeInfo resp = await messengerSender.SendReply(new MessageRequestWrap
|
||||||
|
{
|
||||||
|
Connection = clientSignInState.Connection,
|
||||||
|
MessengerId = (ushort)FlowMessengerIds.SForward,
|
||||||
|
Payload = MemoryPackSerializer.Serialize(param.Content.DeJson<SForwardFlowRequestInfo>())
|
||||||
|
});
|
||||||
|
if (resp.Code == MessageResponeCodes.OK && resp.Data.Length > 0)
|
||||||
|
{
|
||||||
|
return MemoryPackSerializer.Deserialize<SForwardFlowResponseInfo>(resp.Data.Span);
|
||||||
|
}
|
||||||
|
return new SForwardFlowResponseInfo();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -7,6 +7,7 @@ namespace linker.plugins.flow
|
|||||||
{
|
{
|
||||||
private List<IFlow> flows = new List<IFlow>();
|
private List<IFlow> flows = new List<IFlow>();
|
||||||
|
|
||||||
|
|
||||||
private readonly ServiceProvider serviceProvider;
|
private readonly ServiceProvider serviceProvider;
|
||||||
public FlowTransfer(ServiceProvider serviceProvider)
|
public FlowTransfer(ServiceProvider serviceProvider)
|
||||||
{
|
{
|
||||||
|
@@ -1,4 +1,5 @@
|
|||||||
using MemoryPack;
|
using linker.libs;
|
||||||
|
using MemoryPack;
|
||||||
using System.Text.Json.Serialization;
|
using System.Text.Json.Serialization;
|
||||||
|
|
||||||
namespace linker.plugins.flow
|
namespace linker.plugins.flow
|
||||||
@@ -11,7 +12,7 @@ namespace linker.plugins.flow
|
|||||||
}
|
}
|
||||||
|
|
||||||
[MemoryPackable]
|
[MemoryPackable]
|
||||||
public sealed partial class FlowItemInfo
|
public partial class FlowItemInfo
|
||||||
{
|
{
|
||||||
public ulong ReceiveBytes { get; set; }
|
public ulong ReceiveBytes { get; set; }
|
||||||
public ulong SendtBytes { get; set; }
|
public ulong SendtBytes { get; set; }
|
||||||
@@ -23,11 +24,10 @@ namespace linker.plugins.flow
|
|||||||
[MemoryPackable]
|
[MemoryPackable]
|
||||||
public sealed partial class FlowInfo
|
public sealed partial class FlowInfo
|
||||||
{
|
{
|
||||||
public Dictionary<string, FlowItemInfo> Resolvers { get; set; }
|
public Dictionary<string, FlowItemInfo> Items { get; set; }
|
||||||
public Dictionary<ushort, FlowItemInfo> Messangers { get; set; }
|
|
||||||
|
|
||||||
public DateTime Start { get; set; }
|
public DateTime Start { get; set; }
|
||||||
public DateTime Now { get; set; }
|
public DateTime Now { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -1,4 +1,5 @@
|
|||||||
using linker.plugins.messenger;
|
using linker.plugins.messenger;
|
||||||
|
using linker.plugins.sforward.proxy;
|
||||||
using MemoryPack;
|
using MemoryPack;
|
||||||
|
|
||||||
namespace linker.plugins.flow.messenger
|
namespace linker.plugins.flow.messenger
|
||||||
@@ -8,14 +9,16 @@ namespace linker.plugins.flow.messenger
|
|||||||
private readonly MessengerResolver messengerResolver;
|
private readonly MessengerResolver messengerResolver;
|
||||||
private readonly FlowTransfer flowTransfer;
|
private readonly FlowTransfer flowTransfer;
|
||||||
private readonly MessengerFlow messengerFlow;
|
private readonly MessengerFlow messengerFlow;
|
||||||
|
private readonly SForwardFlow sForwardFlow;
|
||||||
|
|
||||||
private DateTime start = DateTime.Now;
|
private DateTime start = DateTime.Now;
|
||||||
|
|
||||||
public FlowMessenger(MessengerResolver messengerResolver, FlowTransfer flowTransfer, MessengerFlow messengerFlow)
|
public FlowMessenger(MessengerResolver messengerResolver, FlowTransfer flowTransfer, MessengerFlow messengerFlow, SForwardFlow sForwardFlow)
|
||||||
{
|
{
|
||||||
this.messengerResolver = messengerResolver;
|
this.messengerResolver = messengerResolver;
|
||||||
this.flowTransfer = flowTransfer;
|
this.flowTransfer = flowTransfer;
|
||||||
this.messengerFlow = messengerFlow;
|
this.messengerFlow = messengerFlow;
|
||||||
|
this.sForwardFlow = sForwardFlow;
|
||||||
}
|
}
|
||||||
|
|
||||||
[MessengerId((ushort)FlowMessengerIds.List)]
|
[MessengerId((ushort)FlowMessengerIds.List)]
|
||||||
@@ -23,14 +26,26 @@ namespace linker.plugins.flow.messenger
|
|||||||
{
|
{
|
||||||
FlowInfo serverFlowInfo = new FlowInfo
|
FlowInfo serverFlowInfo = new FlowInfo
|
||||||
{
|
{
|
||||||
Messangers = messengerFlow.GetFlows(),
|
Items = flowTransfer.GetFlows(),
|
||||||
Resolvers = flowTransfer.GetFlows(),
|
|
||||||
Start = start,
|
Start = start,
|
||||||
Now = DateTime.Now,
|
Now = DateTime.Now,
|
||||||
};
|
};
|
||||||
connection.Write(MemoryPackSerializer.Serialize(serverFlowInfo));
|
connection.Write(MemoryPackSerializer.Serialize(serverFlowInfo));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[MessengerId((ushort)FlowMessengerIds.Messenger)]
|
||||||
|
public void Messenger(IConnection connection)
|
||||||
|
{
|
||||||
|
connection.Write(MemoryPackSerializer.Serialize(messengerFlow.GetFlows()));
|
||||||
|
}
|
||||||
|
|
||||||
|
[MessengerId((ushort)FlowMessengerIds.SForward)]
|
||||||
|
public void SForward(IConnection connection)
|
||||||
|
{
|
||||||
|
sForwardFlow.Update();
|
||||||
|
SForwardFlowRequestInfo info = MemoryPackSerializer.Deserialize<SForwardFlowRequestInfo>(connection.ReceiveRequestWrap.Payload.Span);
|
||||||
|
connection.Write(MemoryPackSerializer.Serialize(sForwardFlow.GetFlows(info)));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -5,6 +5,9 @@
|
|||||||
Min = 2700,
|
Min = 2700,
|
||||||
|
|
||||||
List = 2701,
|
List = 2701,
|
||||||
|
Messenger = 2702,
|
||||||
|
Relay = 2703,
|
||||||
|
SForward = 2704,
|
||||||
|
|
||||||
Max = 2799
|
Max = 2799
|
||||||
}
|
}
|
||||||
|
@@ -149,7 +149,7 @@ namespace linker.plugins.forward.proxy
|
|||||||
{
|
{
|
||||||
token.Connection = tunnelToken.Connection;
|
token.Connection = tunnelToken.Connection;
|
||||||
await token.TargetSocket.SendToAsync(tunnelToken.Proxy.Data, target).ConfigureAwait(false);
|
await token.TargetSocket.SendToAsync(tunnelToken.Proxy.Data, target).ConfigureAwait(false);
|
||||||
token.Update();
|
token.LastTicks.Update();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -221,7 +221,7 @@ namespace linker.plugins.forward.proxy
|
|||||||
{
|
{
|
||||||
SocketReceiveFromResult result = await socket.ReceiveFromAsync(udpToken.Buffer, SocketFlags.None, target).ConfigureAwait(false);
|
SocketReceiveFromResult result = await socket.ReceiveFromAsync(udpToken.Buffer, SocketFlags.None, target).ConfigureAwait(false);
|
||||||
udpToken.Proxy.Data = udpToken.Buffer.AsMemory(0, result.ReceivedBytes);
|
udpToken.Proxy.Data = udpToken.Buffer.AsMemory(0, result.ReceivedBytes);
|
||||||
udpToken.Update();
|
udpToken.LastTicks.Update();
|
||||||
await SendToConnection(udpToken).ConfigureAwait(false);
|
await SendToConnection(udpToken).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -384,8 +384,8 @@ namespace linker.plugins.forward.proxy
|
|||||||
|
|
||||||
public byte[] Buffer { get; set; }
|
public byte[] Buffer { get; set; }
|
||||||
|
|
||||||
public long LastTime { get; set; } = Environment.TickCount64;
|
public LastTicksManager LastTicks { get; set; } = new LastTicksManager();
|
||||||
public bool Timeout => Environment.TickCount64 - LastTime > 60*60*1000;
|
public bool Timeout => LastTicks.Timeout(60 * 60 * 1000);
|
||||||
public void Clear()
|
public void Clear()
|
||||||
{
|
{
|
||||||
TargetSocket?.SafeClose();
|
TargetSocket?.SafeClose();
|
||||||
@@ -393,10 +393,6 @@ namespace linker.plugins.forward.proxy
|
|||||||
GC.Collect();
|
GC.Collect();
|
||||||
GC.SuppressFinalize(this);
|
GC.SuppressFinalize(this);
|
||||||
}
|
}
|
||||||
public void Update()
|
|
||||||
{
|
|
||||||
LastTime = Environment.TickCount64;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
public sealed class ConnectIdUdpComparer : IEqualityComparer<ConnectIdUdp>
|
public sealed class ConnectIdUdpComparer : IEqualityComparer<ConnectIdUdp>
|
||||||
{
|
{
|
||||||
|
@@ -246,7 +246,7 @@ namespace linker.plugins.messenger
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public override bool Connected => SourceSocket != null && ticks > 0 && Environment.TickCount64 - ticks < 15000;
|
public override bool Connected => SourceSocket != null && lastTicks.Timeout(15000) == false;
|
||||||
|
|
||||||
|
|
||||||
private IConnectionReceiveCallback callback;
|
private IConnectionReceiveCallback callback;
|
||||||
@@ -256,8 +256,8 @@ namespace linker.plugins.messenger
|
|||||||
private bool framing;
|
private bool framing;
|
||||||
private ReceiveDataBuffer bufferCache = new ReceiveDataBuffer();
|
private ReceiveDataBuffer bufferCache = new ReceiveDataBuffer();
|
||||||
|
|
||||||
private long ticks = Environment.TickCount64;
|
private LastTicksManager lastTicks = new LastTicksManager();
|
||||||
private long pingStart = Environment.TickCount64;
|
private LastTicksManager pingTicks =new LastTicksManager();
|
||||||
private static byte[] pingBytes = Encoding.UTF8.GetBytes($"{Helper.GlobalString}.tcp.ping");
|
private static byte[] pingBytes = Encoding.UTF8.GetBytes($"{Helper.GlobalString}.tcp.ping");
|
||||||
private static byte[] pongBytes = Encoding.UTF8.GetBytes($"{Helper.GlobalString}.tcp.pong");
|
private static byte[] pongBytes = Encoding.UTF8.GetBytes($"{Helper.GlobalString}.tcp.pong");
|
||||||
private bool pong = true;
|
private bool pong = true;
|
||||||
@@ -297,7 +297,7 @@ namespace linker.plugins.messenger
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
ReceiveBytes += length;
|
ReceiveBytes += length;
|
||||||
ticks = Environment.TickCount64;
|
lastTicks.Update();
|
||||||
await ReadPacket(buffer.AsMemory(0, length)).ConfigureAwait(false);
|
await ReadPacket(buffer.AsMemory(0, length)).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -310,7 +310,7 @@ namespace linker.plugins.messenger
|
|||||||
{
|
{
|
||||||
LoggerHelper.Instance.Error(ex);
|
LoggerHelper.Instance.Error(ex);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
@@ -362,7 +362,7 @@ namespace linker.plugins.messenger
|
|||||||
}
|
}
|
||||||
else if (packet.Span.SequenceEqual(pongBytes))
|
else if (packet.Span.SequenceEqual(pongBytes))
|
||||||
{
|
{
|
||||||
Delay = (int)(Environment.TickCount64 - pingStart);
|
Delay = (int)pingTicks.Diff();
|
||||||
pong = true;
|
pong = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -384,9 +384,9 @@ namespace linker.plugins.messenger
|
|||||||
{
|
{
|
||||||
while (cancellationTokenSource.IsCancellationRequested == false)
|
while (cancellationTokenSource.IsCancellationRequested == false)
|
||||||
{
|
{
|
||||||
if (Environment.TickCount64 - ticks > 3000)
|
if (lastTicks.Greater(3000))
|
||||||
{
|
{
|
||||||
pingStart = Environment.TickCount64;
|
pingTicks .Update();
|
||||||
await SendPingPong(pingBytes).ConfigureAwait(false);
|
await SendPingPong(pingBytes).ConfigureAwait(false);
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -435,7 +435,7 @@ namespace linker.plugins.messenger
|
|||||||
{
|
{
|
||||||
if (pong == false) return;
|
if (pong == false) return;
|
||||||
pong = false;
|
pong = false;
|
||||||
pingStart = Environment.TickCount64;
|
pingTicks.Update();
|
||||||
await SendPingPong(pingBytes);
|
await SendPingPong(pingBytes);
|
||||||
}
|
}
|
||||||
public override async Task<bool> SendAsync(ReadOnlyMemory<byte> data)
|
public override async Task<bool> SendAsync(ReadOnlyMemory<byte> data)
|
||||||
@@ -448,7 +448,7 @@ namespace linker.plugins.messenger
|
|||||||
else
|
else
|
||||||
await SourceSocket.SendAsync(data, cancellationTokenSourceWrite.Token).ConfigureAwait(false);
|
await SourceSocket.SendAsync(data, cancellationTokenSourceWrite.Token).ConfigureAwait(false);
|
||||||
SendBytes += data.Length;
|
SendBytes += data.Length;
|
||||||
ticks = Environment.TickCount64;
|
lastTicks.Update();
|
||||||
}
|
}
|
||||||
catch (OperationCanceledException)
|
catch (OperationCanceledException)
|
||||||
{
|
{
|
||||||
@@ -496,7 +496,7 @@ namespace linker.plugins.messenger
|
|||||||
SourceSocket?.SafeClose();
|
SourceSocket?.SafeClose();
|
||||||
TargetSocket?.SafeClose();
|
TargetSocket?.SafeClose();
|
||||||
|
|
||||||
ticks = 0;
|
lastTicks.Clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -1,15 +1,15 @@
|
|||||||
using linker.plugins.flow;
|
using linker.plugins.flow;
|
||||||
using static System.Reflection.Metadata.BlobBuilder;
|
|
||||||
|
|
||||||
namespace linker.plugins.messenger
|
namespace linker.plugins.messenger
|
||||||
{
|
{
|
||||||
public sealed class MessengerFlow : IFlow
|
public sealed class MessengerFlow : IFlow
|
||||||
{
|
{
|
||||||
public ulong ReceiveBytes { get; private set; }
|
public ulong ReceiveBytes { get; private set; }
|
||||||
public ulong SendtBytes { get; private set; }
|
public ulong SendtBytes { get; private set; }
|
||||||
public string FlowName => "Messenger";
|
public string FlowName => "Messenger";
|
||||||
|
|
||||||
private Dictionary<ushort, FlowItemInfo> flows { get; } = new Dictionary<ushort, FlowItemInfo>();
|
private Dictionary<ushort, FlowItemInfo> flows { get; } = new Dictionary<ushort, FlowItemInfo>();
|
||||||
|
|
||||||
public MessengerFlow()
|
public MessengerFlow()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
@@ -28,6 +28,10 @@ namespace linker.plugins.sforward
|
|||||||
serviceCollection.AddSingleton<SForwardClientApiController>();
|
serviceCollection.AddSingleton<SForwardClientApiController>();
|
||||||
serviceCollection.AddSingleton<SForwardTransfer>();
|
serviceCollection.AddSingleton<SForwardTransfer>();
|
||||||
serviceCollection.AddSingleton<SForwardClientMessenger>();
|
serviceCollection.AddSingleton<SForwardClientMessenger>();
|
||||||
|
|
||||||
|
serviceCollection.AddSingleton<SForwardFlow>();
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void AddServer(ServiceCollection serviceCollection, FileConfig config, Assembly[] assemblies)
|
public void AddServer(ServiceCollection serviceCollection, FileConfig config, Assembly[] assemblies)
|
||||||
@@ -37,6 +41,7 @@ namespace linker.plugins.sforward
|
|||||||
serviceCollection.AddSingleton<ISForwardServerCahing, SForwardServerCahing>();
|
serviceCollection.AddSingleton<ISForwardServerCahing, SForwardServerCahing>();
|
||||||
serviceCollection.AddSingleton<ISForwardValidator, Validator>();
|
serviceCollection.AddSingleton<ISForwardValidator, Validator>();
|
||||||
|
|
||||||
|
serviceCollection.AddSingleton<SForwardFlow>();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool added = false;
|
bool added = false;
|
||||||
|
153
linker/plugins/sforward/proxy/SForwardFlow.cs
Normal file
153
linker/plugins/sforward/proxy/SForwardFlow.cs
Normal file
@@ -0,0 +1,153 @@
|
|||||||
|
using linker.libs;
|
||||||
|
using linker.libs.extends;
|
||||||
|
using linker.plugins.flow;
|
||||||
|
using MemoryPack;
|
||||||
|
using System.Text.Json.Serialization;
|
||||||
|
|
||||||
|
namespace linker.plugins.sforward.proxy
|
||||||
|
{
|
||||||
|
public sealed class SForwardFlow : IFlow
|
||||||
|
{
|
||||||
|
public ulong ReceiveBytes { get; private set; }
|
||||||
|
public ulong SendtBytes { get; private set; }
|
||||||
|
public string FlowName => "SForward";
|
||||||
|
|
||||||
|
private readonly LastTicksManager lastTicksManager = new LastTicksManager();
|
||||||
|
|
||||||
|
private Dictionary<string, SForwardFlowItemInfo> flows { get; } = new Dictionary<string, SForwardFlowItemInfo>();
|
||||||
|
|
||||||
|
public SForwardFlow()
|
||||||
|
{
|
||||||
|
TimerHelper.SetInterval(() =>
|
||||||
|
{
|
||||||
|
if (lastTicksManager.Less(5000))
|
||||||
|
{
|
||||||
|
foreach (var item in flows.Values)
|
||||||
|
{
|
||||||
|
item.DiffReceiveBytes = item.SendtBytes - item.OldSendtBytes;
|
||||||
|
item.DiffSendtBytes = item.ReceiveBytes - item.OldReceiveBytes;
|
||||||
|
|
||||||
|
item.OldSendtBytes = item.SendtBytes;
|
||||||
|
item.OldReceiveBytes = item.ReceiveBytes;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}, 1000);
|
||||||
|
|
||||||
|
AddSendt("snltty", 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void Update()
|
||||||
|
{
|
||||||
|
lastTicksManager.Update();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void AddReceive(string key, ulong bytes)
|
||||||
|
{
|
||||||
|
if (flows.TryGetValue(key, out SForwardFlowItemInfo messengerFlowItemInfo) == false)
|
||||||
|
{
|
||||||
|
messengerFlowItemInfo = new SForwardFlowItemInfo { };
|
||||||
|
flows.TryAdd(key, messengerFlowItemInfo);
|
||||||
|
}
|
||||||
|
ReceiveBytes += bytes;
|
||||||
|
messengerFlowItemInfo.ReceiveBytes += bytes;
|
||||||
|
}
|
||||||
|
public void AddSendt(string key, ulong bytes)
|
||||||
|
{
|
||||||
|
if (flows.TryGetValue(key, out SForwardFlowItemInfo messengerFlowItemInfo) == false)
|
||||||
|
{
|
||||||
|
messengerFlowItemInfo = new SForwardFlowItemInfo { };
|
||||||
|
flows.TryAdd(key, messengerFlowItemInfo);
|
||||||
|
}
|
||||||
|
SendtBytes += bytes;
|
||||||
|
messengerFlowItemInfo.SendtBytes += bytes;
|
||||||
|
}
|
||||||
|
public SForwardFlowResponseInfo GetFlows(SForwardFlowRequestInfo info)
|
||||||
|
{
|
||||||
|
var items = flows.Where(c => string.IsNullOrWhiteSpace(info.Key) || c.Key.Contains(info.Key));
|
||||||
|
switch (info.Order)
|
||||||
|
{
|
||||||
|
case SForwardFlowOrder.Sendt:
|
||||||
|
if (info.OrderType == SForwardFlowOrderType.Desc)
|
||||||
|
items = items.OrderByDescending(x => x.Value.SendtBytes);
|
||||||
|
else
|
||||||
|
items = items.OrderBy(x => x.Value.SendtBytes);
|
||||||
|
break;
|
||||||
|
case SForwardFlowOrder.DiffSendt:
|
||||||
|
if (info.OrderType == SForwardFlowOrderType.Desc)
|
||||||
|
items = items.OrderByDescending(x => x.Value.DiffSendtBytes);
|
||||||
|
else
|
||||||
|
items = items.OrderBy(x => x.Value.DiffSendtBytes);
|
||||||
|
break;
|
||||||
|
case SForwardFlowOrder.Receive:
|
||||||
|
if (info.OrderType == SForwardFlowOrderType.Desc)
|
||||||
|
items = items.OrderByDescending(x => x.Value.ReceiveBytes);
|
||||||
|
else
|
||||||
|
items = items.OrderBy(x => x.Value.ReceiveBytes);
|
||||||
|
break;
|
||||||
|
case SForwardFlowOrder.DiffRecive:
|
||||||
|
if (info.OrderType == SForwardFlowOrderType.Desc)
|
||||||
|
items = items.OrderByDescending(x => x.Value.DiffReceiveBytes);
|
||||||
|
else
|
||||||
|
items = items.OrderBy(x => x.Value.DiffReceiveBytes);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
SForwardFlowResponseInfo resp = new SForwardFlowResponseInfo
|
||||||
|
{
|
||||||
|
Page = info.Page,
|
||||||
|
PageSize = info.PageSize,
|
||||||
|
Count = flows.Count,
|
||||||
|
Data = items.Skip((info.Page - 1) * info.PageSize).Take(info.PageSize).ToDictionary()
|
||||||
|
};
|
||||||
|
|
||||||
|
return resp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[MemoryPackable]
|
||||||
|
public sealed partial class SForwardFlowItemInfo : FlowItemInfo
|
||||||
|
{
|
||||||
|
public ulong DiffReceiveBytes { get; set; }
|
||||||
|
public ulong DiffSendtBytes { get; set; }
|
||||||
|
|
||||||
|
[MemoryPackIgnore, JsonIgnore]
|
||||||
|
public ulong OldReceiveBytes { get; set; }
|
||||||
|
[MemoryPackIgnore, JsonIgnore]
|
||||||
|
public ulong OldSendtBytes { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
[MemoryPackable]
|
||||||
|
public sealed partial class SForwardFlowRequestInfo
|
||||||
|
{
|
||||||
|
public string Key { get; set; } = string.Empty;
|
||||||
|
public int Page { get; set; } = 1;
|
||||||
|
public int PageSize { get; set; } = 15;
|
||||||
|
public SForwardFlowOrder Order { get; set; }
|
||||||
|
public SForwardFlowOrderType OrderType { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum SForwardFlowOrder : byte
|
||||||
|
{
|
||||||
|
Sendt = 1,
|
||||||
|
DiffSendt = 2,
|
||||||
|
Receive = 3,
|
||||||
|
DiffRecive = 4
|
||||||
|
}
|
||||||
|
public enum SForwardFlowOrderType : byte
|
||||||
|
{
|
||||||
|
Desc = 0,
|
||||||
|
Asc = 1,
|
||||||
|
}
|
||||||
|
|
||||||
|
[MemoryPackable]
|
||||||
|
public sealed partial class SForwardFlowResponseInfo
|
||||||
|
{
|
||||||
|
public int Page { get; set; }
|
||||||
|
public int PageSize { get; set; }
|
||||||
|
public int Count { get; set; }
|
||||||
|
public Dictionary<string,SForwardFlowItemInfo> Data { get; set; }
|
||||||
|
}
|
||||||
|
}
|
@@ -4,19 +4,18 @@ using System.Text;
|
|||||||
|
|
||||||
namespace linker.plugins.sforward.proxy
|
namespace linker.plugins.sforward.proxy
|
||||||
{
|
{
|
||||||
public partial class SForwardProxy : IFlow
|
public partial class SForwardProxy
|
||||||
{
|
{
|
||||||
public ulong ReceiveBytes { get; private set; }
|
|
||||||
public ulong SendtBytes { get; private set; }
|
|
||||||
public string FlowName => "SForward";
|
|
||||||
|
|
||||||
|
|
||||||
private readonly NumberSpace ns = new NumberSpace();
|
private readonly NumberSpace ns = new NumberSpace();
|
||||||
private byte[] flagBytes = Encoding.UTF8.GetBytes($"snltty.sforward");
|
private byte[] flagBytes = Encoding.UTF8.GetBytes($"snltty.sforward");
|
||||||
|
|
||||||
public SForwardProxy()
|
private readonly SForwardFlow sForwardFlow;
|
||||||
|
public SForwardProxy(SForwardFlow sForwardFlow)
|
||||||
{
|
{
|
||||||
|
this.sForwardFlow = sForwardFlow;
|
||||||
UdpTask();
|
UdpTask();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public string Start(int port, bool isweb, byte bufferSize)
|
public string Start(int port, bool isweb, byte bufferSize)
|
||||||
|
@@ -18,7 +18,7 @@ namespace linker.plugins.sforward.proxy
|
|||||||
|
|
||||||
#region 服务端
|
#region 服务端
|
||||||
|
|
||||||
|
|
||||||
private void StartTcp(int port, bool isweb, byte bufferSize)
|
private void StartTcp(int port, bool isweb, byte bufferSize)
|
||||||
{
|
{
|
||||||
IPEndPoint localEndPoint = new IPEndPoint(IPAddress.Any, port);
|
IPEndPoint localEndPoint = new IPEndPoint(IPAddress.Any, port);
|
||||||
@@ -154,7 +154,7 @@ namespace linker.plugins.sforward.proxy
|
|||||||
await token.TargetSocket.SendAsync(buffer1.AsMemory(0, length)).ConfigureAwait(false);
|
await token.TargetSocket.SendAsync(buffer1.AsMemory(0, length)).ConfigureAwait(false);
|
||||||
|
|
||||||
//两端交换数据
|
//两端交换数据
|
||||||
await Task.WhenAll(CopyToAsync(buffer1, token.SourceSocket, token.TargetSocket), CopyToAsync(buffer2, token.TargetSocket, token.SourceSocket)).ConfigureAwait(false);
|
await Task.WhenAll(CopyToAsync(token.Host, token.ListenPort, buffer1, token.SourceSocket, token.TargetSocket), CopyToAsync(token.Host, token.ListenPort, buffer2, token.TargetSocket, token.SourceSocket)).ConfigureAwait(false);
|
||||||
|
|
||||||
CloseClientSocket(token);
|
CloseClientSocket(token);
|
||||||
}
|
}
|
||||||
@@ -248,7 +248,7 @@ namespace linker.plugins.sforward.proxy
|
|||||||
await sourceSocket.SendAsync(buffer1.AsMemory(0, flagBytes.Length + 8)).ConfigureAwait(false);
|
await sourceSocket.SendAsync(buffer1.AsMemory(0, flagBytes.Length + 8)).ConfigureAwait(false);
|
||||||
|
|
||||||
//交换数据即可
|
//交换数据即可
|
||||||
await Task.WhenAll(CopyToAsync(buffer1, sourceSocket, targetSocket), CopyToAsync(buffer2, targetSocket, sourceSocket)).ConfigureAwait(false);
|
await Task.WhenAll(CopyToAsync(string.Empty, service.Port, buffer1, sourceSocket, targetSocket), CopyToAsync(string.Empty, service.Port, buffer2, targetSocket, sourceSocket)).ConfigureAwait(false);
|
||||||
|
|
||||||
}
|
}
|
||||||
catch (Exception)
|
catch (Exception)
|
||||||
@@ -265,20 +265,32 @@ namespace linker.plugins.sforward.proxy
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 读取数据,然后发送给对方,用户两端交换数据
|
/// 读取数据,然后发送给对方,用户两端交换数据
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
/// <param name="domain"></param>
|
||||||
|
/// <param name="port"></param>
|
||||||
/// <param name="buffer"></param>
|
/// <param name="buffer"></param>
|
||||||
/// <param name="source"></param>
|
/// <param name="source"></param>
|
||||||
/// <param name="target"></param>
|
/// <param name="target"></param>
|
||||||
/// <param name="receive"></param>
|
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
private async Task CopyToAsync(Memory<byte> buffer, Socket source, Socket target)
|
private async Task CopyToAsync(string domain, int port, Memory<byte> buffer, Socket source, Socket target)
|
||||||
{
|
{
|
||||||
|
bool isDomain = string.IsNullOrWhiteSpace(domain) == false;
|
||||||
|
string portStr = port.ToString();
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
int bytesRead;
|
int bytesRead;
|
||||||
while ((bytesRead = await source.ReceiveAsync(buffer, SocketFlags.None).ConfigureAwait(false)) != 0)
|
while ((bytesRead = await source.ReceiveAsync(buffer, SocketFlags.None).ConfigureAwait(false)) != 0)
|
||||||
{
|
{
|
||||||
ReceiveBytes += (ulong)bytesRead;
|
if (isDomain)
|
||||||
SendtBytes += (ulong)bytesRead;
|
{
|
||||||
|
sForwardFlow.AddReceive(domain, (ulong)bytesRead);
|
||||||
|
sForwardFlow.AddSendt(domain, (ulong)bytesRead);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
sForwardFlow.AddReceive(portStr, (ulong)bytesRead);
|
||||||
|
sForwardFlow.AddSendt(portStr, (ulong)bytesRead);
|
||||||
|
}
|
||||||
await target.SendAsync(buffer.Slice(0, bytesRead), SocketFlags.None).ConfigureAwait(false);
|
await target.SendAsync(buffer.Slice(0, bytesRead), SocketFlags.None).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -296,7 +308,7 @@ namespace linker.plugins.sforward.proxy
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public sealed class AsyncUserToken
|
public sealed class AsyncUserToken
|
||||||
|
@@ -40,6 +40,9 @@ namespace linker.plugins.sforward.proxy
|
|||||||
{
|
{
|
||||||
byte[] buffer = new byte[(1 << bufferSize) * 1024];
|
byte[] buffer = new byte[(1 << bufferSize) * 1024];
|
||||||
IPEndPoint tempRemoteEP = new IPEndPoint(IPAddress.Any, IPEndPoint.MinPort);
|
IPEndPoint tempRemoteEP = new IPEndPoint(IPAddress.Any, IPEndPoint.MinPort);
|
||||||
|
|
||||||
|
string portStr = token.ListenPort.ToString();
|
||||||
|
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
SocketReceiveFromResult result = await token.SourceSocket.ReceiveFromAsync(buffer, tempRemoteEP).ConfigureAwait(false);
|
SocketReceiveFromResult result = await token.SourceSocket.ReceiveFromAsync(buffer, tempRemoteEP).ConfigureAwait(false);
|
||||||
@@ -49,14 +52,15 @@ namespace linker.plugins.sforward.proxy
|
|||||||
}
|
}
|
||||||
|
|
||||||
Memory<byte> memory = buffer.AsMemory(0, result.ReceivedBytes);
|
Memory<byte> memory = buffer.AsMemory(0, result.ReceivedBytes);
|
||||||
ReceiveBytes += (ulong)memory.Length;
|
|
||||||
|
sForwardFlow.AddReceive(portStr, (ulong)memory.Length);
|
||||||
|
|
||||||
IPEndPoint source = result.RemoteEndPoint as IPEndPoint;
|
IPEndPoint source = result.RemoteEndPoint as IPEndPoint;
|
||||||
//已经连接
|
//已经连接
|
||||||
if (udpConnections.TryGetValue(source, out UdpTargetCache cache) && cache != null)
|
if (udpConnections.TryGetValue(source, out UdpTargetCache cache) && cache != null)
|
||||||
{
|
{
|
||||||
SendtBytes += (ulong)memory.Length;
|
sForwardFlow.AddSendt(portStr, (ulong)memory.Length);
|
||||||
cache.Update();
|
cache.LastTicks.Update();
|
||||||
await token.SourceSocket.SendToAsync(memory, cache.IPEndPoint).ConfigureAwait(false);
|
await token.SourceSocket.SendToAsync(memory, cache.IPEndPoint).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -171,6 +175,8 @@ namespace linker.plugins.sforward.proxy
|
|||||||
IPEndPoint tempEp = new IPEndPoint(IPAddress.Any, IPEndPoint.MinPort);
|
IPEndPoint tempEp = new IPEndPoint(IPAddress.Any, IPEndPoint.MinPort);
|
||||||
|
|
||||||
UdpConnectedCache cache = new UdpConnectedCache { SourceSocket = socketUdp, TargetSocket = serviceUdp };
|
UdpConnectedCache cache = new UdpConnectedCache { SourceSocket = socketUdp, TargetSocket = serviceUdp };
|
||||||
|
|
||||||
|
string portStr = service.Port.ToString();
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
@@ -183,11 +189,12 @@ namespace linker.plugins.sforward.proxy
|
|||||||
socketUdp?.Dispose();
|
socketUdp?.Dispose();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
cache.Update();
|
cache.LastTicks.Update();
|
||||||
|
|
||||||
Memory<byte> memory = buffer.AsMemory(0, result.ReceivedBytes);
|
Memory<byte> memory = buffer.AsMemory(0, result.ReceivedBytes);
|
||||||
ReceiveBytes += (ulong)memory.Length;
|
|
||||||
SendtBytes += (ulong)memory.Length;
|
sForwardFlow.AddReceive(portStr, (ulong)memory.Length);
|
||||||
|
sForwardFlow.AddSendt(portStr, (ulong)memory.Length);
|
||||||
|
|
||||||
if (serviceUdp == null)
|
if (serviceUdp == null)
|
||||||
{
|
{
|
||||||
@@ -215,11 +222,11 @@ namespace linker.plugins.sforward.proxy
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
Memory<byte> memory = buffer.AsMemory(0, result.ReceivedBytes);
|
Memory<byte> memory = buffer.AsMemory(0, result.ReceivedBytes);
|
||||||
ReceiveBytes += (ulong)memory.Length;
|
sForwardFlow.AddReceive(portStr, (ulong)memory.Length);
|
||||||
SendtBytes += (ulong)memory.Length;
|
sForwardFlow.AddSendt(portStr, (ulong)memory.Length);
|
||||||
|
|
||||||
await socketUdp.SendToAsync(memory, server).ConfigureAwait(false);
|
await socketUdp.SendToAsync(memory, server).ConfigureAwait(false);
|
||||||
cache.Update();
|
cache.LastTicks.Update();
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
@@ -284,24 +291,16 @@ namespace linker.plugins.sforward.proxy
|
|||||||
public sealed class UdpTargetCache
|
public sealed class UdpTargetCache
|
||||||
{
|
{
|
||||||
public IPEndPoint IPEndPoint { get; set; }
|
public IPEndPoint IPEndPoint { get; set; }
|
||||||
public long LastTime { get; set; } = Environment.TickCount64;
|
public LastTicksManager LastTicks { get; set; } = new LastTicksManager();
|
||||||
public void Update()
|
public bool Timeout => LastTicks.Greater(5 * 60 * 1000);
|
||||||
{
|
|
||||||
LastTime = Environment.TickCount64;
|
|
||||||
}
|
|
||||||
public bool Timeout => Environment.TickCount64 - LastTime > 5 * 60 * 1000;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public sealed class UdpConnectedCache
|
public sealed class UdpConnectedCache
|
||||||
{
|
{
|
||||||
public Socket SourceSocket { get; set; }
|
public Socket SourceSocket { get; set; }
|
||||||
public Socket TargetSocket { get; set; }
|
public Socket TargetSocket { get; set; }
|
||||||
public long LastTime { get; set; } = Environment.TickCount64;
|
public LastTicksManager LastTicks { get; set; } = new LastTicksManager();
|
||||||
public void Update()
|
public bool Timeout => LastTicks.Greater(5 * 60 * 1000);
|
||||||
{
|
|
||||||
LastTime = Environment.TickCount64;
|
|
||||||
}
|
|
||||||
public bool Timeout => Environment.TickCount64 - LastTime > 5 * 60 * 1000;
|
|
||||||
|
|
||||||
public void Clear()
|
public void Clear()
|
||||||
{
|
{
|
||||||
|
@@ -180,23 +180,6 @@ namespace linker.plugins.tunnel
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public async Task<ConcurrentDictionary<string, TunnelRecordInfo>> Records(ApiControllerParamsInfo param)
|
|
||||||
{
|
|
||||||
MessageResponeInfo resp = await messengerSender.SendReply(new MessageRequestWrap
|
|
||||||
{
|
|
||||||
Connection = clientSignInState.Connection,
|
|
||||||
MessengerId = (ushort)TunnelMessengerIds.Records
|
|
||||||
}).ConfigureAwait(false);
|
|
||||||
|
|
||||||
if(resp.Code == MessageResponeCodes.OK)
|
|
||||||
{
|
|
||||||
return MemoryPackSerializer.Deserialize<ConcurrentDictionary<string, TunnelRecordInfo>>(resp.Data.Span);
|
|
||||||
}
|
|
||||||
|
|
||||||
return new ConcurrentDictionary<string, TunnelRecordInfo>();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -156,22 +156,6 @@ namespace linker.plugins.tunnel.messenger
|
|||||||
tunnelTransportInfo.Local.MachineName = cacheFrom.MachineName;
|
tunnelTransportInfo.Local.MachineName = cacheFrom.MachineName;
|
||||||
tunnelTransportInfo.Remote.MachineName = cacheTo.MachineName;
|
tunnelTransportInfo.Remote.MachineName = cacheTo.MachineName;
|
||||||
|
|
||||||
/*
|
|
||||||
TunnelRecordInfo tunnelRecordInfo = new TunnelRecordInfo
|
|
||||||
{
|
|
||||||
MachineName = cacheFrom.MachineName,
|
|
||||||
Times = 1
|
|
||||||
};
|
|
||||||
records.AddOrUpdate(cacheFrom.MachineName, tunnelRecordInfo, (a, b) =>
|
|
||||||
{
|
|
||||||
TunnelRecordItemInfo item = new TunnelRecordItemInfo { MachineName = cacheTo.MachineName, Times = 1 };
|
|
||||||
b.To.AddOrUpdate(cacheTo.MachineId, item, (a, b) => { b.Times++; return b; });
|
|
||||||
|
|
||||||
b.Times++;
|
|
||||||
return b;
|
|
||||||
});
|
|
||||||
*/
|
|
||||||
|
|
||||||
await messengerSender.SendOnly(new MessageRequestWrap
|
await messengerSender.SendOnly(new MessageRequestWrap
|
||||||
{
|
{
|
||||||
Connection = cacheTo.Connection,
|
Connection = cacheTo.Connection,
|
||||||
@@ -269,13 +253,6 @@ namespace linker.plugins.tunnel.messenger
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
[MessengerId((ushort)TunnelMessengerIds.Records)]
|
|
||||||
public void Records(IConnection connection)
|
|
||||||
{
|
|
||||||
connection.Write(MemoryPackSerializer.Serialize(records));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[MemoryPackable]
|
[MemoryPackable]
|
||||||
|
@@ -22,8 +22,6 @@
|
|||||||
RouteLevel = 2011,
|
RouteLevel = 2011,
|
||||||
RouteLevelForward = 2012,
|
RouteLevelForward = 2012,
|
||||||
|
|
||||||
Records = 2013,
|
|
||||||
|
|
||||||
None = 2099
|
None = 2099
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -202,6 +202,11 @@ namespace linker.plugins.tuntap
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void SubscribePing(ApiControllerParamsInfo param)
|
||||||
|
{
|
||||||
|
tuntapTransfer.SubscribePing();
|
||||||
|
}
|
||||||
|
|
||||||
public sealed class RouteItemListInfo
|
public sealed class RouteItemListInfo
|
||||||
{
|
{
|
||||||
public object[] List { get; set; }
|
public object[] List { get; set; }
|
||||||
|
@@ -190,6 +190,9 @@ namespace linker.plugins.tuntap
|
|||||||
TimerHelper.Async(() =>
|
TimerHelper.Async(() =>
|
||||||
{
|
{
|
||||||
DeleteForward();
|
DeleteForward();
|
||||||
|
|
||||||
|
bool needReboot = info.IP.Equals(runningConfig.Data.Tuntap.IP) == false || info.PrefixLength != runningConfig.Data.Tuntap.PrefixLength;
|
||||||
|
|
||||||
runningConfig.Data.Tuntap.IP = info.IP;
|
runningConfig.Data.Tuntap.IP = info.IP;
|
||||||
runningConfig.Data.Tuntap.LanIPs = info.LanIPs;
|
runningConfig.Data.Tuntap.LanIPs = info.LanIPs;
|
||||||
runningConfig.Data.Tuntap.Masks = info.Masks;
|
runningConfig.Data.Tuntap.Masks = info.Masks;
|
||||||
@@ -197,7 +200,7 @@ namespace linker.plugins.tuntap
|
|||||||
runningConfig.Data.Tuntap.Switch = info.Switch;
|
runningConfig.Data.Tuntap.Switch = info.Switch;
|
||||||
runningConfig.Data.Tuntap.Forwards = info.Forwards;
|
runningConfig.Data.Tuntap.Forwards = info.Forwards;
|
||||||
runningConfig.Data.Update();
|
runningConfig.Data.Update();
|
||||||
if (Status == TuntapStatus.Running)
|
if (Status == TuntapStatus.Running && needReboot)
|
||||||
{
|
{
|
||||||
Shutdown();
|
Shutdown();
|
||||||
Setup();
|
Setup();
|
||||||
@@ -254,7 +257,7 @@ namespace linker.plugins.tuntap
|
|||||||
foreach (var item in list)
|
foreach (var item in list)
|
||||||
{
|
{
|
||||||
tuntapInfos.AddOrUpdate(item.MachineId, item, (a, b) => item);
|
tuntapInfos.AddOrUpdate(item.MachineId, item, (a, b) => item);
|
||||||
item.LastTicks = Environment.TickCount64;
|
item.LastTicks.Update();
|
||||||
}
|
}
|
||||||
var removes = tuntapInfos.Keys.Except(list.Select(c => c.MachineId)).ToList();
|
var removes = tuntapInfos.Keys.Except(list.Select(c => c.MachineId)).ToList();
|
||||||
foreach (var item in removes)
|
foreach (var item in removes)
|
||||||
@@ -262,7 +265,7 @@ namespace linker.plugins.tuntap
|
|||||||
if (tuntapInfos.TryGetValue(item, out TuntapInfo tuntapInfo))
|
if (tuntapInfos.TryGetValue(item, out TuntapInfo tuntapInfo))
|
||||||
{
|
{
|
||||||
tuntapInfo.Status = TuntapStatus.Normal;
|
tuntapInfo.Status = TuntapStatus.Normal;
|
||||||
tuntapInfo.LastTicks = 0;
|
tuntapInfo.LastTicks.Clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Version.Add();
|
Version.Add();
|
||||||
@@ -428,7 +431,7 @@ namespace linker.plugins.tuntap
|
|||||||
|
|
||||||
return infos
|
return infos
|
||||||
//自己的ip不要
|
//自己的ip不要
|
||||||
.Where(c => c.IP.Equals(runningConfig.Data.Tuntap.IP) == false && c.LastTicks > 0)
|
.Where(c => c.IP.Equals(runningConfig.Data.Tuntap.IP) == false && c.LastTicks.Greater(0))
|
||||||
.OrderBy(c => c.LastTicks)
|
.OrderBy(c => c.LastTicks)
|
||||||
.Select(c =>
|
.Select(c =>
|
||||||
{
|
{
|
||||||
@@ -511,30 +514,51 @@ namespace linker.plugins.tuntap
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
private readonly LastTicksManager lastTicksManager = new LastTicksManager();
|
||||||
|
public void SubscribePing()
|
||||||
|
{
|
||||||
|
lastTicksManager.Update();
|
||||||
|
}
|
||||||
private void PingTask()
|
private void PingTask()
|
||||||
{
|
{
|
||||||
TimerHelper.SetInterval(async () =>
|
TimerHelper.SetInterval(async () =>
|
||||||
{
|
{
|
||||||
if (Status == TuntapStatus.Running && (runningConfig.Data.Tuntap.Switch & TuntapSwitch.ShowDelay) == TuntapSwitch.ShowDelay)
|
if (lastTicksManager.Less(5000))
|
||||||
{
|
{
|
||||||
var items = tuntapInfos.Values.Where(c => c.IP != null && c.IP.Equals(IPAddress.Any) == false && (c.Status & TuntapStatus.Running) == TuntapStatus.Running);
|
await Ping();
|
||||||
if ((runningConfig.Data.Tuntap.Switch & TuntapSwitch.AutoConnect) != TuntapSwitch.AutoConnect)
|
|
||||||
{
|
|
||||||
var connections = tuntapProxy.GetConnections();
|
|
||||||
items = items.Where(c => (connections.TryGetValue(c.MachineId, out ITunnelConnection connection) && connection.Connected) || c.MachineId == config.Data.Client.Id);
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (var item in items)
|
|
||||||
{
|
|
||||||
using Ping ping = new Ping();
|
|
||||||
PingReply pingReply = await ping.SendPingAsync(item.IP, 500);
|
|
||||||
item.Delay = pingReply.Status == IPStatus.Success ? (int)pingReply.RoundtripTime : -1;
|
|
||||||
|
|
||||||
Version.Add();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}, 3000);
|
}, 3000);
|
||||||
|
TimerHelper.SetInterval(async () =>
|
||||||
|
{
|
||||||
|
if (lastTicksManager.Greater(15000))
|
||||||
|
{
|
||||||
|
await Ping();
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}, 30000);
|
||||||
|
}
|
||||||
|
private async Task Ping()
|
||||||
|
{
|
||||||
|
if (Status == TuntapStatus.Running && (runningConfig.Data.Tuntap.Switch & TuntapSwitch.ShowDelay) == TuntapSwitch.ShowDelay)
|
||||||
|
{
|
||||||
|
var items = tuntapInfos.Values.Where(c => c.IP != null && c.IP.Equals(IPAddress.Any) == false && (c.Status & TuntapStatus.Running) == TuntapStatus.Running);
|
||||||
|
if ((runningConfig.Data.Tuntap.Switch & TuntapSwitch.AutoConnect) != TuntapSwitch.AutoConnect)
|
||||||
|
{
|
||||||
|
var connections = tuntapProxy.GetConnections();
|
||||||
|
items = items.Where(c => (connections.TryGetValue(c.MachineId, out ITunnelConnection connection) && connection.Connected) || c.MachineId == config.Data.Client.Id);
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var item in items)
|
||||||
|
{
|
||||||
|
using Ping ping = new Ping();
|
||||||
|
PingReply pingReply = await ping.SendPingAsync(item.IP, 500);
|
||||||
|
item.Delay = pingReply.Status == IPStatus.Success ? (int)pingReply.RoundtripTime : -1;
|
||||||
|
|
||||||
|
Version.Add();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,4 +1,5 @@
|
|||||||
using linker.plugins.tuntap.config;
|
using linker.libs;
|
||||||
|
using linker.plugins.tuntap.config;
|
||||||
using MemoryPack;
|
using MemoryPack;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
|
|
||||||
@@ -149,7 +150,7 @@ namespace linker.plugins.tuntap.config
|
|||||||
public TuntapSwitch Switch { get; set; }
|
public TuntapSwitch Switch { get; set; }
|
||||||
|
|
||||||
[MemoryPackIgnore]
|
[MemoryPackIgnore]
|
||||||
public long LastTicks { get; set; } = Environment.TickCount64;
|
public LastTicksManager LastTicks { get; set; } = new LastTicksManager();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 延迟ms
|
/// 延迟ms
|
||||||
@@ -246,6 +247,29 @@ namespace linker.plugins.tuntap.config
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 使用广播
|
||||||
|
/// </summary>
|
||||||
|
[MemoryPackIgnore]
|
||||||
|
public bool Multicast
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return (Switch & TuntapSwitch.Multicast) == TuntapSwitch.Multicast;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (value)
|
||||||
|
{
|
||||||
|
Switch |= TuntapSwitch.Multicast;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Switch &= ~TuntapSwitch.Multicast;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[Flags]
|
[Flags]
|
||||||
@@ -255,6 +279,7 @@ namespace linker.plugins.tuntap.config
|
|||||||
ShowDelay = 2,
|
ShowDelay = 2,
|
||||||
Upgrade = 4,
|
Upgrade = 4,
|
||||||
AutoConnect = 8,
|
AutoConnect = 8,
|
||||||
|
Multicast = 16,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@@ -41,15 +41,6 @@ namespace linker.plugins.updater
|
|||||||
updaterTransfer.SetSecretKey(param.Content);
|
updaterTransfer.SetSecretKey(param.Content);
|
||||||
}
|
}
|
||||||
|
|
||||||
public UpdateInfo GetCurrent(ApiControllerParamsInfo param)
|
|
||||||
{
|
|
||||||
var updaters = updaterTransfer.Get();
|
|
||||||
if (updaters.TryGetValue(config.Data.Client.Id, out UpdateInfo info))
|
|
||||||
{
|
|
||||||
return info;
|
|
||||||
}
|
|
||||||
return new UpdateInfo { };
|
|
||||||
}
|
|
||||||
public async Task<UpdateInfo> GetServer(ApiControllerParamsInfo param)
|
public async Task<UpdateInfo> GetServer(ApiControllerParamsInfo param)
|
||||||
{
|
{
|
||||||
MessageResponeInfo resp = await messengerSender.SendReply(new MessageRequestWrap
|
MessageResponeInfo resp = await messengerSender.SendReply(new MessageRequestWrap
|
||||||
@@ -85,7 +76,15 @@ namespace linker.plugins.updater
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public UpdateInfo GetCurrent(ApiControllerParamsInfo param)
|
||||||
|
{
|
||||||
|
var updaters = updaterTransfer.Get();
|
||||||
|
if (updaters.TryGetValue(config.Data.Client.Id, out UpdateInfo info))
|
||||||
|
{
|
||||||
|
return info;
|
||||||
|
}
|
||||||
|
return new UpdateInfo { };
|
||||||
|
}
|
||||||
public UpdaterListInfo Get(ApiControllerParamsInfo param)
|
public UpdaterListInfo Get(ApiControllerParamsInfo param)
|
||||||
{
|
{
|
||||||
ulong hashCode = ulong.Parse(param.Content);
|
ulong hashCode = ulong.Parse(param.Content);
|
||||||
@@ -144,6 +143,16 @@ namespace linker.plugins.updater
|
|||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public async Task Subscribe(ApiControllerParamsInfo param)
|
||||||
|
{
|
||||||
|
await messengerSender.SendOnly(new MessageRequestWrap
|
||||||
|
{
|
||||||
|
Connection = clientSignInState.Connection,
|
||||||
|
MessengerId = (ushort)UpdaterMessengerIds.SubscribeForward
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public sealed class UpdaterListInfo
|
public sealed class UpdaterListInfo
|
||||||
|
@@ -13,6 +13,7 @@ namespace linker.plugins.updater
|
|||||||
{
|
{
|
||||||
private UpdateInfo updateInfo = new UpdateInfo();
|
private UpdateInfo updateInfo = new UpdateInfo();
|
||||||
private ConcurrentDictionary<string, UpdateInfo> updateInfos = new ConcurrentDictionary<string, UpdateInfo>();
|
private ConcurrentDictionary<string, UpdateInfo> updateInfos = new ConcurrentDictionary<string, UpdateInfo>();
|
||||||
|
private ConcurrentDictionary<string, LastTicksManager> subscribes = new ConcurrentDictionary<string, LastTicksManager>();
|
||||||
|
|
||||||
private readonly FileConfig fileConfig;
|
private readonly FileConfig fileConfig;
|
||||||
private readonly MessengerSender messengerSender;
|
private readonly MessengerSender messengerSender;
|
||||||
@@ -76,19 +77,43 @@ namespace linker.plugins.updater
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void Subscribe(string machineId)
|
||||||
|
{
|
||||||
|
if (subscribes.TryGetValue(machineId, out LastTicksManager lastTicksManager) == false)
|
||||||
|
{
|
||||||
|
lastTicksManager = new LastTicksManager();
|
||||||
|
subscribes.TryAdd(machineId, lastTicksManager);
|
||||||
|
}
|
||||||
|
|
||||||
|
//距离上次订阅超过一分钟,需要立即更新一次
|
||||||
|
bool needUpdate = lastTicksManager.Greater(60 * 1000);
|
||||||
|
|
||||||
|
lastTicksManager.Update();
|
||||||
|
|
||||||
|
if (needUpdate)
|
||||||
|
{
|
||||||
|
updateInfo.Update();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void UpdateTask()
|
private void UpdateTask()
|
||||||
{
|
{
|
||||||
TimerHelper.SetInterval(async () =>
|
TimerHelper.SetInterval(async () =>
|
||||||
{
|
{
|
||||||
if (updateInfo.Updated)
|
if (updateInfo.Updated)
|
||||||
{
|
{
|
||||||
updateInfo.MachineId = fileConfig.Data.Client.Id;
|
string[] machines = subscribes.Where(c => c.Value.Less(15000)).Select(c => c.Key).ToArray();
|
||||||
await messengerSender.SendOnly(new MessageRequestWrap
|
if (machines.Length > 0)
|
||||||
{
|
{
|
||||||
Connection = clientSignInState.Connection,
|
updateInfo.MachineId = fileConfig.Data.Client.Id;
|
||||||
MessengerId = (ushort)UpdaterMessengerIds.UpdateForward,
|
await messengerSender.SendOnly(new MessageRequestWrap
|
||||||
Payload = MemoryPackSerializer.Serialize(updateInfo),
|
{
|
||||||
});
|
Connection = clientSignInState.Connection,
|
||||||
|
MessengerId = (ushort)UpdaterMessengerIds.UpdateForward,
|
||||||
|
Payload = MemoryPackSerializer.Serialize(new UpdateClientInfo { ToMachines = machines, Info = updateInfo }),
|
||||||
|
});
|
||||||
|
}
|
||||||
Update(updateInfo);
|
Update(updateInfo);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
@@ -105,5 +130,11 @@ namespace linker.plugins.updater
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[MemoryPackable]
|
||||||
|
public sealed partial class UpdateClientInfo
|
||||||
|
{
|
||||||
|
public string[] ToMachines { get; set; }
|
||||||
|
public UpdateInfo Info { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -44,6 +44,14 @@ namespace linker.plugins.updater.messenger
|
|||||||
{
|
{
|
||||||
Environment.Exit(1);
|
Environment.Exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
[MessengerId((ushort)UpdaterMessengerIds.Subscribe)]
|
||||||
|
public void Subscribe(IConnection connection)
|
||||||
|
{
|
||||||
|
string machineId = MemoryPackSerializer.Deserialize<string>(connection.ReceiveRequestWrap.Payload.Span);
|
||||||
|
updaterTransfer.Subscribe(machineId);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -144,16 +152,17 @@ namespace linker.plugins.updater.messenger
|
|||||||
[MessengerId((ushort)UpdaterMessengerIds.UpdateForward)]
|
[MessengerId((ushort)UpdaterMessengerIds.UpdateForward)]
|
||||||
public void UpdateForward(IConnection connection)
|
public void UpdateForward(IConnection connection)
|
||||||
{
|
{
|
||||||
UpdateInfo info = MemoryPackSerializer.Deserialize<UpdateInfo>(connection.ReceiveRequestWrap.Payload.Span);
|
UpdateClientInfo info = MemoryPackSerializer.Deserialize<UpdateClientInfo>(connection.ReceiveRequestWrap.Payload.Span);
|
||||||
if (signCaching.TryGet(connection.Id, out SignCacheInfo cache))
|
if (signCaching.TryGet(connection.Id, out SignCacheInfo cache))
|
||||||
{
|
{
|
||||||
foreach (var item in signCaching.Get(cache.GroupId).Where(c => c.Connected && c.MachineId != connection.Id))
|
byte[] payload = MemoryPackSerializer.Serialize(info.Info);
|
||||||
|
foreach (var item in signCaching.Get(cache.GroupId).Where(c => info.ToMachines.Contains(c.MachineId)).Where(c => c.Connected && c.MachineId != connection.Id))
|
||||||
{
|
{
|
||||||
_ = messengerSender.SendOnly(new MessageRequestWrap
|
_ = messengerSender.SendOnly(new MessageRequestWrap
|
||||||
{
|
{
|
||||||
Connection = item.Connection,
|
Connection = item.Connection,
|
||||||
MessengerId = (ushort)UpdaterMessengerIds.Update,
|
MessengerId = (ushort)UpdaterMessengerIds.Update,
|
||||||
Payload = connection.ReceiveRequestWrap.Payload
|
Payload = payload
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -177,5 +186,30 @@ namespace linker.plugins.updater.messenger
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 订阅更新信息
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="connection"></param>
|
||||||
|
[MessengerId((ushort)UpdaterMessengerIds.SubscribeForward)]
|
||||||
|
public void SubscribeForward(IConnection connection)
|
||||||
|
{
|
||||||
|
if (signCaching.TryGet(connection.Id, out SignCacheInfo cache))
|
||||||
|
{
|
||||||
|
byte[] mechineId = MemoryPackSerializer.Serialize(connection.Id);
|
||||||
|
foreach (var item in signCaching.Get(cache.GroupId).Where(c => c.Connected && c.MachineId != connection.Id))
|
||||||
|
{
|
||||||
|
_ = messengerSender.SendOnly(new MessageRequestWrap
|
||||||
|
{
|
||||||
|
Connection = item.Connection,
|
||||||
|
MessengerId = (ushort)UpdaterMessengerIds.Subscribe,
|
||||||
|
Payload = mechineId
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -17,6 +17,9 @@
|
|||||||
ConfirmServer = 2608,
|
ConfirmServer = 2608,
|
||||||
ExitServer = 2609,
|
ExitServer = 2609,
|
||||||
|
|
||||||
|
Subscribe = 2610,
|
||||||
|
SubscribeForward = 2611,
|
||||||
|
|
||||||
Max = 2299
|
Max = 2299
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,3 +1,4 @@
|
|||||||
v1.4.4
|
v1.4.4
|
||||||
2024-09-26 23:52:00
|
2024-09-27 17:23:47
|
||||||
1. 增加流量统计(暂时显示服务端流量)
|
1. 总览,和详细流量统计,一眼知道服务器流量花在哪里
|
||||||
|
2. 优化信标。减少流量,没有操作时尽量不产生流量
|
Reference in New Issue
Block a user