重构管理页面代码

This commit is contained in:
snltty
2025-11-16 20:01:56 +08:00
parent 380ed077fb
commit 222bfb9fd0
53 changed files with 816 additions and 924 deletions

View File

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

View File

@@ -22,24 +22,30 @@ namespace linker.libs
{
public ConcurrentDictionary<string, bool> StringKeyValue=> dicOperating;
public VersionManager DataVersion { get; } = new VersionManager();
private readonly ConcurrentDictionary<string, bool> dicOperating = new ConcurrentDictionary<string, bool>();
private readonly ConcurrentDictionary<uint, bool> dicOperating1 = new ConcurrentDictionary<uint, bool>();
public bool StartOperation(string key)
{
DataVersion.Increment();
return dicOperating.TryAdd(key, true);
}
public void StopOperation(string key)
{
DataVersion.Increment();
dicOperating.TryRemove(key, out _);
}
public bool StartOperation(uint key)
{
DataVersion.Increment();
return dicOperating1.TryAdd(key, true);
}
public void StopOperation(uint key)
{
DataVersion.Increment();
dicOperating1.TryRemove(key, out _);
}
}

View File

@@ -1,37 +1,93 @@
using linker.libs;
using linker.libs.extends;
using linker.libs.timer;
using linker.messenger.pcp;
using linker.messenger.relay.client;
using linker.messenger.signin;
using linker.tunnel;
using linker.tunnel.connection;
using System.Collections.Concurrent;
using linker.messenger.relay.client;
using linker.messenger.pcp;
using linker.messenger.signin;
using linker.libs.timer;
using System.Net;
namespace linker.messenger.channel
{
public class Channel
public sealed class ChannelConnectionCaching
{
public VersionManager Version { get; } = new VersionManager();
public ConcurrentDictionary<string, ConcurrentDictionary<string, ITunnelConnection>> Connections { get; } = new();
public ConcurrentDictionary<string, ITunnelConnection> this[string transactionId]
{
get
{
if (Connections.TryGetValue(transactionId, out ConcurrentDictionary<string, ITunnelConnection> _connections) == false)
{
_connections = new ConcurrentDictionary<string, ITunnelConnection>();
Connections.TryAdd(transactionId, _connections);
}
return _connections;
}
}
public bool TryGetValue(string machineId, string transactionId, out ITunnelConnection connection)
{
connection = null;
if (Connections.TryGetValue(transactionId, out ConcurrentDictionary<string, ITunnelConnection> _connections))
{
return _connections.TryGetValue(machineId, out connection);
}
return false;
}
public void Add(ITunnelConnection connection)
{
if (Connections.TryGetValue(connection.TransactionId, out ConcurrentDictionary<string, ITunnelConnection> _connections) == false)
{
_connections = new ConcurrentDictionary<string, ITunnelConnection>();
Connections.TryAdd(connection.TransactionId, _connections);
}
_connections.AddOrUpdate(connection.RemoteMachineId, connection, (a, b) => connection);
Version.Increment();
}
public void Remove(string machineId, string transactionId)
{
if (Connections.TryGetValue(transactionId, out ConcurrentDictionary<string, ITunnelConnection> _connections))
{
if (_connections.TryRemove(machineId, out ITunnelConnection _connection))
{
try
{
_connection.Dispose();
}
catch (Exception)
{
}
Version.Increment();
}
}
}
}
public class Channel
{
public VersionManager Version => channelConnectionCaching.Version;
public ConcurrentDictionary<string, ITunnelConnection> Connections => channelConnectionCaching[TransactionId];
protected virtual string TransactionId { get; }
protected readonly ConcurrentDictionary<string, ITunnelConnection> connections = new ConcurrentDictionary<string, ITunnelConnection>();
private readonly TunnelTransfer tunnelTransfer;
private readonly RelayClientTransfer relayTransfer;
private readonly PcpTransfer pcpTransfer;
private readonly SignInClientTransfer signInClientTransfer;
private readonly ISignInClientStore signInClientStore;
private readonly IRelayClientStore relayClientStore;
private readonly ChannelConnectionCaching channelConnectionCaching;
public Channel(TunnelTransfer tunnelTransfer, RelayClientTransfer relayTransfer, PcpTransfer pcpTransfer, SignInClientTransfer signInClientTransfer, ISignInClientStore signInClientStore, IRelayClientStore relayClientStore)
public Channel(TunnelTransfer tunnelTransfer, RelayClientTransfer relayTransfer, PcpTransfer pcpTransfer,
SignInClientTransfer signInClientTransfer, ISignInClientStore signInClientStore, ChannelConnectionCaching channelConnectionCaching)
{
this.tunnelTransfer = tunnelTransfer;
this.relayTransfer = relayTransfer;
this.pcpTransfer = pcpTransfer;
this.signInClientTransfer = signInClientTransfer;
this.signInClientStore = signInClientStore;
this.relayClientStore = relayClientStore;
this.channelConnectionCaching = channelConnectionCaching;
//监听打洞成功
tunnelTransfer.SetConnectedCallback(TransactionId, OnConnected);
@@ -54,15 +110,11 @@ namespace linker.messenger.channel
if (LoggerHelper.Instance.LoggerLevel <= LoggerTypes.DEBUG)
LoggerHelper.Instance.Warning($"{TransactionId} add connection {connection.GetHashCode()} {connection.ToJson()}");
if (connections.TryGetValue(connection.RemoteMachineId, out ITunnelConnection connectionOld) && connection.Equals(connectionOld) == false)
if (channelConnectionCaching.TryGetValue(connection.RemoteMachineId, TransactionId, out ITunnelConnection connectionOld) && connection.Equals(connectionOld) == false)
{
connections.AddOrUpdate(connection.RemoteMachineId, connection, (a, b) => connection);
TimerHelper.SetTimeout(connectionOld.Dispose, 5000);
}
else
{
connections.AddOrUpdate(connection.RemoteMachineId, connection, (a, b) => connection);
}
channelConnectionCaching.Add(connection);
Version.Increment();
Connected(connection);
@@ -86,7 +138,7 @@ namespace linker.messenger.channel
return null;
}
//之前这个客户端已经连接过
if (connections.TryGetValue(machineId, out ITunnelConnection connection) && connection.Connected)
if (channelConnectionCaching.TryGetValue(machineId, TransactionId, out ITunnelConnection connection) && connection.Connected)
{
return connection;
}
@@ -99,7 +151,7 @@ namespace linker.messenger.channel
}
//获得锁再次看看之前有没有连接成功
if (connections.TryGetValue(machineId, out connection) && connection.Connected)
if (channelConnectionCaching.TryGetValue(machineId, TransactionId, out connection) && connection.Connected)
{
return connection;
}
@@ -113,7 +165,7 @@ namespace linker.messenger.channel
if (connection != null)
{
connections.AddOrUpdate(machineId, connection, (a, b) => connection);
channelConnectionCaching.Add(connection);
}
}
@@ -148,7 +200,7 @@ namespace linker.messenger.channel
//后台打洞
tunnelTransfer.StartBackground(machineId, TransactionId, denyProtocols, () =>
{
return connections.TryGetValue(machineId, out ITunnelConnection connection) && connection.Connected && connection.Type == TunnelType.P2P;
return channelConnectionCaching.TryGetValue(machineId, TransactionId, out ITunnelConnection connection) && connection.Connected && connection.Type == TunnelType.P2P;
}, async (_connection) =>
{
//后台打洞失败pcp
@@ -181,31 +233,5 @@ namespace linker.messenger.channel
return connection;
}
/// <summary>
/// 获取隧道
/// </summary>
/// <returns></returns>
public ConcurrentDictionary<string, ITunnelConnection> GetConnections()
{
return connections;
}
/// <summary>
/// 删除隧道
/// </summary>
/// <param name="machineId"></param>
public void RemoveConnection(string machineId)
{
if (connections.TryRemove(machineId, out ITunnelConnection _connection))
{
try
{
_connection.Dispose();
}
catch (Exception)
{
}
Version.Increment();
}
}
}
}

View File

@@ -0,0 +1,53 @@
using linker.libs.extends;
using System.Collections.Concurrent;
using linker.tunnel.connection;
using linker.messenger.api;
using linker.libs.web;
namespace linker.messenger.channel
{
public sealed class ChannelApiController : IApiController
{
private readonly ChannelConnectionCaching channelConnectionCaching;
public ChannelApiController(ChannelConnectionCaching channelConnectionCaching)
{
this.channelConnectionCaching = channelConnectionCaching;
}
public ConnectionListInfo Get(ApiControllerParamsInfo param)
{
ulong hashCode = ulong.Parse(param.Content);
if (channelConnectionCaching.Version.Eq(hashCode, out ulong version) == false)
{
return new ConnectionListInfo
{
List = channelConnectionCaching.Connections,
HashCode = version
};
}
return new ConnectionListInfo { HashCode = version };
}
[Access(AccessValue.TunnelRemove)]
public void Remove(ApiControllerParamsInfo param)
{
RemoveInfo info = param.Content.DeJson<RemoveInfo>();
channelConnectionCaching.Remove(info.MachineId, info.TransactionId);
}
}
public sealed class RemoveInfo
{
public string MachineId { get; set; }
public string TransactionId { get; set; }
}
public sealed class ConnectionListInfo
{
public ConcurrentDictionary<string, ConcurrentDictionary<string, ITunnelConnection>> List { get; set; }
public ulong HashCode { get; set; }
}
}

View File

@@ -0,0 +1,23 @@
using linker.libs.web;
using Microsoft.Extensions.DependencyInjection;
using System.Text.Json;
namespace linker.messenger.channel
{
public static class Entry
{
public static ServiceCollection AddChannelClient(this ServiceCollection serviceCollection)
{
serviceCollection.AddSingleton<ChannelApiController>();
serviceCollection.AddSingleton<ChannelConnectionCaching>();
return serviceCollection;
}
public static ServiceProvider UseChannelClient(this ServiceProvider serviceProvider, JsonDocument json = default)
{
linker.messenger.api.IWebServer apiServer = serviceProvider.GetService<linker.messenger.api.IWebServer>();
apiServer.AddPlugins(new List<IApiController> { serviceProvider.GetService<ChannelApiController>() });
return serviceProvider;
}
}
}

View File

@@ -23,6 +23,7 @@ using System.Text.Json;
using linker.messenger.firewall;
using linker.messenger.wakeup;
using linker.messenger.wlist;
using linker.messenger.channel;
namespace linker.messenger.entry
{
@@ -68,7 +69,7 @@ namespace linker.messenger.entry
.AddPcpClient().AddPcpServer()
//中继
.AddRelayClient().AddRelayServer()
//服务器穿透
.AddSForwardClient().AddSForwardServer()
//登录
@@ -104,7 +105,9 @@ namespace linker.messenger.entry
.AddWakeupClient().AddWakeupServer()
//白名单
.AddWhiteListClient().AddWhiteListServer();
.AddWhiteListClient().AddWhiteListServer()
.AddChannelClient();
}
/// <summary>
@@ -160,8 +163,6 @@ namespace linker.messenger.entry
ICommonStore commonStore = serviceProvider.GetService<ICommonStore>();
serviceProvider.UseMessenger();
if ((modules & ExcludeModule.StoreFile) != ExcludeModule.StoreFile)
@@ -228,6 +229,8 @@ namespace linker.messenger.entry
serviceProvider.UseSignInClient();
serviceProvider.UsePlanClient();
serviceProvider.UseChannelClient();
}
}

View File

@@ -1,6 +1,7 @@
using linker.libs;
using linker.libs.extends;
using linker.libs.timer;
using linker.messenger.channel;
using linker.messenger.forward.proxy;
using linker.messenger.pcp;
using linker.messenger.relay.client;
@@ -18,7 +19,8 @@ namespace linker.messenger.flow
private readonly FlowForward forwardFlow;
private readonly FlowTunnel flowTunnel;
public FlowForwardProxy(FlowForward forwardFlow, FlowTunnel flowTunnel, ISignInClientStore signInClientStore, TunnelTransfer tunnelTransfer, RelayClientTransfer relayTransfer, PcpTransfer pcpTransfer,
SignInClientTransfer signInClientTransfer, IRelayClientStore relayClientStore) : base(signInClientStore, tunnelTransfer, relayTransfer, pcpTransfer, signInClientTransfer, relayClientStore)
SignInClientTransfer signInClientTransfer, ChannelConnectionCaching channelConnectionCaching)
: base(signInClientStore, tunnelTransfer, relayTransfer, pcpTransfer, signInClientTransfer, channelConnectionCaching)
{
this.forwardFlow = forwardFlow;
this.flowTunnel = flowTunnel;

View File

@@ -1,6 +1,7 @@
using linker.libs;
using linker.libs.extends;
using linker.libs.timer;
using linker.messenger.channel;
using linker.messenger.pcp;
using linker.messenger.relay.client;
using linker.messenger.signin;
@@ -19,7 +20,8 @@ namespace linker.messenger.flow
private readonly FlowTunnel flowTunnel;
public FlowSocks5Proxy(FlowSocks5 flowSocks5, FlowTunnel flowTunnel, ISignInClientStore signInClientStore, TunnelTransfer tunnelTransfer, RelayClientTransfer relayTransfer, PcpTransfer pcpTransfer,
SignInClientTransfer signInClientTransfer, IRelayClientStore relayClientStore, Socks5CidrDecenterManager socks5CidrDecenterManager) : base(signInClientStore, tunnelTransfer, relayTransfer, pcpTransfer, signInClientTransfer, relayClientStore, socks5CidrDecenterManager)
SignInClientTransfer signInClientTransfer, Socks5CidrDecenterManager socks5CidrDecenterManager, ChannelConnectionCaching channelConnectionCaching)
: base(signInClientStore, tunnelTransfer, relayTransfer, pcpTransfer, signInClientTransfer, socks5CidrDecenterManager, channelConnectionCaching)
{
this.flowSocks5 = flowSocks5;
this.flowTunnel = flowTunnel;

View File

@@ -1,5 +1,6 @@
using linker.libs;
using linker.libs.extends;
using linker.messenger.channel;
using linker.messenger.pcp;
using linker.messenger.relay.client;
using linker.messenger.signin;
@@ -18,11 +19,11 @@ namespace linker.messenger.flow
private readonly FlowTunnel flowTunnel;
public FlowTuntapProxy(FlowTunnel flowTunnel, ISignInClientStore signInClientStore, TunnelTransfer tunnelTransfer, RelayClientTransfer relayTransfer, PcpTransfer pcpTransfer,
SignInClientTransfer signInClientTransfer, IRelayClientStore relayClientStore, TuntapConfigTransfer tuntapConfigTransfer,
SignInClientTransfer signInClientTransfer, TuntapConfigTransfer tuntapConfigTransfer,
TuntapCidrConnectionManager tuntapCidrConnectionManager, TuntapCidrDecenterManager tuntapCidrDecenterManager,
TuntapCidrMapfileManager tuntapCidrMapfileManager,TuntapDecenter tuntapDecenter)
: base(signInClientStore, tunnelTransfer, relayTransfer, pcpTransfer, signInClientTransfer, relayClientStore,
tuntapConfigTransfer, tuntapCidrConnectionManager, tuntapCidrDecenterManager, tuntapCidrMapfileManager, tuntapDecenter)
TuntapCidrMapfileManager tuntapCidrMapfileManager,TuntapDecenter tuntapDecenter, ChannelConnectionCaching channelConnectionCaching)
: base(signInClientStore, tunnelTransfer, relayTransfer, pcpTransfer, signInClientTransfer,
tuntapConfigTransfer, tuntapCidrConnectionManager, tuntapCidrDecenterManager, tuntapCidrMapfileManager, tuntapDecenter, channelConnectionCaching)
{
this.flowTunnel = flowTunnel;
}

View File

@@ -31,35 +31,7 @@ namespace linker.messenger.forward
this.serializer = serializer;
}
/// <summary>
/// 获取隧道连接
/// </summary>
/// <param name="param"></param>
/// <returns></returns>
public ConnectionListInfo Connections(ApiControllerParamsInfo param)
{
ulong hashCode = ulong.Parse(param.Content);
if (forwardProxy.Version.Eq(hashCode, out ulong version) == false)
{
return new ConnectionListInfo
{
List = forwardProxy.GetConnections(),
HashCode = version
};
}
return new ConnectionListInfo { HashCode = version };
}
/// <summary>
/// 移除隧道连接
/// </summary>
/// <param name="param"></param>
[Access(AccessValue.TunnelRemove)]
public void RemoveConnection(ApiControllerParamsInfo param)
{
forwardProxy.RemoveConnection(param.Content);
}
/// <summary>
/// 获取绑定IP列表
/// </summary>
@@ -165,14 +137,4 @@ namespace linker.messenger.forward
}
}
public sealed class ForwardListInfo
{
public ConcurrentDictionary<string, int> List { get; set; }
public ulong HashCode { get; set; }
}
public sealed class ConnectionListInfo
{
public ConcurrentDictionary<string, ITunnelConnection> List { get; set; }
public ulong HashCode { get; set; }
}
}

View File

@@ -23,8 +23,8 @@ namespace linker.messenger.forward.proxy
protected override string TransactionId => "forward";
public ForwardProxy(ISignInClientStore signInClientStore, TunnelTransfer tunnelTransfer, RelayClientTransfer relayTransfer, PcpTransfer pcpTransfer,
SignInClientTransfer signInClientTransfer, IRelayClientStore relayClientStore)
: base(tunnelTransfer, relayTransfer, pcpTransfer, signInClientTransfer, signInClientStore, relayClientStore)
SignInClientTransfer signInClientTransfer, ChannelConnectionCaching channelConnectionCaching)
: base(tunnelTransfer, relayTransfer, pcpTransfer, signInClientTransfer, signInClientStore, channelConnectionCaching)
{
TaskUdp();
}

View File

@@ -7,6 +7,7 @@ using linker.messenger.relay.messenger;
using linker.messenger.relay.server;
using linker.messenger.signin;
using linker.messenger.sync;
using linker.tunnel;
using linker.tunnel.connection;
using System.Collections.Concurrent;
@@ -72,10 +73,20 @@ namespace linker.messenger.relay.client
/// </summary>
/// <param name="param"></param>
/// <returns></returns>
public ConcurrentDictionary<string, bool> Operating(ApiControllerParamsInfo param)
public RelayOperatingInfo Operating(ApiControllerParamsInfo param)
{
return relayTransfer.Operating;
ulong hashCode = ulong.Parse(param.Content);
if (relayTransfer.OperatingVersion.Eq(hashCode, out ulong version) == false)
{
return new RelayOperatingInfo
{
List = relayTransfer.Operating,
HashCode = version
};
}
return new RelayOperatingInfo { HashCode = version };
}
/// <summary>
/// 连接
/// </summary>
@@ -146,6 +157,14 @@ namespace linker.messenger.relay.client
return resp.Code == MessageResponeCodes.OK && resp.Data.Span.SequenceEqual(Helper.TrueArray);
}
}
public sealed class RelayOperatingInfo
{
public ConcurrentDictionary<string, bool> List { get; set; }
public ulong HashCode { get; set; }
}
public sealed class UpdateInfo
{
public string Key { get; set; }

View File

@@ -14,9 +14,9 @@ namespace linker.messenger.relay.client
{
public List<IRelayClientTransport> Transports { get; private set; }
public VersionManager OperatingVersion => operating.DataVersion;
public ConcurrentDictionary<string, bool> Operating => operating.StringKeyValue;
private OperatingMultipleManager operating = new OperatingMultipleManager();
private readonly OperatingMultipleManager operating = new OperatingMultipleManager();
private Dictionary<string, List<Action<ITunnelConnection>>> OnConnected { get; } = new Dictionary<string, List<Action<ITunnelConnection>>>();
@@ -77,7 +77,6 @@ namespace linker.messenger.relay.client
if (string.IsNullOrWhiteSpace(nodeId)) nodeId = relayClientStore.DefaultNodeId;
if(protocol == TunnelProtocolType.None) protocol = relayClientStore.DefaultProtocol;
if (operating.StartOperation(BuildKey(remoteMachineId, transactionId)) == false)
{
return null;

View File

@@ -30,26 +30,6 @@ namespace linker.messenger.socks5
this.accessStore = accessStore;
}
public ConnectionListInfo Connections(ApiControllerParamsInfo param)
{
ulong hashCode = ulong.Parse(param.Content);
if (tunnelProxy.Version.Eq(hashCode, out ulong version) == false)
{
return new ConnectionListInfo
{
List = tunnelProxy.GetConnections(),
HashCode = version
};
}
return new ConnectionListInfo { HashCode = version };
}
[Access(AccessValue.TunnelRemove)]
public void RemoveConnection(ApiControllerParamsInfo param)
{
tunnelProxy.RemoveConnection(param.Content);
}
/// <summary>
/// 获取所有客户端的信息
/// </summary>
@@ -164,9 +144,4 @@ namespace linker.messenger.socks5
public ConcurrentDictionary<string, Socks5Info> List { get; set; }
public ulong HashCode { get; set; }
}
public sealed class ConnectionListInfo
{
public ConcurrentDictionary<string, ITunnelConnection> List { get; set; }
public ulong HashCode { get; set; }
}
}

View File

@@ -22,8 +22,8 @@ namespace linker.messenger.socks5
private readonly Socks5CidrDecenterManager socks5CidrDecenterManager;
public Socks5Proxy(ISignInClientStore signInClientStore, TunnelTransfer tunnelTransfer, RelayClientTransfer relayTransfer, PcpTransfer pcpTransfer,
SignInClientTransfer signInClientTransfer, IRelayClientStore relayClientStore, Socks5CidrDecenterManager socks5CidrDecenterManager)
: base(tunnelTransfer, relayTransfer, pcpTransfer, signInClientTransfer, signInClientStore, relayClientStore)
SignInClientTransfer signInClientTransfer, Socks5CidrDecenterManager socks5CidrDecenterManager, ChannelConnectionCaching channelConnectionCaching)
: base(tunnelTransfer, relayTransfer, pcpTransfer, signInClientTransfer, signInClientStore, channelConnectionCaching)
{
this.socks5CidrDecenterManager = socks5CidrDecenterManager;
TaskUdp();

View File

@@ -72,9 +72,18 @@ namespace linker.messenger.tunnel
/// </summary>
/// <param name="param"></param>
/// <returns></returns>
public ConcurrentDictionary<string, bool> Operating(ApiControllerParamsInfo param)
public TunnelOperatingInfo Operating(ApiControllerParamsInfo param)
{
return tunnelTransfer.Operating;
ulong hashCode = ulong.Parse(param.Content);
if (tunnelTransfer.OperatingVersion.Eq(hashCode, out ulong version) == false)
{
return new TunnelOperatingInfo
{
List = tunnelTransfer.Operating,
HashCode = version
};
}
return new TunnelOperatingInfo { HashCode = version };
}
/// <summary>
/// 连接
@@ -187,6 +196,11 @@ namespace linker.messenger.tunnel
return new TunnelLocalNetworkInfo();
}
public sealed class TunnelOperatingInfo
{
public ConcurrentDictionary<string, bool> List { get; set; }
public ulong HashCode { get; set; }
}
public sealed class TunnelListInfo
{
public ConcurrentDictionary<string, TunnelRouteLevelInfo> List { get; set; }

View File

@@ -46,36 +46,6 @@ namespace linker.messenger.tuntap
this.tuntapProxy = tuntapProxy;
}
/// <summary>
/// 连接
/// </summary>
/// <param name="param"></param>
/// <returns></returns>
public ConnectionListInfo Connections(ApiControllerParamsInfo param)
{
ulong hashCode = ulong.Parse(param.Content);
if (tuntapProxy.Version.Eq(hashCode, out ulong version) == false)
{
return new ConnectionListInfo
{
List = tuntapProxy.GetConnections(),
HashCode = version
};
}
return new ConnectionListInfo { HashCode = version };
}
/// <summary>
/// 删除连接
/// </summary>
/// <param name="param"></param>
[Access(AccessValue.TunnelRemove)]
public void RemoveConnection(ApiControllerParamsInfo param)
{
tuntapProxy.RemoveConnection(param.Content);
}
/// <summary>
/// 路由表
/// </summary>
@@ -363,12 +333,6 @@ namespace linker.messenger.tuntap
public ConcurrentDictionary<string, TuntapInfo> List { get; set; }
public ulong HashCode { get; set; }
}
public sealed class ConnectionListInfo
{
public ConcurrentDictionary<string, ITunnelConnection> List { get; set; }
public ulong HashCode { get; set; }
}
public sealed class NetworkParamInfo
{
public IPAddress IP { get; set; }

View File

@@ -50,7 +50,7 @@ namespace linker.messenger.tuntap
var items = tuntapDecenter.Infos.Values.Where(c => c.IP != null && c.IP.Equals(IPAddress.Any) == false && (c.Status & TuntapStatus.Running) == TuntapStatus.Running);
if ((tuntapConfigTransfer.Info.Switch & TuntapSwitch.AutoConnect) != TuntapSwitch.AutoConnect)
{
var connections = tuntapProxy.GetConnections();
var connections = tuntapProxy.Connections;
items = items.Where(c => connections.TryGetValue(c.MachineId, out ITunnelConnection connection) && connection.Connected || c.MachineId == signInClientStore.Id);
}

View File

@@ -1,13 +1,14 @@
using linker.tunnel;
using linker.tunnel.connection;
using linker.libs;
using System.Buffers.Binary;
using linker.libs;
using linker.messenger.channel;
using linker.messenger.pcp;
using linker.messenger.relay.client;
using linker.messenger.signin;
using linker.messenger.pcp;
using linker.messenger.tuntap.cidr;
using linker.nat;
using linker.tun.device;
using linker.tunnel;
using linker.tunnel.connection;
using System.Buffers.Binary;
namespace linker.messenger.tuntap
{
@@ -31,8 +32,10 @@ namespace linker.messenger.tuntap
public TuntapProxy(ISignInClientStore signInClientStore,
TunnelTransfer tunnelTransfer, RelayClientTransfer relayTransfer, PcpTransfer pcpTransfer,
SignInClientTransfer signInClientTransfer, IRelayClientStore relayClientStore, TuntapConfigTransfer tuntapConfigTransfer, TuntapCidrConnectionManager tuntapCidrConnectionManager, TuntapCidrDecenterManager tuntapCidrDecenterManager, TuntapCidrMapfileManager tuntapCidrMapfileManager, TuntapDecenter tuntapDecenter)
: base(tunnelTransfer, relayTransfer, pcpTransfer, signInClientTransfer, signInClientStore, relayClientStore)
SignInClientTransfer signInClientTransfer, TuntapConfigTransfer tuntapConfigTransfer,
TuntapCidrConnectionManager tuntapCidrConnectionManager, TuntapCidrDecenterManager tuntapCidrDecenterManager,
TuntapCidrMapfileManager tuntapCidrMapfileManager, TuntapDecenter tuntapDecenter, ChannelConnectionCaching channelConnectionCaching)
: base(tunnelTransfer, relayTransfer, pcpTransfer, signInClientTransfer, signInClientStore, channelConnectionCaching)
{
this.tuntapConfigTransfer = tuntapConfigTransfer;
this.tuntapCidrConnectionManager = tuntapCidrConnectionManager;
@@ -85,9 +88,9 @@ namespace linker.messenger.tuntap
public async Task InputPacket(LinkerTunDevicPacket packet)
{
//IPV4广播组播、IPV6 多播
if ((packet.IPV4Broadcast || packet.IPV6Multicast) && tuntapConfigTransfer.Info.Multicast == false && connections.IsEmpty == false)
if ((packet.IPV4Broadcast || packet.IPV6Multicast) && tuntapConfigTransfer.Info.Multicast == false && Connections.IsEmpty == false)
{
await Task.WhenAll(connections.Values.Where(c => c != null && c.Connected).Select(c => c.SendAsync(packet.Buffer, packet.Offset, packet.Length)));
await Task.WhenAll(Connections.Values.Where(c => c != null && c.Connected).Select(c => c.SendAsync(packet.Buffer, packet.Offset, packet.Length))).ConfigureAwait(false);
return;
}

View File

@@ -19,6 +19,7 @@ namespace linker.tunnel
private readonly TunnelWanPortTransfer tunnelWanPortTransfer;
private readonly TunnelUpnpTransfer tunnelUpnpTransfer;
public VersionManager OperatingVersion => operating.DataVersion;
public ConcurrentDictionary<string, bool> Operating => operating.StringKeyValue;
private readonly OperatingMultipleManager operating = new OperatingMultipleManager();
private uint flowid = 1;

View File

@@ -1,11 +1,5 @@
import { sendWebsocketMsg } from './request'
export const getForwardConnections = (hashcode = '0') => {
return sendWebsocketMsg('forward/connections', hashcode);
}
export const removeForwardConnection = (id) => {
return sendWebsocketMsg('forward/removeconnection', id);
}
export const getForwardInfo = (hashcode = '0') => {
return sendWebsocketMsg('forward/get', hashcode);
}

View File

@@ -12,8 +12,8 @@ export const setRelayServers = (servers) => {
export const setRelaySubscribe = () => {
return sendWebsocketMsg('relay/Subscribe');
}
export const relayOperating = () => {
return sendWebsocketMsg('relay/Operating');
export const relayOperating = (data) => {
return sendWebsocketMsg('relay/Operating',data);
}
export const relayConnect = (data) => {
return sendWebsocketMsg('relay/Connect', data);

View File

@@ -1,13 +1,5 @@
import { sendWebsocketMsg } from './request'
export const getSocks5Connections = (hashcode = '0') => {
return sendWebsocketMsg('socks5/connections', hashcode);
}
export const removeSocks5Connection = (id) => {
return sendWebsocketMsg('socks5/removeconnection', id);
}
export const getSocks5Info = (hashcode = '0') => {
return sendWebsocketMsg('socks5/get', hashcode);
}

View File

@@ -6,8 +6,8 @@ export const getTunnelInfo = (hashcode = '0') => {
export const tunnelRefresh = () => {
return sendWebsocketMsg('tunnel/refresh');
}
export const tunnelOperating = () => {
return sendWebsocketMsg('tunnel/Operating');
export const tunnelOperating = (data) => {
return sendWebsocketMsg('tunnel/Operating',data);
}
export const tunnelConnect = (data) => {
return sendWebsocketMsg('tunnel/connect',data);
@@ -29,4 +29,11 @@ export const getTunnelRecords = () => {
}
export const getTunnelNetwork = (data) => {
return sendWebsocketMsg('tunnel/GetNetwork',data);
}
export const getTunnelConnections = (hashcode) => {
return sendWebsocketMsg('channel/get',hashcode);
}
export const removeTunnelConnection = (machineid,transactionId) => {
return sendWebsocketMsg('channel/remove',{machineid,transactionId});
}

View File

@@ -1,13 +1,6 @@
import { sendWebsocketMsg } from './request'
export const getTuntapConnections = (hashcode = '0') => {
return sendWebsocketMsg('tuntap/connections', hashcode);
}
export const removeTuntapConnection = (id) => {
return sendWebsocketMsg('tuntap/removeconnection', id);
}
export const getTuntapRoutes = (machineid) => {
return sendWebsocketMsg('tuntap/routes', machineid);
}

View File

@@ -28,8 +28,8 @@ export const provideAccess = () => {
});
});
}
const accessProcessFn = (device) => {
Object.assign(device,{
const accessProcessFn = (device,json) => {
Object.assign(json,{
hook_accesss: access.value.list[device.MachineId] || ''
})
}

View File

@@ -1,156 +0,0 @@
import { getForwardConnections, removeForwardConnection } from "@/apis/forward";
import { getTuntapConnections, removeTuntapConnection } from "@/apis/tuntap";
import { getSocks5Connections, removeSocks5Connection } from "@/apis/socks5";
import { inject, provide, ref } from "vue";
const connectionsSymbol = Symbol();
const forwardConnectionsSymbol = Symbol();
const tuntapConnectionsSymbol = Symbol();
const socks5ConnectionsSymbol = Symbol();
export const provideConnections = () => {
const connections = ref({
showEdit: false,
speedCache: {},
current: '',
currentName: '',
hashcode: 0,
hashcode1: 0,
_updateRealTime: false,
updateRealTime: (value) => {
forwardConnections.value.hashcode = 0;
tuntapConnections.value.hashcode = 0;
socks5Connections.value.hashcode = 0;
connections.value._updateRealTime = value;
}
});
provide(connectionsSymbol, connections);
const forwardConnections = ref({
timer: 0,
list: {},
hashcode: 0,
});
provide(forwardConnectionsSymbol, forwardConnections);
const _getForwardConnections = () => {
clearTimeout(forwardConnections.value.timer)
getForwardConnections(forwardConnections.value.hashcode.toString()).then((res) => {
if (forwardConnections.value._updateRealTime == false)
forwardConnections.value.hashcode = res.HashCode;
if (res.List) {
parseConnections(res.List, removeForwardConnection);
forwardConnections.value.list = res.List;
}
forwardConnections.value.timer = setTimeout(_getForwardConnections, 1000);
}).catch((e) => {
forwardConnections.value.timer = setTimeout(_getForwardConnections, 1000);
})
}
const tuntapConnections = ref({
timer: 0,
list: {},
hashcode: 0,
});
provide(tuntapConnectionsSymbol, tuntapConnections);
const _getTuntapConnections = () => {
clearTimeout(tuntapConnections.value.timer)
getTuntapConnections(tuntapConnections.value.hashcode.toString()).then((res) => {
if (connections.value._updateRealTime == false)
tuntapConnections.value.hashcode = res.HashCode;
if (res.List) {
parseConnections(res.List, removeTuntapConnection);
tuntapConnections.value.list = res.List;
}
tuntapConnections.value.timer = setTimeout(_getTuntapConnections, 1000);
}).catch((e) => {
tuntapConnections.value.timer = setTimeout(_getTuntapConnections, 1000);
})
}
const socks5Connections = ref({
timer: 0,
list: {},
hashcode: 0,
});
provide(socks5ConnectionsSymbol, socks5Connections);
const _getSocks5Connections = () => {
clearTimeout(socks5Connections.value.timer)
getSocks5Connections(socks5Connections.value.hashcode.toString()).then((res) => {
if (connections.value._updateRealTime == false)
socks5Connections.value.hashcode = res.HashCode;
if (res.List) {
parseConnections(res.List, removeSocks5Connection);
socks5Connections.value.list = res.List;
}
socks5Connections.value.timer = setTimeout(_getSocks5Connections, 1000);
}).catch((e) => {
socks5Connections.value.timer = setTimeout(_getSocks5Connections, 1000);
})
}
const parseConnections = (_connections, removeFunc) => {
const caches = connections.value.speedCache;
for (let machineId in _connections) {
const connection = _connections[machineId];
connection.removeFunc = removeFunc;
const key = `${connection.RemoteMachineId}-${connection.TransactionId}`;
const cache = caches[key] || { SendBytes: 0, ReceiveBytes: 0 };
connection.SendBytesText = parseSpeed(connection.SendBytes - cache.SendBytes,'/s');
connection.ReceiveBytesText = parseSpeed(connection.ReceiveBytes - cache.ReceiveBytes,'/s');
connection.SendBufferRemainingText = parseSpeed(connection.SendBufferRemaining,'');
connection.RecvBufferRemainingText = parseSpeed(connection.RecvBufferRemaining || 0,'');
cache.SendBytes = connection.SendBytes;
cache.ReceiveBytes = connection.ReceiveBytes;
caches[key] = cache;
}
}
const parseSpeed = (num,subfix = '') => {
let index = 0;
while (num >= 1024) {
num /= 1024;
index++;
}
return `${num.toFixed(2)}${['B', 'KB', 'MB', 'GB', 'TB'][index]}${subfix}`;
}
const handleTunnelConnections = (device) => {
connections.value.current = device.MachineId;
connections.value.currentName = device.MachineName;
connections.value.showEdit = true;
}
const clearConnectionsTimeout = () => {
clearTimeout(forwardConnections.value.timer);
clearTimeout(tuntapConnections.value.timer);
clearTimeout(socks5Connections.value.timer);
}
return {
connections,
forwardConnections, _getForwardConnections,
tuntapConnections, _getTuntapConnections,
socks5Connections, _getSocks5Connections,
handleTunnelConnections, clearConnectionsTimeout
}
}
export const useConnections = () => {
return inject(connectionsSymbol);
}
export const useForwardConnections = () => {
return inject(forwardConnectionsSymbol);
}
export const useTuntapConnections = () => {
return inject(tuntapConnectionsSymbol);
}
export const useSocks5Connections = () => {
return inject(socks5ConnectionsSymbol);
}

View File

@@ -25,10 +25,14 @@ export const provideDecenter = () => {
});
}
const counterProcessFn = (device) => {
Object.assign(device,{
hook_counter: decenter.value.list[device.MachineId] || ''
})
const counterProcessFn = (device,json) => {
const _json = {};
for (const key in decenter.value.list) {
_json[key] = decenter.value.list[key][device.MachineId] || 0;
}
Object.assign(json,{
hook_counter: _json
});
}
const counterRefreshFn = () => {
refreshCounter();

View File

@@ -14,9 +14,9 @@
<p class="flex">
<template v-if="scope.row.Connected">
<div>
<template v-if="tuntap.list[scope.row.MachineId] && tuntap.list[scope.row.MachineId].systems">
<template v-for="system in tuntap.list[scope.row.MachineId].systems">
<span :title="tuntap.list[scope.row.MachineId].SystemInfo">
<template v-if="scope.row.hook_tuntap && scope.row.hook_tuntap.systems">
<template v-for="system in scope.row.hook_tuntap.systems">
<span :title="scope.row.hook_tuntap.SystemInfo">
<img class="system" :src="`./${system}.svg`" />
</span>
</template>
@@ -27,7 +27,7 @@
</span>
<span class="flex-1"></span>
<UpdaterBtn v-if="scope.row.showip == false" :config="true" :item="scope.row"></UpdaterBtn>
<UpdaterBtn :config="true" :item="scope.row"></UpdaterBtn>
</template>
<template v-else>
<span>{{ scope.row.LastSignIn }}</span>
@@ -42,14 +42,12 @@ import { ref } from 'vue';
import {Search} from '@element-plus/icons-vue'
import UpdaterBtn from '../updater/UpdaterBtn.vue';
import DeviceName from './DeviceName.vue';
import { useTuntap } from '../tuntap/tuntap';
export default {
emits:['refresh'],
components:{Search,UpdaterBtn,DeviceName},
setup(props,{emit}) {
const tuntap = useTuntap();
const name = ref(sessionStorage.getItem('search-name') || '');
const handleRefresh = ()=>{
@@ -58,7 +56,7 @@ export default {
}
return {
tuntap,name, handleRefresh
name, handleRefresh
}
}
}

View File

@@ -9,6 +9,7 @@ export const provideDevices = () => {
const machineId = computed(() => globalData.value.config.Client.Id);
const devices = reactive({
timer: 0,
timer1: 0,
page: {
Request: {
Page: 1, Size: +(localStorage.getItem('ps') || '10'), Name: '', Ids: [], Prop: '', Asc: true
@@ -25,18 +26,32 @@ export const provideDevices = () => {
provide(deviceSymbol, devices);
const hooks = {};
const addDeviceHook = (name,dataFn,processFn,refreshFn) => {
hooks[name] = {dataFn,processFn,refreshFn,changed:true};
const deviceAddHook = (name,dataFn,processFn,refreshFn) => {
hooks[name] = {dataFn,processFn,refreshFn,changed:true,refresh:true};
}
const deviceRefreshHook = (name) => {
if(hooks[name]) {
hooks[name].changed = true;
}
}
const startHooks = () => {
const fn = async ()=>{
for (let j in devices.page.List) {
for(let name in hooks) {
const hook = hooks[name];
if(hook.changed) {
hook.changed = false;
hook.refreshFn();
hook.processFn(devices.page.List[j]);
clearTimeout(devices.timer1);
for(let name in hooks) {
const hook = hooks[name];
if(hook.refresh) {
hook.refresh = false;
hook.refreshFn();
}
}
for(let name in hooks) {
const hook = hooks[name];
if(hook.changed) {
hook.changed = false;
for (let i = 0; i< devices.page.List.length; i++) {
const json = {}
hook.processFn(devices.page.List[i],json);
Object.assign(devices.page.List[i], json);
}
}
}
@@ -44,13 +59,13 @@ export const provideDevices = () => {
const hook = hooks[name];
hook.changed = await hook.dataFn();
}
setTimeout(fn,1000);
devices.timer1 = setTimeout(fn,1000);
}
fn();
}
startHooks();
const startDeviceProcess = () => {
const deviceStartProcess = () => {
_getSignList().then(()=>{
startHooks();
_getSignList1();
@@ -66,8 +81,7 @@ export const provideDevices = () => {
showDel: machineId.value != res.List[j].MachineId && res.List[j].Connected == false,
showAccess: machineId.value != res.List[j].MachineId && res.List[j].Connected,
showReboot: res.List[j].Connected,
isSelf: machineId.value == res.List[j].MachineId,
showip: false
isSelf: machineId.value == res.List[j].MachineId
});
if (res.List[j].isSelf) {
globalData.value.self = res.List[j];
@@ -120,9 +134,11 @@ export const provideDevices = () => {
}
_getSignList();
}
const clearDevicesTimeout = () => {
const deviceClearTimeout = () => {
clearTimeout(devices.timer);
clearTimeout(devices.timer1);
devices.timer = 0;
devices.timer1 = 0;
}
const setSort = (ids) => {
@@ -130,7 +146,7 @@ export const provideDevices = () => {
}
return {
devices,addDeviceHook, startDeviceProcess, handlePageChange, handlePageSizeChange, clearDevicesTimeout, setSort
devices,deviceAddHook,deviceRefreshHook, deviceStartProcess, handlePageChange, handlePageSizeChange, deviceClearTimeout, setSort
}
}
export const useDevice = () => {

View File

@@ -1,19 +1,19 @@
<template>
<el-table-column prop="forward" :label="$t('home.forward')" width="80">
<template #default="scope">
<template v-if="scope.row.Connected">
<template v-if="scope.row.Connected && scope.row.hook_counter">
<AccessBoolean value="ForwardOther,ForwardSelf">
<template #default="{values}">
<template v-if="values.ForwardOther || (values.ForwardSelf && scope.row.isSelf)">
<div class="nowrap">
<ConnectionShow :data="connections.list[scope.row.MachineId]" :row="scope.row" transitionId="forward"></ConnectionShow>
<a href="javascript:;" :class="{green:(scope.row.hook_counter || {forward:0}).forward>0}" @click="handleEdit(scope.row.MachineId,scope.row.MachineName,values)">
<span :class="{gateway:(scope.row.hook_counter || {forward:0}).forward>0}">{{$t('home.forwardPort')}}({{(scope.row.hook_counter || {forward:0}).forward>99 ? '99+' : (scope.row.hook_counter || {forward:0}).forward}})</span>
<ConnectionShow :row="scope.row" transactionId="forward"></ConnectionShow>
<a href="javascript:;" :class="{green:scope.row.hook_counter.forward>0}" @click="handleEdit(scope.row.MachineId,scope.row.MachineName,values)">
<span :class="{gateway:scope.row.hook_counter.forward>0}">{{$t('home.forwardPort')}}({{scope.row.hook_counter.forward>99 ? '99+' : scope.row.hook_counter.forward}})</span>
</a>
</div>
<div class="nowrap">
<a href="javascript:;" :class="{green:(scope.row.hook_counter || {sforward:0}).sforward>0}" @click="handleSEdit(scope.row.MachineId,scope.row.MachineName,values)">
<span :class="{gateway:(scope.row.hook_counter || {sforward:0}).sforward>0 }">{{$t('home.forwardServer')}}({{(scope.row.hook_counter || {sforward:0}).sforward>99 ? '99+' :(scope.row.hook_counter || {sforward:0}).sforward}})</span>
<a href="javascript:;" :class="{green:scope.row.hook_counter.sforward>0}" @click="handleSEdit(scope.row.MachineId,scope.row.MachineName,values)">
<span :class="{gateway:scope.row.hook_counter.sforward>0 }">{{$t('home.forwardServer')}}({{scope.row.hook_counter.sforward>99 ? '99+' :scope.row.hook_counter.sforward}})</span>
</a>
</div>
</template>
@@ -28,8 +28,7 @@ import { injectGlobalData } from '@/provide';
import { useForward } from './forward';
import { useSforward } from './sforward';
import { computed } from 'vue';
import { useForwardConnections } from '../connection/connections';
import ConnectionShow from '../connection/ConnectionShow.vue';
import ConnectionShow from '../tunnel/ConnectionShow.vue';
import { ElMessage } from 'element-plus';
export default {
@@ -41,7 +40,6 @@ export default {
const globalData = injectGlobalData();
const machineId = computed(() => globalData.value.config.Client.Id);
const connections = useForwardConnections();
const handleEdit = (_machineId,_machineName,access)=>{
if(machineId.value === _machineId){
@@ -76,7 +74,7 @@ export default {
sforward.value.showEdit = true;
}
return {
connections, handleEdit,handleSEdit
handleEdit,handleSEdit
}
}
}

View File

@@ -2,11 +2,7 @@ import { inject, provide, ref } from "vue"
const operSymbol = Symbol();
export const provideOper = () => {
const oper = ref({
device: {id:'',name:''},
showFirewall:false,
showWakeup:false,
showTransport:false,
showAction:false,
device: {id:'',name:''}
});
provide(operSymbol, oper);
return {

View File

@@ -1,34 +1,20 @@
<template>
<el-table-column prop="socks5" :label="socks5.show?$t('home.proxy'):''" width="160">
<el-table-column prop="socks5" :label="$t('home.proxy')" width="160">
<template #default="scope">
<div v-if="socks5.show && socks5.list[scope.row.MachineId]">
<Socks5Show :config="true" :item="scope.row" @edit="handleSocks5" @refresh="handleSocks5Refresh"></Socks5Show>
<div v-if="scope.row.hook_socks5">
<Socks5Show :config="true" :item="scope.row"></Socks5Show>
</div>
</template>
</el-table-column>
</template>
<script>
import { useSocks5 } from './socks5';
import Socks5Show from './Socks5Show.vue';
export default {
emits: ['edit','refresh'],
components:{Socks5Show},
setup(props, { emit }) {
setup() {
const socks5 = useSocks5();
const handleSocks5 = (_socks5) => {
socks5.value.current = _socks5;
socks5.value.showEdit = true;
}
const handleSocks5Refresh = ()=>{
emit('refresh');
}
return {
socks5, handleSocks5,handleSocks5Refresh
}
return {}
}
}
</script>

View File

@@ -27,7 +27,6 @@ import { injectGlobalData } from '@/provide';
import { ElMessage } from 'element-plus';
import { reactive, ref, watch } from 'vue';
import { useSocks5 } from './socks5';
import { Delete, Plus } from '@element-plus/icons-vue'
import Socks5Lan from './Socks5Lan.vue';
export default {
props: ['modelValue'],
@@ -61,7 +60,7 @@ export default {
const socks5Dom = ref(null);
const handleSave = () => {
const json = JSON.parse(JSON.stringify(socks5.value.current));
const json = JSON.parse(JSON.stringify(socks5.value.current,(key,value)=> key =='device'?'':value));
json.Port = +(state.ruleForm.Port || '1805');
json.Lans = socks5Dom.value.getData();
updateSocks5(json).then(() => {

View File

@@ -4,36 +4,36 @@
<div>
<div class="flex">
<div class="flex-1">
<ConnectionShow :data="connections.list[item.MachineId]" :row="item" transitionId="socks5"></ConnectionShow>
<a href="javascript:;" class="a-line" @click="handleSocks5Port(socks5.list[item.MachineId],values)" title="此设备的socks5代理">
<template v-if="socks5.list[item.MachineId].SetupError">
<strong class="red" :title="socks5.list[item.MachineId].SetupError">
socks5://*:{{ socks5.list[item.MachineId].Port }}
<ConnectionShow :row="item" transactionId="socks5"></ConnectionShow>
<a href="javascript:;" class="a-line" @click="handleSocks5Port(item.hook_socks5,values)" title="此设备的socks5代理">
<template v-if="item.hook_socks5.SetupError">
<strong class="red" :title="item.hook_socks5.SetupError">
socks5://*:{{ item.hook_socks5.Port }}
</strong>
</template>
<template v-else>
<template v-if="item.Connected &&socks5.list[item.MachineId].running">
<strong class="green gateway">socks5://*:{{ socks5.list[item.MachineId].Port }}</strong>
<template v-if="item.Connected &&item.hook_socks5.running">
<strong class="green gateway">socks5://*:{{ item.hook_socks5.Port }}</strong>
</template>
<template v-else>
<span>socks5://*:{{ socks5.list[item.MachineId].Port }}</span>
<span>socks5://*:{{ item.hook_socks5.Port }}</span>
</template>
</template>
</a>
</div>
<template v-if="socks5.list[item.MachineId].loading">
<template v-if="item.hook_socks5.loading">
<div>
<el-icon size="14" class="loading"><Loading /></el-icon>
</div>
</template>
<template v-else>
<el-switch :model-value="item.Connected && socks5.list[item.MachineId].running" :loading="socks5.list[item.MachineId].loading" disabled @click="handleSocks5(socks5.list[item.MachineId],values)" size="small" inline-prompt active-text="😀" inactive-text="😣" >
<el-switch :model-value="item.Connected && item.hook_socks5.running" :loading="item.hook_socks5.loading" disabled @click="handleSocks5(item.hook_socks5,values)" size="small" inline-prompt active-text="😀" inactive-text="😣" >
</el-switch>
</template>
</div>
<div>
<div>
<template v-for="(item1,index) in socks5.list[item.MachineId].Lans" :key="index">
<template v-for="(item1,index) in item.hook_socks5.Lans" :key="index">
<template v-if="item1.Disabled">
<div class="flex disable" title="已禁用">{{ item1.IP }} / {{ item1.PrefixLength }}</div>
</template>
@@ -41,7 +41,7 @@
<div class="flex yellow" title="与其它设备填写IP、或本机局域网IP有冲突">{{ item1.IP }} / {{ item1.PrefixLength }}</div>
</template>
<template v-else>
<div class="flex green" title="正常使用" :class="{green:item.Connected &&socks5.list[item.MachineId].running}">{{ item1.IP }} / {{ item1.PrefixLength }}</div>
<div class="flex green" title="正常使用" :class="{green:item.Connected && item.hook_socks5.running}">{{ item1.IP }} / {{ item1.PrefixLength }}</div>
</template>
</template>
</div>
@@ -58,24 +58,21 @@ import { useSocks5 } from './socks5';
import {Loading} from '@element-plus/icons-vue'
import { injectGlobalData } from '@/provide';
import { computed } from 'vue';
import { useSocks5Connections } from '../connection/connections';
import ConnectionShow from '../connection/ConnectionShow.vue';
import ConnectionShow from '../tunnel/ConnectionShow.vue';
export default {
props:['item','config'],
emits: ['edit','refresh'],
components:{Loading,ConnectionShow},
setup (props,{emit}) {
setup (props) {
const socks5 = useSocks5();
const globalData = injectGlobalData();
const machineId = computed(() => globalData.value.config.Client.Id);
const connections = useSocks5Connections();
const handleSocks5 = (socks5,access) => {
const handleSocks5 = (_socks5,access) => {
if(!props.config){
return;
}
if(machineId.value === socks5.MachineId){
if(machineId.value === _socks5.MachineId){
if(!access.Socks5StatusSelf){
ElMessage.success('无权限');
return;
@@ -86,8 +83,8 @@ export default {
return;
}
}
const fn = props.item.Connected && socks5.running ? stopSocks5 (socks5.MachineId) : runSocks5(socks5.MachineId);
socks5.loading = true;
const fn = props.item.Connected && _socks5.running ? stopSocks5 (_socks5.MachineId) : runSocks5(_socks5.MachineId);
_socks5.loading = true;
fn.then(() => {
ElMessage.success('操作成功!');
}).catch((err) => {
@@ -95,11 +92,11 @@ export default {
ElMessage.error('操作失败!');
})
}
const handleSocks5Port = (socks5,access) => {
if(!props.config && machineId.value != socks5.MachineId){
const handleSocks5Port = (_socks5,access) => {
if(!props.config && machineId.value != _socks5.MachineId){
return;
}
if(machineId.value === socks5.MachineId){
if(machineId.value === _socks5.MachineId){
if(!access.Socks5ChangeSelf){
ElMessage.success('无权限');
return;
@@ -110,15 +107,13 @@ export default {
return;
}
}
socks5.device = props.item;
emit('edit',socks5);
}
const handleSocks5Refresh = ()=>{
emit('refresh');
_socks5.device = props.item;
socks5.value.current = _socks5;
socks5.value.showEdit = true;
}
return {
item:computed(()=>props.item),socks5,connections, handleSocks5, handleSocks5Port,handleSocks5Refresh
socks5, handleSocks5, handleSocks5Port,
}
}
}

View File

@@ -13,36 +13,35 @@ export const provideSocks5 = () => {
});
provide(socks5Symbol, socks5);
const _getSocks5Info = () => {
clearTimeout(socks5.value.timer);
getSocks5Info(socks5.value.hashcode.toString()).then((res) => {
socks5.value.hashcode = res.HashCode;
if (res.List) {
for (let j in res.List) {
Object.assign(res.List[j], {
running: res.List[j].Status == 2,
loading: res.List[j].Status == 1
});
const socks5DataFn = () => {
return new Promise((resolve, reject) => {
getSocks5Info(socks5.value.hashcode.toString()).then((res) => {
socks5.value.hashcode = res.HashCode;
if (res.List) {
for (let j in res.List) {
Object.assign(res.List[j], {
running: res.List[j].Status == 2,
loading: res.List[j].Status == 1
});
}
socks5.value.list = res.List;
resolve(true);
return;
}
socks5.value.list = res.List;
}
socks5.value.timer = setTimeout(_getSocks5Info, 1100);
}).catch((e) => {
socks5.value.timer = setTimeout(_getSocks5Info, 1100);
resolve(false);
}).catch((e) => {
resolve(false);
});
});
}
const handleSocks5Edit = (_socks5) => {
socks5.value.current = _socks5;
socks5.value.showEdit = true;
const socks5ProcessFn = (device,json) => {
Object.assign(json,{
hook_socks5: socks5.value.list[device.MachineId] || ''
});
}
const handleSocks5Refresh = () => {
const socks5RefreshFn = () => {
refreshSocks5();
}
const clearSocks5Timeout = () => {
clearTimeout(socks5.value.timer);
socks5.value.timer = 0;
}
const getSocks5Machines = (name) => {
return Object.values(socks5.value.list)
.filter(c => c.Port.toString().indexOf(name) >= 0 || (c.Lans.filter(d => d.IP.indexOf(name) >= 0).length > 0))
@@ -55,7 +54,7 @@ export const provideSocks5 = () => {
return {
socks5, _getSocks5Info, handleSocks5Edit, handleSocks5Refresh, clearSocks5Timeout, getSocks5Machines, sortSocks5
socks5, socks5DataFn,socks5ProcessFn, socks5RefreshFn, getSocks5Machines, sortSocks5
}
}

View File

@@ -1,15 +1,7 @@
<template>
<div class="connect-point" @click="handleShow" v-if="state.isSelf == false">
<template v-if="state.connection && state.connection.Connected">
<template v-if="state.connection.Type == 0">
<span class="connect-point p2p" title="打洞直连" v-loading="state.connecting"></span>
</template>
<template v-else-if="state.connection.Type == 1">
<span class="connect-point relay" title="中继连接" v-loading="state.connecting"></span>
</template>
<template v-else-if="state.connection.Type == 2">
<span class="connect-point node" title="节点连接" v-loading="state.connecting"></span>
</template>
<div class="connect-point" @click="handleShow">
<template v-if="state.className">
<span :class="`connect-point ${state.className}`" :title="state.title" v-loading="state.connecting"></span>
</template>
<template v-else>
<span class="connect-point default" title="未连接" v-loading="state.connecting"></span>
@@ -18,27 +10,22 @@
</template>
<script>
import { computed, reactive, watch } from 'vue';
import { computed, reactive } from 'vue';
import { useConnections } from './connections';
import { useTunnel } from '../tunnel/tunnel';
export default {
props: ['data','row'],
props: ['row','transactionId'],
setup (props) {
const connections = useConnections();
const tunnel = useTunnel();
const connection = computed(()=>props.row.hook_connection?props.row.hook_connection[props.transactionId] || {} : {});
const state = reactive({
connection:props.data,
transitionId:props.transitionId,
connecting:computed(()=>tunnel.value.p2pOperatings[props.row.MachineId] || tunnel.value.relayOperatings[props.row.MachineId]),
isSelf:props.row.isSelf
});
watch(()=>props.data,()=>{
state.connection = props.data
transactionId:props.transactionId,
connecting:computed(()=>props.row.hook_operating[props.transactionId]),
className:computed(()=>['p2p','relay','node'][connection.value.Type]),
title:computed(()=>['打洞直连','中继连接','节点连接'][connection.value.Type]),
});
const handleShow = () => {
connections.value.current = props.row.MachineId;
connections.value.currentName = props.row.MachineName;
connections.value.device = props.row;
connections.value.transactionId = props.transactionId;
connections.value.showEdit = true;
}

View File

@@ -1,81 +1,60 @@
<template>
<el-dialog v-model="state.show" append-to=".app-wrap" :title="`与[${state.machineName}]的链接`" top="1vh" width="98%">
<el-dialog v-model="state.show" append-to=".app-wrap" :title="`与[${state.device.MachineName}]的链接`" top="1vh" width="500">
<div>
<el-table :data="state.data" size="small" border height="500">
<el-table-column property="RemoteMachineId" label="目标/服务器">
<template #default="scope">
<div :class="{ green: scope.row.Connected }">
<p>{{ scope.row.IPEndPoint }}</p>
<p>ssl : {{ scope.row.SSL }}</p>
</div>
</template>
</el-table-column>
<el-table-column property="TransactionId" label="事务" width="80">
<template #default="scope">
<span>{{ state.transactions[scope.row.TransactionId] }}</span>
</template>
</el-table-column>
<el-table-column property="TransportName" label="协议" >
<template #default="scope">
<div>
<p>{{ scope.row.TransportName }}({{ state.protocolTypes[scope.row.ProtocolType] }})</p>
<p>{{ state.types[scope.row.Type] }} - {{ scope.row.SendBufferRemainingText }} - {{ scope.row.RecvBufferRemainingText }}</p>
</div>
</template>
</el-table-column>
<el-table-column property="Delay" label="延迟" width="60">
<template #default="scope">
<div>
<p>{{ scope.row.Delay }}</p>
</div>
</template>
</el-table-column>
<el-table-column property="Bytes" label="通信">
<template #default="scope">
<div>
<p>up : {{ scope.row.SendBytesText }}</p>
<p>down : {{ scope.row.ReceiveBytesText }}</p>
</div>
</template>
</el-table-column>
<el-table-column property="relay" label="中继节点">
<template #default="scope">
<div>
<p class="ellipsis">
<span>中继 : </span>
<a v-if="state.relayOperatings[scope.row.RemoteMachineId]" href="javascript:;" class="a-line">
<span>操作中.</span><el-icon size="14" class="loading"><Loading /></el-icon>
</a>
<a v-else href="javascript:;" class="a-line" @click="handleNode(scope.row)">{{
state.nodesDic[scope.row.NodeId] || '选择节点' }}</a>
</p>
<p>
<span>打洞 : </span>
<a v-if="state.p2pOperatings[scope.row.RemoteMachineId]" href="javascript:;" class="a-line">
<span>操作中.</span><el-icon size="14" class="loading"><Loading /></el-icon>
</a>
<a v-else href="javascript:;" class="a-line" @click="handlep2p(scope.row)">尝试打洞</a>
</p>
</div>
</template>
</el-table-column>
<el-table-column label="操作" width="54">
<template #default="scope">
<div>
<AccessShow value="TunnelRemove">
<el-popconfirm confirm-button-text="确认" cancel-button-text="取消"
title="确定关闭此连接?" @confirm="handleDel(scope.row)">
<template #reference>
<el-button type="danger" size="small"><el-icon>
<Delete />
</el-icon></el-button>
</template>
</el-popconfirm>
</AccessShow>
</div>
</template>
</el-table-column>
</el-table>
<el-descriptions border size="small" :column="2" column-max-width="120px" overlength-control="wrap">
<el-descriptions-item label="目标">{{ state.connection.IPEndPoint || '0.0.0.0:0' }}</el-descriptions-item>
<el-descriptions-item label="事务">{{ state.transactions[state.connection.TransactionId] }}</el-descriptions-item>
<el-descriptions-item label="协议">
<div>
<p>{{ state.connection.TransportName }}({{ state.protocolTypes[state.connection.ProtocolType] }}) - {{ state.types[state.connection.Type] }}</p>
<!-- <p> - {{ state.connection.SendBufferRemainingText }} - {{ state.connection.RecvBufferRemainingText }}</p> -->
</div>
</el-descriptions-item>
<el-descriptions-item label="SSL">{{ state.connection.SSL }}</el-descriptions-item>
<el-descriptions-item label="上传">
<div>
<p><span>{{ state.connection.SendBytesText }}</span></p>
</div>
</el-descriptions-item>
<el-descriptions-item label="下载">
<div>
<p><span>{{ state.connection.ReceiveBytesText }}</span></p>
</div>
</el-descriptions-item>
<el-descriptions-item label="中继">
<div>
<a v-if="state.connecting" href="javascript:;" class="a-line">
<span>操作中.</span><el-icon size="14" class="loading"><Loading /></el-icon>
</a>
<a v-else href="javascript:;" class="a-line" @click="handleNode">{{ state.nodesDic[state.connection.NodeId] || '选择节点' }}</a>
</div>
</el-descriptions-item>
<el-descriptions-item label="打洞">
<div>
<a v-if="state.connecting" href="javascript:;" class="a-line">
<span>操作中.</span><el-icon size="14" class="loading"><Loading /></el-icon>
</a>
<a v-else href="javascript:;" class="a-line" @click="handlep2p">尝试打洞</a>
</div>
</el-descriptions-item>
<el-descriptions-item label="延迟">{{ state.connection.Delay }}</el-descriptions-item>
<el-descriptions-item label="操作">
<div>
<AccessShow value="TunnelRemove">
<el-popconfirm confirm-button-text="确认" cancel-button-text="取消"
title="确定关闭此连接?" @confirm="handleDel">
<template #reference>
<el-button type="danger" size="small"><el-icon>
<Delete />
</el-icon></el-button>
</template>
</el-popconfirm>
</AccessShow>
</div>
</el-descriptions-item>
</el-descriptions>
</div>
</el-dialog>
<el-dialog v-model="state.showNodes" :title="$t('server.relayTitle')" width="98%" top="2vh">
@@ -136,13 +115,12 @@
<script>
import { reactive, watch, computed, onMounted, onUnmounted } from 'vue';
import { ElMessage } from 'element-plus';
import { useConnections, useForwardConnections, useSocks5Connections, useTuntapConnections } from './connections';
import { useConnections} from './connections';
import { Delete, Select, ArrowDown,Loading } from '@element-plus/icons-vue';
import { injectGlobalData } from '@/provide';
import { relayConnect, setRelaySubscribe } from '@/apis/relay';
import { useI18n } from 'vue-i18n';
import { useTunnel } from '../tunnel/tunnel';
import { tunnelConnect } from '@/apis/tunnel';
import { removeTunnelConnection, tunnelConnect } from '@/apis/tunnel';
export default {
props: ['modelValue'],
emits: ['change', 'update:modelValue'],
@@ -153,31 +131,22 @@ export default {
const globalData = injectGlobalData();
const connections = useConnections();
const forwardConnections = useForwardConnections();
const tuntapConnections = useTuntapConnections();
const socks5Connections = useSocks5Connections();
const tunnel = useTunnel();
const connection = computed(() =>connections.value.device.hook_connection? connections.value.device.hook_connection[connections.value.transactionId] || {} :{});
const state = reactive({
show: true,
protocolTypes: { 1: 'tcp', 2: 'udp', 4: 'msquic' },
types: { 0: '打洞', 1: '中继', 2: '节点' },
transactions: { 'forward': '端口转发', 'tuntap': '虚拟网卡', 'socks5': '代理转发' },
machineName: connections.value.currentName,
currentRow: {},
data: computed(() => {
return [
forwardConnections.value.list[connections.value.current],
tuntapConnections.value.list[connections.value.current],
socks5Connections.value.list[connections.value.current],
].filter(c => !!c);
}),
device: connections.value.device,
transactionId: connections.value.transactionId,
connecting:computed(()=>connections.value.device.hook_operating[connections.value.transactionId]),
connection:connection,
showNodes: false,
nodes: [],
nodesDic: {},
timer: 0,
relayOperatings:tunnel.value.relayOperatings,
p2pOperatings:tunnel.value.p2pOperatings,
timer: 0
});
watch(() => state.show, (val) => {
if (!val) {
@@ -187,8 +156,8 @@ export default {
}, 300);
}
});
const handleDel = (row) => {
row.removeFunc(row.RemoteMachineId).then(() => {
const handleDel = () => {
removeTunnelConnection(state.device.MachineId,state.transactionId).then(() => {
ElMessage.success(t('common.oper'));
}).catch(() => { });
}
@@ -207,25 +176,24 @@ export default {
});
}
const handlep2p = (row)=>{
const handlep2p = ()=>{
tunnelConnect({
ToMachineId:row.RemoteMachineId,
TransactionId:row.TransactionId,
DenyProtocols:row.TransactionId == 'tuntap' ? 4 : 2
ToMachineId:state.device.MachineId,
TransactionId:state.transactionId,
DenyProtocols:state.transactionId == 'tuntap' ? 4 : 2
}).then(()=>{
ElMessage.success(t('common.oper'));
}).catch(()=>{ElMessage.success(t('common.operFail'));})
}
const handleNode = (row) => {
state.currentRow = row;
const handleNode = () => {
state.showNodes = true;
}
const handleConnect = (id, protocol) => {
const json = {
FromMachineId: globalData.value.config.Client.Id,
TransactionId: state.currentRow.TransactionId,
ToMachineId: state.currentRow.RemoteMachineId,
TransactionId: state.transactionId,
ToMachineId: state.device.MachineId,
NodeId: id,
Protocol: protocol
};

View File

@@ -3,27 +3,27 @@
<template #default="{values}">
<el-table-column prop="tunnel" :label="$t('home.tunnel')" width="86">
<template #default="scope">
<template v-if="tunnel.list[scope.row.MachineId]">
<template v-if="scope.row.hook_tunnel">
<div>
<template v-if="tunnel.list[scope.row.MachineId].Net.CountryCode">
<template v-if="scope.row.hook_tunnel.Net.CountryCode">
<img
:title="`${tunnel.list[scope.row.MachineId].Net.CountryCode}、${tunnel.list[scope.row.MachineId].Net.City}`"
:title="`${scope.row.hook_tunnel.Net.CountryCode}、${scope.row.hook_tunnel.Net.City}`"
class="system"
:src="`https://unpkg.com/flag-icons@7.2.3/flags/4x3/${tunnel.list[scope.row.MachineId].Net.CountryCode.toLowerCase()}.svg`" />
:src="`https://unpkg.com/flag-icons@7.2.3/flags/4x3/${scope.row.hook_tunnel.Net.CountryCode.toLowerCase()}.svg`" />
</template>
<template v-else>
<img title="?" class="system" src="/system.svg" />
</template>
<template v-if="tunnel.list[scope.row.MachineId].Net.Isp">
<template v-if="scope.row.hook_tunnel.Net.Isp">
<img
:title="`${tunnel.list[scope.row.MachineId].Net.Isp}`"
class="system" :src="netImg(tunnel.list[scope.row.MachineId].Net)" />
:title="`${scope.row.hook_tunnel.Net.Isp}`"
class="system" :src="netImg(scope.row.hook_tunnel.Net)" />
</template>
<template v-else>
<img title="?" class="system" src="/system.svg" />
</template>
<template v-if="tunnel.list[scope.row.MachineId].Net.Nat">
<span class="nat" :title="tunnel.list[scope.row.MachineId].Net.Nat">{{ natMap[tunnel.list[scope.row.MachineId].Net.Nat] }}</span>
<template v-if="scope.row.hook_tunnel.Net.Nat">
<span class="nat" :title="scope.row.hook_tunnel.Net.Nat">{{ natMap[scope.row.hook_tunnel.Net.Nat] }}</span>
</template>
<template v-else>
<img title="?" class="system" src="/system.svg" />
@@ -31,10 +31,10 @@
</div>
<div class="flex">
<a href="javascript:;" class="a-line"
:class="{yellow:tunnel.list[scope.row.MachineId].NeedReboot}"
:class="{yellow:scope.row.hook_tunnel.NeedReboot}"
:title="$t('home.holeText')"
@click="handleTunnel(tunnel.list[scope.row.MachineId],scope.row,values)">
<span>{{$t('home.jump')}}:{{tunnel.list[scope.row.MachineId].RouteLevel}}+{{tunnel.list[scope.row.MachineId].RouteLevelPlus}}</span>
@click="handleTunnel(scope.row.hook_tunnel,scope.row,values)">
<span>{{$t('home.jump')}}:{{scope.row.hook_tunnel.RouteLevel}}+{{scope.row.hook_tunnel.RouteLevelPlus}}</span>
</a>
</div>
</template>
@@ -45,7 +45,6 @@
</template>
<script>
import { useTunnel } from './tunnel';
import { useConnections,useForwardConnections,useSocks5Connections,useTuntapConnections } from '../connection/connections';
import { injectGlobalData } from '@/provide';
import { computed } from 'vue';
import { ElMessage } from 'element-plus';
@@ -53,17 +52,13 @@ import {useI18n} from 'vue-i18n';
export default {
emits: ['edit','refresh'],
setup(props, { emit }) {
setup() {
const t = useI18n();
const globalData = injectGlobalData();
const machineId = computed(() => globalData.value.config.Client.Id);
const tunnel = useTunnel();
const connections = useConnections();
const forwardConnections = useForwardConnections();
const tuntapConnections = useTuntapConnections();
const socks5Connections = useSocks5Connections();
const imgMap = {
'chinanet':'chinanet.svg',
@@ -88,7 +83,6 @@ export default {
}
return `./system.svg`;
}
const natMap = {
"Unknown":'?',
"UnsupportedServer":'?',
@@ -101,43 +95,24 @@ export default {
"Symmetric":'4',
}
const connectionCount = (machineId)=>{
const length = [
forwardConnections.value.list[machineId],
tuntapConnections.value.list[machineId],
socks5Connections.value.list[machineId],
].filter(c=>!!c && c.Connected).length;
return length;
};
const handleTunnel = (_tunnel,row,access) => {
if(machineId.value === _tunnel.MachineId){
if(!access.TunnelChangeSelf){
ElMessage.success(t('common.access'));
return;
}
return;
}
}else{
if(!access.TunnelChangeOther){
ElMessage.success(t('common.access'));
return;
}
return;
}
}
_tunnel.device = row;
tunnel.value.current = _tunnel;
tunnel.value.showEdit = true;
}
const handleTunnelRefresh = ()=>{
emit('refresh');
}
const handleConnections = (row)=>{
connections.value.current = row.MachineId;
connections.value.currentName = row.MachineName;
connections.value.showEdit = true;
}
return {
tunnel, handleTunnel,handleTunnelRefresh,
connectionCount,handleConnections,netImg,natMap
handleTunnel,netImg,natMap
}
}
}

View File

@@ -92,7 +92,7 @@ export default {
});
const handleSave = () => {
const json = JSON.parse(JSON.stringify(tunnel.value.current));
const json = JSON.parse(JSON.stringify(tunnel.value.current,(key,value)=> key =='device'?'':value));
json.RouteLevel = +state.ruleForm.RouteLevel;
json.RouteLevelPlus = +state.ruleForm.RouteLevelPlus;
json.PortMapWan = +state.ruleForm.PortMapWan;

View File

@@ -0,0 +1,90 @@
import { inject, provide, ref } from "vue";
import { getTunnelConnections } from "@/apis/tunnel";
const connectionsSymbol = Symbol();
export const provideConnections = () => {
const connections = ref({
speedCache: {},
showEdit: false,
device:{},
transactionId:'',
timer: 0,
list: {},
hashcode: 0,
_updateRealTime: false,
updateRealTime: (value) => {
connections.value.hashcode = 0;
connections.value._updateRealTime = value;
}
});
provide(connectionsSymbol, connections);
const parseConnections = (_connections) => {
const result = {};
const caches = connections.value.speedCache;
for (let transactionId in _connections) {
for (let machineId in _connections[transactionId]) {
const connection = _connections[transactionId][machineId];
result[machineId] = result[machineId] || {};
result[machineId][transactionId] = connection;
const key = `${machineId}-${transactionId}`;
const cache = caches[key] || { SendBytes: 0, ReceiveBytes: 0 };
connection.SendBytesText = parseSpeed(connection.SendBytes - cache.SendBytes,'/s');
connection.ReceiveBytesText = parseSpeed(connection.ReceiveBytes - cache.ReceiveBytes,'/s');
connection.SendBufferRemainingText = parseSpeed(connection.SendBufferRemaining,'');
connection.RecvBufferRemainingText = parseSpeed(connection.RecvBufferRemaining || 0,'');
cache.SendBytes = connection.SendBytes;
cache.ReceiveBytes = connection.ReceiveBytes;
caches[key] = cache;
}
}
return result;
}
const parseSpeed = (num,subfix = '') => {
let index = 0;
while (num >= 1024) {
num /= 1024;
index++;
}
return `${num.toFixed(2)}${['B', 'KB', 'MB', 'GB', 'TB'][index]}${subfix}`;
}
const connectionDataFn = () => {
return new Promise((resolve, reject) => {
getTunnelConnections(connections.value.hashcode.toString()).then((res) => {
if (connections.value._updateRealTime == false)
connections.value.hashcode = res.HashCode;
if (res.List) {
connections.value.list = parseConnections(res.List);
resolve(true);
return;
}
resolve(false);
}).catch(() => {
resolve(false);
})
});
}
const connectionRefreshFn = () => {
}
const connectionProcessFn = (device,json) => {
Object.assign(json,{
hook_connection: connections.value.list[device.MachineId]
});
}
return {
connections, connectionDataFn, connectionProcessFn,connectionRefreshFn
}
}
export const useConnections = () => {
return inject(connectionsSymbol);
}

View File

@@ -1,75 +1,120 @@
import { relayOperating } from "@/apis/relay";
import { getTunnelInfo, tunnelRefresh,tunnelOperating } from "@/apis/tunnel";
import { injectGlobalData } from "@/provide";
import { inject, provide, ref } from "vue";
const tunnelSymbol = Symbol();
export const provideTunnel = () => {
const tunnel = ref({
timer1: 0,
p2pOperatings:{},
timer2: 0,
relayOperatings:{},
showEdit: false,
current: null,
timer: 0,
list: {},
hashcode: 0,
showMap: false
timer1: 0,
p2pOperatings:{},
hashcode1: 0,
timer2: 0,
relayOperatings:{},
hashcode2: 0,
showEdit: false,
current: null,
});
provide(tunnelSymbol, tunnel);
const _getTunnelInfo = () => {
clearTimeout(tunnel.value.timer);
getTunnelInfo(tunnel.value.hashcode.toString()).then((res) => {
tunnel.value.hashcode = res.HashCode;
if (res.List) {
tunnel.value.list = res.List;
}
tunnel.value.timer = setTimeout(_getTunnelInfo, 1060);
}).catch(() => {
tunnel.value.timer = setTimeout(_getTunnelInfo, 1060);
});
}
const getTunnelOperating = () => {
clearTimeout(tunnel.value.timer1);
tunnelOperating().then((res) => {
tunnel.p2pOperatings = res;
tunnel.value.timer1 = setTimeout(getTunnelOperating, 1080);
}).catch(() => {
tunnel.value.timer1 = setTimeout(getTunnelOperating, 1080);
});
}
const getRelayOperating = () => {
clearTimeout(tunnel.value.timer2);
relayOperating().then((res) => {
tunnel.relayOperatings = res;
tunnel.value.timer2 = setTimeout(getRelayOperating, 1040);
}).catch(() => {
tunnel.value.timer2 = setTimeout(getRelayOperating, 1040);
return new Promise((resolve, reject) => {
getTunnelInfo(tunnel.value.hashcode.toString()).then((res) => {
tunnel.value.hashcode = res.HashCode;
if (res.List) {
tunnel.value.list = res.List;
resolve(true);
return;
}
resolve(false);
}).catch(() => {
resolve(false);
});
});
}
const handleTunnelEdit = (_tunnel) => {
tunnel.value.current = _tunnel;
tunnel.value.showEdit = true;
const parseOperating = (operatings) => {
const json = {};
for(let key in operatings){
let arr = key.split('@');
if(!json[arr[0]]) json[arr[0]] = {};
json[arr[0]][arr[1]] = operatings[key];
}
return json;
}
const handleTunnelRefresh = () => {
const getTunnelOperating = () => {
return new Promise((resolve, reject) => {
tunnelOperating(tunnel.value.hashcode1.toString()).then((res) => {
tunnel.value.hashcode1 = res.HashCode;
if (res.List)
{
tunnel.value.p2pOperatings = parseOperating(res.List);
resolve(true);
return;
}
resolve(false);
}).catch(() => {
resolve(false);
});
});
}
const getRelayOperating = () => {
return new Promise((resolve, reject) => {
relayOperating(tunnel.value.hashcode2.toString()).then((res) => {
tunnel.value.hashcode2 = res.HashCode;
if (res.List)
{
tunnel.value.relayOperatings = parseOperating(res.List);
resolve(true);
return;
}
resolve(false);
}).catch(() => {
resolve(false);
});
});
}
const tunnelDataFn = () => {
return new Promise((resolve, reject) => {
Promise.all([_getTunnelInfo(), getTunnelOperating(), getRelayOperating()]).then((res) => {
resolve(res.filter(c=>c == true).length > 0);
}).catch(() => {
resolve(false);
});
});
}
const tunnelRefreshFn = () => {
tunnelRefresh();
}
const clearTunnelTimeout = () => {
clearTimeout(tunnel.value.timer);
clearTimeout(tunnel.value.timer1);
clearTimeout(tunnel.value.timer2);
const tunnelProcessFn = (device,json) => {
const p2p = tunnel.value.p2pOperatings[device.MachineId] || {};
const relay = tunnel.value.relayOperatings[device.MachineId]|| {};
const keys = [...new Set(Object.keys(p2p).concat(Object.keys(relay)))];
const _json = {};
for(let key of keys) {
_json[key] = p2p[key] || relay[key] || false;
}
Object.assign(json,{
hook_tunnel: tunnel.value.list[device.MachineId],
hook_operating: _json,
});
}
const sortTunnel = (asc) => {
return Object.values(tunnel.value.list).sort((a, b) => {
return a.RouteLevel + a.RouteLevelPlus - b.RouteLevel + b.RouteLevelPlus;
}).map(c => c.MachineId);
}
return {
tunnel, _getTunnelInfo,getTunnelOperating,getRelayOperating, handleTunnelEdit, handleTunnelRefresh, clearTunnelTimeout, sortTunnel
tunnel, tunnelDataFn,tunnelProcessFn,tunnelRefreshFn, sortTunnel
}
}
export const useTunnel = () => {

View File

@@ -1,10 +1,10 @@
<template>
<el-table-column prop="tuntap" :label="tuntap.show?$t('home.tuntap'):''" width="160">
<el-table-column prop="tuntap" :label="$t('home.tuntap')" width="160">
<template #header>
<a v-if="tuntap.show" href="javascript:;" class="a-line" @click="handleShowLease">{{$t('home.tuntap')}}</a>
<a href="javascript:;" class="a-line" @click="handleShowLease">{{$t('home.tuntap')}}</a>
</template>
<template #default="scope">
<div v-if="tuntap.show && tuntap.list[scope.row.MachineId]">
<div v-if="scope.row.hook_tuntap">
<TuntapShow :config="true" :item="scope.row"></TuntapShow>
</div>
</template>

View File

@@ -89,7 +89,8 @@ export default {
}
const getData = ()=>{
const json = JSON.parse(JSON.stringify(tuntap.value.current));
console.log(tuntap.value.current);
const json = JSON.parse(JSON.stringify(tuntap.value.current,(key,value)=> key =='device'?'':value ));
json.IP = state.ruleForm.IP.replace(/\s/g, '') || '0.0.0.0';
json.PrefixLength = +state.ruleForm.PrefixLength;
json.Gateway = state.ruleForm.Gateway;

View File

@@ -4,50 +4,50 @@
<div>
<div class="flex">
<div class="flex-1">
<ConnectionShow :data="connections.list[item.MachineId]" :row="item" transitionId="tuntap"></ConnectionShow>
<a href="javascript:;" class="a-line" @click="handleTuntapIP(tuntap.list[item.MachineId],values)" title="虚拟网卡IP">
<ConnectionShow :row="item" transactionId="tuntap"></ConnectionShow>
<a href="javascript:;" class="a-line" @click="handleTuntapIP(item.hook_tuntap,values)" title="虚拟网卡IP">
<template v-if="item.Connected">
<template v-if="tuntap.list[item.MachineId].SetupError">
<strong class="red" :title="`setup ${tuntap.list[item.MachineId].SetupError}`">{{ tuntap.list[item.MachineId].IP }}</strong>
<template v-if="item.hook_tuntap.SetupError">
<strong class="red" :title="`setup ${item.hook_tuntap.SetupError}`">{{ item.hook_tuntap.IP }}</strong>
</template>
<template v-else-if="tuntap.list[item.MachineId].Exists">
<strong class="red" title="IP存在冲突请使用新IP">{{ tuntap.list[item.MachineId].IP }}</strong>
<template v-else-if="item.hook_tuntap.Exists">
<strong class="red" title="IP存在冲突请使用新IP">{{ item.hook_tuntap.IP }}</strong>
</template>
<template v-else-if="tuntap.list[item.MachineId].Available == false">
<strong class="disable" title="IP不生效可能是设备不在线">{{ tuntap.list[item.MachineId].IP }}</strong>
<template v-else-if="item.hook_tuntap.Available == false">
<strong class="disable" title="IP不生效可能是设备不在线">{{ item.hook_tuntap.IP }}</strong>
</template>
<template v-else-if="tuntap.list[item.MachineId].NatError">
<strong class="yellow" :title="`nat ${tuntap.list[item.MachineId].NatError}`">{{ tuntap.list[item.MachineId].IP }}</strong>
<template v-else-if="item.hook_tuntap.NatError">
<strong class="yellow" :title="`nat ${item.hook_tuntap.NatError}`">{{ item.hook_tuntap.IP }}</strong>
</template>
<template v-else-if="tuntap.list[item.MachineId].AppNat && tuntap.list[item.MachineId].running">
<strong class="app-nat" :title="`虚拟网卡IP\r\n应用层DNAT`">{{ tuntap.list[item.MachineId].IP }}</strong>
<template v-else-if="item.hook_tuntap.AppNat && item.hook_tuntap.running">
<strong class="app-nat" :title="`虚拟网卡IP\r\n应用层DNAT`">{{ item.hook_tuntap.IP }}</strong>
</template>
<template v-else-if="tuntap.list[item.MachineId].running">
<strong class="green gateway" :title="`虚拟网卡IP\r\n系统NAT`">{{ tuntap.list[item.MachineId].IP }}</strong>
<template v-else-if="item.hook_tuntap.running">
<strong class="green gateway" :title="`虚拟网卡IP\r\n系统NAT`">{{ item.hook_tuntap.IP }}</strong>
</template>
<template v-else>
<strong>{{ tuntap.list[item.MachineId].IP }}</strong>
<strong>{{ item.hook_tuntap.IP }}</strong>
</template>
</template>
<template v-else>
<strong class="disable" title="IP不生效可能是设备不在线">{{ tuntap.list[item.MachineId].IP }}</strong>
<strong class="disable" title="IP不生效可能是设备不在线">{{ item.hook_tuntap.IP }}</strong>
</template>
</a>
</div>
<template v-if="tuntap.list[item.MachineId].loading">
<template v-if="item.hook_tuntap.loading">
<div>
<el-icon size="14" class="loading"><Loading /></el-icon>
</div>
</template>
<template v-else>
<el-switch :model-value="item.Connected && tuntap.list[item.MachineId].running" :loading="tuntap.list[item.MachineId].loading" disabled @click="handleTuntap(tuntap.list[item.MachineId],values)" size="small" inline-prompt active-text="😀" inactive-text="😣" >
<el-switch :model-value="item.Connected && item.hook_tuntap.running" :loading="item.hook_tuntap.loading" disabled @click="handleTuntap(item.hook_tuntap,values)" size="small" inline-prompt active-text="😀" inactive-text="😣" >
</el-switch>
</template>
</div>
<div>
<div>
<template v-for="(item1,index) in tuntap.list[item.MachineId].Lans" :key="index">
<template v-if="tuntap.list[item.MachineId].Available == false">
<template v-for="(item1,index) in item.hook_tuntap.Lans" :key="index">
<template v-if="item.hook_tuntap.Available == false">
<div class="flex disable" title="IP不生效可能是设备不在线">{{ item1.IP }} / {{ item1.PrefixLength }}</div>
</template>
<template v-else-if="item1.Disabled">
@@ -61,15 +61,15 @@
</template>
</template>
</div>
<template v-if="tuntap.list[item.MachineId].Any">
<template v-if="item.hook_tuntap.Any">
<div class="any green"><el-icon><Share /></el-icon></div>
</template>
<template v-if="showDelay">
<template v-if="tuntap.list[item.MachineId].Delay>=0 && tuntap.list[item.MachineId].Delay<=100">
<div class="delay green">{{ tuntap.list[item.MachineId].Delay }}ms</div>
<template v-if="item.hook_tuntap.Delay>=0 && item.hook_tuntap.Delay<=100">
<div class="delay green">{{ item.hook_tuntap.Delay }}ms</div>
</template>
<template>
<div class="delay yellow">{{ tuntap.list[item.MachineId].Delay }}ms</div>
<div class="delay yellow">{{ item.hook_tuntap.Delay }}ms</div>
</template>
</template>
</div>
@@ -85,8 +85,7 @@ import { useTuntap } from './tuntap';
import {Loading,Share} from '@element-plus/icons-vue'
import { injectGlobalData } from '@/provide';
import { computed } from 'vue';
import { useTuntapConnections } from '../connection/connections';
import ConnectionShow from '../connection/ConnectionShow.vue';
import ConnectionShow from '../tunnel/ConnectionShow.vue';
export default {
props:['item','config'],
components:{Loading,Share,ConnectionShow},
@@ -95,7 +94,6 @@ export default {
const tuntap = useTuntap();
const globalData = injectGlobalData();
const machineId = computed(() => globalData.value.config.Client.Id);
const connections = useTuntapConnections();
const showDelay = computed(()=>((globalData.value.config.Running.Tuntap || {Switch:0}).Switch & 2) == 2);
@@ -149,7 +147,7 @@ export default {
}
return {
item:computed(()=>props.item),tuntap,showDelay,connections, handleTuntap, handleTuntapIP,handleTuntapRefresh
item:computed(()=>props.item),tuntap,showDelay, handleTuntap, handleTuntapIP,handleTuntapRefresh
}
}
}

View File

@@ -4,7 +4,6 @@ import { getTuntapInfo, refreshTuntap, subscribePing } from "@/apis/tuntap";
const tuntapSymbol = Symbol();
export const provideTuntap = () => {
const tuntap = ref({
show: true,
timer: 0,
showEdit: false,
current: null,
@@ -22,40 +21,39 @@ export const provideTuntap = () => {
const reg = /iphone|samsung|vivo|oppo|google|huawei|xiaomi|ios|android|windows|ubuntu|openwrt|armbian|archlinux|fedora|centos|rocky|alpine|debian|linux|docker/g;
const _getTuntapInfo = () => {
clearTimeout(tuntap.value.timer);
getTuntapInfo(tuntap.value.hashcode.toString()).then((res) => {
tuntap.value.hashcode = res.HashCode;
if (res.List) {
for (let j in res.List) {
const systemStr = res.List[j].SystemInfo.toLowerCase();
const tuntapDataFn = () => {
return new Promise((resolve, reject) => {
getTuntapInfo(tuntap.value.hashcode.toString()).then((res) => {
const match =[...new Set(systemStr.match(reg))];
Object.assign(res.List[j], {
running: res.List[j].Status == 2,
loading: res.List[j].Status == 1,
systems: match
});
subscribePing();
tuntap.value.hashcode = res.HashCode;
if (res.List) {
for (let j in res.List) {
const systemStr = res.List[j].SystemInfo.toLowerCase();
const match =[...new Set(systemStr.match(reg))];
Object.assign(res.List[j], {
running: res.List[j].Status == 2,
loading: res.List[j].Status == 1,
systems: match
});
}
tuntap.value.list = res.List;
resolve(true);
return;
}
tuntap.value.list = res.List;
}
tuntap.value.timer = setTimeout(_getTuntapInfo, 1100);
subscribePing();
}).catch((e) => {
tuntap.value.timer = setTimeout(_getTuntapInfo, 1100);
resolve(false);
}).catch((e) => {
resolve(false);
});
});
}
const handleTuntapEdit = (_tuntap) => {
tuntap.value.current = _tuntap;
tuntap.value.showEdit = true;
}
const handleTuntapRefresh = () => {
}
const tuntapRefreshFn = () => {
refreshTuntap();
}
const clearTuntapTimeout = () => {
clearTimeout(tuntap.value.timer);
tuntap.value.timer = 0;
const tuntapProcessFn = (device,json) => {
Object.assign(json,{
hook_tuntap: tuntap.value.list[device.MachineId]
});
}
const getTuntapMachines = (name) => {
return Object.values(tuntap.value.list)
@@ -79,7 +77,7 @@ export const provideTuntap = () => {
return {
tuntap, _getTuntapInfo, handleTuntapEdit, handleTuntapRefresh, clearTuntapTimeout, getTuntapMachines, sortTuntapIP
tuntap, tuntapDataFn, tuntapProcessFn, tuntapRefreshFn, getTuntapMachines, sortTuntapIP
}
}

View File

@@ -4,19 +4,19 @@
<a href="javascript:;" class="download" @click="handleUpdate(values)" :title="updaterText" :class="updaterColor">
<span>
<span>{{item.Version}}</span>
<template v-if="updater.list[item.MachineId]">
<template v-if="updater.list[item.MachineId].Status == 1">
<template v-if="item.hook_updater">
<template v-if="item.hook_updater.Status == 1">
<el-icon size="14" class="loading"><Loading /></el-icon>
</template>
<template v-else-if="updater.list[item.MachineId].Status == 2">
<template v-else-if="item.hook_updater.Status == 2">
<el-icon size="14"><Download /></el-icon>
</template>
<template v-else-if="updater.list[item.MachineId].Status == 3 || updater.list[item.MachineId].Status == 5">
<template v-else-if="item.hook_updater.Status == 3 || item.hook_updater.Status == 5">
<el-icon size="14" class="loading"><Loading /></el-icon>
<span class="progress" v-if="updater.list[item.MachineId].Length ==0">0%</span>
<span class="progress" v-else>{{parseInt(updater.list[item.MachineId].Current/updater.list[item.MachineId].Length*100)}}%</span>
<span class="progress" v-if="item.hook_updater.Length ==0">0%</span>
<span class="progress" v-else>{{parseInt(item.hook_updater.Current/item.hook_updater.Length*100)}}%</span>
</template>
<template v-else-if="updater.list[item.MachineId].Status == 6">
<template v-else-if="item.hook_updater.Status == 6">
<el-icon size="14" class="yellow"><CircleCheck /></el-icon>
</template>
</template>
@@ -43,21 +43,20 @@ export default {
components:{Download,Loading,CircleCheck},
setup (props) {
const {t} = useI18n();
const {t} = useI18n();
const globalData = injectGlobalData();
const updater = useUpdater();
const serverVersion = computed(()=>globalData.value.signin.Version);
const updaterVersion = computed(()=>updater.value.current.Version);
const updaterText = computed(()=>{
if(!updater.value.list[props.item.MachineId]){
if(!props.item.hook_updater){
return '未检测到更新';
}
if(updater.value.list[props.item.MachineId].Status <= 2) {
if(props.item.hook_updater.Status <= 2) {
return props.item.Version != serverVersion.value
? `与服务器版本(${serverVersion.value})不一致,建议更新`
: updaterVersion.value != props.item.Version
? `不是最新版本(${updaterVersion.value}),建议更新`
: props.item.hook_updater.Version != props.item.Version
? `不是最新版本(${props.item.hook_updater.Version}),建议更新`
: `是最新版本,但我无法阻止你喜欢更新`
}
return {
@@ -65,12 +64,12 @@ export default {
4:'已下载',
5:'正在解压',
6:'已解压,请重启',
}[updater.value.list[props.item.MachineId].Status];
}[props.item.hook_updater.Status];
})
const updaterColor = computed(()=>{
return props.item.Version != serverVersion.value
? 'red'
: updater.value.list[props.item.MachineId] && updaterVersion.value != props.item.Version
: props.item.hook_updater && props.item.hook_updater.Version != props.item.Version
? 'yellow' :'green'
})
const handleUpdate = (access)=>{
@@ -87,18 +86,17 @@ export default {
return;
}
const updateInfo = updater.value.list[props.item.MachineId];
if(!updateInfo){
if(!props.item.hook_updater){
ElMessage.error('未检测到更新');
return;
}
//未检测,检测中,下载中,解压中
if([0,1,3,5].indexOf(updateInfo.Status)>=0){
if([0,1,3,5].indexOf(props.item.hook_updater.Status)>=0){
ElMessage.error('操作中,请稍后!');
return;
}
//已解压
if(updateInfo.Status == 6){
if(props.item.hook_updater.Status == 6){
ElMessageBox.confirm('确定关闭程序吗?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
@@ -108,12 +106,12 @@ export default {
}).catch(() => {});
return;
}
updater.value.show = updateInfo.Status == 2;
updater.value.show = props.item.hook_updater.Status == 2;
}
return {
item:computed(()=>props.item),updater,updaterText,updaterColor,handleUpdate
updater,updaterText,updaterColor,handleUpdate
}
}
}

View File

@@ -48,16 +48,14 @@ export default {
const globalData = injectGlobalData();
const updater = useUpdater();
const serverVersion = computed(()=>globalData.value.signin.Version);
const updaterVersion = computed(()=>updater.value.current.Version);
const versions = [
{label:`${updaterVersion.value}【最新版本】`,value:updaterVersion.value},
{label:`${updater.value.device.hook_updater.Version}【最新版本】`,value:updater.value.device.hook_updater.Version},
{label:`${serverVersion.value}【服务器版本】`,value:serverVersion.value},
].filter(c=>c.value);
const state = reactive({
show: true,
type:'',
version:versions[0] || '',
version:versions[0] || {},
versions:versions,
msg:[]
});
@@ -104,7 +102,7 @@ export default {
});
return {
state,getTypes,updater,handleUpdate
state,getTypes,handleUpdate
}
}
}

View File

@@ -4,58 +4,55 @@ import { inject, provide, ref } from "vue";
const updaterSymbol = Symbol();
export const provideUpdater = () => {
const globalData = injectGlobalData();
const updater = ref({
timer: 0,
list: {},
hashcode: 0,
current: { Version: '', Msg: [], DateTime: '', Status: 0, Length: 0, Current: 0 },
subscribeTimer: 0,
device: {},
show: false,
});
provide(updaterSymbol, updater);
const _getUpdater = () => {
clearTimeout(updater.value.timer);
getUpdater(updater.value.hashcode.toString()).then((res) => {
updater.value.hashcode = res.HashCode;
if (res.List) {
const self = Object.values(res.List).filter(c => !!c.Version)[0];
if (self) {
Object.assign(updater.value.current, {
Version: self.Version,
Status: self.Status,
Length: self.Length,
Current: self.Current
});
globalData.value.updater = updater.value.current;
const updaterDataFn = () => {
return new Promise((resolve, reject) => {
getUpdater(updater.value.hashcode.toString()).then((res) => {
updater.value.hashcode = res.HashCode;
if (res.List) {
updater.value.list = res.List;
resolve(true);
return;
}
updater.value.list = res.List;
}
updater.value.timer = setTimeout(_getUpdater, 800);
}).catch(() => {
updater.value.timer = setTimeout(_getUpdater, 800);
resolve(false);
}).catch(() => {
resolve(false);
});
});
}
const _subscribeUpdater = () => {
const updaterRefreshFn = () => {
}
const updaterProcessFn = (device,json) => {
Object.assign(json,{
hook_updater: updater.value.list[device.MachineId] || {}
});
}
const updaterSubscribe = () => {
subscribeUpdater().then(() => {
updater.value.subscribeTimer = setTimeout(_subscribeUpdater, 5000);
updater.value.subscribeTimer = setTimeout(updaterSubscribe, 5000);
}).catch(() => {
updater.value.subscribeTimer = setTimeout(_subscribeUpdater, 5000);
updater.value.subscribeTimer = setTimeout(updaterSubscribe, 5000);
});
}
const clearUpdaterTimeout = () => {
clearTimeout(updater.value.timer);
const updaterClearTimeout = () => {
clearTimeout(updater.value.subscribeTimer);
}
return {
updater, _getUpdater, _subscribeUpdater, clearUpdaterTimeout
updater, updaterDataFn, updaterProcessFn,updaterRefreshFn,updaterSubscribe, updaterClearTimeout
}
}
export const useUpdater = () => {

View File

@@ -3,17 +3,17 @@
<Sort @sort="handleSortChange"></Sort>
<el-table :data="devices.page.List" stripe border style="width: 100%" :height="`${state.height}px`" size="small">
<Device @refresh="handlePageRefresh"></Device>
<Tunnel @refresh="handleTunnelRefresh"></Tunnel>
<Tunnel @refresh="deviceRefreshHook('tunnel')"></Tunnel>
<Tuntap></Tuntap>
<Socks5 @refresh="handleSocks5Refresh"></Socks5>
<Socks5 @refresh="deviceRefreshHook('socks5')"></Socks5>
<Forward ></Forward>
<Oper @refresh="handlePageRefresh"></Oper>
</el-table>
<div class="page" :class="{'t-c':globalData.isPc}">
<div class="page" :class="{'t-c':state.center}">
<div class="page-wrap">
<el-pagination small background :total="devices.page.Count"
:pager-count="globalData.isPc?7:3"
:layout="globalData.isPc?'total,sizes,prev,pager, next':'prev, pager, next'"
:pager-count="state.paperCount"
:layout="state.paperLayout"
:page-size="devices.page.Request.Size" :current-page="devices.page.Request.Page"
@current-change="handlePageChange" @size-change="handlePageSizeChange"
:page-sizes="[10, 20, 50, 100,255]" />
@@ -21,11 +21,11 @@
</div>
<DeviceEdit v-if="devices.showDeviceEdit" v-model="devices.showDeviceEdit" @change="handlePageChange" :data="devices.deviceInfo"></DeviceEdit>
<AccessEdit v-if="devices.showAccessEdit" v-model="devices.showAccessEdit" @change="handlePageChange" :data="devices.deviceInfo"></AccessEdit>
<TunnelEdit v-if="tunnel.showEdit" v-model="tunnel.showEdit" @change="handleTunnelRefresh"></TunnelEdit>
<TunnelEdit v-if="tunnel.showEdit" v-model="tunnel.showEdit" @change="deviceRefreshHook('tunnel')"></TunnelEdit>
<ConnectionsEdit v-if="connections.showEdit" v-model="connections.showEdit" ></ConnectionsEdit>
<TuntapEdit v-if="tuntap.showEdit" v-model="tuntap.showEdit" @change="handleTuntapRefresh"></TuntapEdit>
<TuntapLease v-if="tuntap.showLease" v-model="tuntap.showLease" @change="handleTuntapRefresh"></TuntapLease>
<Socks5Edit v-if="socks5.showEdit" v-model="socks5.showEdit" @change="handleSocks5Refresh"></Socks5Edit>
<TuntapEdit v-if="tuntap.showEdit" v-model="tuntap.showEdit" @change="deviceRefreshHook('tuntap')"></TuntapEdit>
<TuntapLease v-if="tuntap.showLease" v-model="tuntap.showLease" @change="deviceRefreshHook('tuntap')"></TuntapLease>
<Socks5Edit v-if="socks5.showEdit" v-model="socks5.showEdit" @change="deviceRefreshHook('socks5')"></Socks5Edit>
<ForwardEdit v-if="forward.showEdit" v-model="forward.showEdit" ></ForwardEdit>
<SForwardEdit v-if="sforward.showEdit" v-model="sforward.showEdit" ></SForwardEdit>
<UpdaterConfirm v-if="updater.show" v-model="updater.show" ></UpdaterConfirm>
@@ -45,7 +45,6 @@ import { ElMessage } from 'element-plus'
import Sort from './Sort.vue'
import Device from '../../../components/device/Device.vue'
import DeviceEdit from '../../../components/device/DeviceEdit.vue'
import { provideDevices } from '../../../components/device/devices'
@@ -53,12 +52,6 @@ import { provideDevices } from '../../../components/device/devices'
import AccessEdit from '../../../components/accesss/AccessEdit.vue'
import { provideAccess } from '../../../components/accesss/access'
import Tuntap from '../../../components/tuntap/Tuntap.vue'
import TuntapEdit from '../../../components/tuntap/TuntapEdit.vue'
import TuntapLease from '../../../components/tuntap/TuntapLease.vue'
import { provideTuntap } from '../../../components/tuntap/tuntap'
import Socks5 from '../../../components/socks5/Socks5.vue'
import Socks5Edit from '../../../components/socks5/Socks5Edit.vue'
import { provideSocks5 } from '../../../components/socks5/socks5'
@@ -67,18 +60,25 @@ import Tunnel from '../../../components/tunnel/Tunnel.vue'
import TunnelEdit from '../../../components/tunnel/TunnelEdit.vue'
import { provideTunnel } from '../../../components/tunnel/tunnel'
import { provideUpdater } from '../../../components/updater/updater'
import UpdaterConfirm from '../../../components/updater/UpdaterConfirm.vue'
import Tuntap from '../../../components/tuntap/Tuntap.vue'
import TuntapEdit from '../../../components/tuntap/TuntapEdit.vue'
import TuntapLease from '../../../components/tuntap/TuntapLease.vue'
import { provideTuntap } from '../../../components/tuntap/tuntap'
import ConnectionsEdit from '../../../components/tunnel/ConnectionsEdit.vue'
import { provideConnections } from '../../../components/tunnel/connections'
import Forward from '../../../components/forward/Forward.vue'
import ForwardEdit from '../../../components/forward/ForwardEdit.vue'
import { provideForward } from '../../../components/forward/forward'
import SForwardEdit from '../../../components/forward/SForwardEdit.vue'
import { provideSforward } from '../../../components/forward/sforward'
import ConnectionsEdit from '../../../components/connection/ConnectionsEdit.vue'
import { provideConnections } from '../../../components/connection/connections'
import { provideUpdater } from '../../../components/updater/updater'
import UpdaterConfirm from '../../../components/updater/UpdaterConfirm.vue'
import { provideFlow } from '../../../components/flow/flow'
import Stopwatch from '../../../components/flow/stopwatch/Index.vue'
import OperFlow from '../../../components/flow/OperDialog.vue'
@@ -114,29 +114,37 @@ export default {
const globalData = injectGlobalData();
const state = reactive({
height: computed(()=>globalData.value.height-90)
height: computed(()=>globalData.value.height-90),
center: computed(()=>globalData.value.isPc),
paperCount: computed(()=>globalData.value.isPc?7:3),
paperLayout: computed(()=>globalData.value.isPc?'total,sizes,prev,pager, next':'prev, pager, next'),
});
const {devices,addDeviceHook, startDeviceProcess, handlePageChange, handlePageSizeChange,clearDevicesTimeout,setSort} = provideDevices();
const {tuntap,_getTuntapInfo,handleTuntapRefresh,clearTuntapTimeout,getTuntapMachines,sortTuntapIP} = provideTuntap();
const {socks5,_getSocks5Info,handleSocks5Refresh,clearSocks5Timeout,getSocks5Machines,sortSocks5} = provideSocks5();
const {tunnel,_getTunnelInfo,getTunnelOperating,getRelayOperating,handleTunnelRefresh,clearTunnelTimeout,sortTunnel} = provideTunnel();
const {devices,deviceAddHook,deviceRefreshHook, deviceStartProcess, handlePageChange, handlePageSizeChange,deviceClearTimeout,setSort} = provideDevices();
const {forward} = provideForward();
const {sforward} = provideSforward();
const {connections,_getForwardConnections,_getTuntapConnections,_getSocks5Connections, clearConnectionsTimeout } = provideConnections();
const {updater,_getUpdater,_subscribeUpdater,clearUpdaterTimeout} = provideUpdater();
const {flow} = provideFlow();
const {accessDataFn,accessProcessFn,accessRefreshFn} = provideAccess();
const {oper} = provideOper();
const {decenter,counterDataFn,counterProcessFn,counterRefreshFn} = provideDecenter();
const {firewall} = provideFirewall();
const {wakeup} = provideWakeup();
const {transport} = provideTransport();
const {action} = provideAction();
addDeviceHook('access',accessDataFn,accessProcessFn,accessRefreshFn)
addDeviceHook('counter',counterDataFn,counterProcessFn,counterRefreshFn)
const {accessDataFn,accessProcessFn,accessRefreshFn} = provideAccess();
deviceAddHook('access',accessDataFn,accessProcessFn,accessRefreshFn);
const {decenter,counterDataFn,counterProcessFn,counterRefreshFn} = provideDecenter();
deviceAddHook('counter',counterDataFn,counterProcessFn,counterRefreshFn);
const {socks5,socks5DataFn,socks5ProcessFn,socks5RefreshFn,getSocks5Machines,sortSocks5} = provideSocks5();
deviceAddHook('socks5',socks5DataFn,socks5ProcessFn,socks5RefreshFn);
const {tunnel,tunnelDataFn,tunnelProcessFn,tunnelRefreshFn,sortTunnel} = provideTunnel();
deviceAddHook('tunnel',tunnelDataFn,tunnelProcessFn,tunnelRefreshFn);
const {updater, updaterDataFn, updaterProcessFn,updaterRefreshFn,updaterSubscribe, updaterClearTimeout} = provideUpdater();
deviceAddHook('updater',updaterDataFn,updaterProcessFn,updaterRefreshFn);
const {tuntap,tuntapDataFn,tuntapProcessFn,tuntapRefreshFn,getTuntapMachines,sortTuntapIP} = provideTuntap();
deviceAddHook('tuntap',tuntapDataFn,tuntapProcessFn,tuntapRefreshFn);
const {connections,connectionDataFn,connectionProcessFn,connectionRefreshFn } = provideConnections();
deviceAddHook('connection',connectionDataFn,connectionProcessFn,connectionRefreshFn);
const handleSortChange = (row)=>{
devices.page.Request.Prop = row.prop;
@@ -183,51 +191,25 @@ export default {
devices.page.Request.Ids = [];
}
handlePageChange();
handleTunnelRefresh();
handleTuntapRefresh();
handleSocks5Refresh();
handleForwardRefresh();
handleSForwardRefresh();
handleAccesssRefresh();
ElMessage.success({message:'刷新成功',grouping:true});
}
onMounted(() => {
handlePageChange();
handleTunnelRefresh();
handleTuntapRefresh();
handleSocks5Refresh();
startDeviceProcess();
_getTuntapInfo();
_getSocks5Info();
_getTunnelInfo();
getTunnelOperating();
getRelayOperating();
_getForwardConnections();
_getTuntapConnections();
_getSocks5Connections();
_getUpdater();
_subscribeUpdater();
deviceStartProcess();
updaterSubscribe();
});
onUnmounted(() => {
clearDevicesTimeout();
clearConnectionsTimeout();
clearTuntapTimeout();
clearSocks5Timeout();
clearTunnelTimeout();
clearUpdaterTimeout();
deviceClearTimeout();
updaterClearTimeout();
});
return {
state,globalData,devices,handleSortChange, handlePageRefresh, handlePageChange,handlePageSizeChange,
state,devices,deviceRefreshHook,handleSortChange, handlePageRefresh, handlePageChange,handlePageSizeChange,
tuntap,
socks5, handleSocks5Refresh,
tunnel,connections, handleTunnelRefresh,
socks5,
tunnel,connections,
forward,
sforward,
updater,flow,oper,firewall,wakeup,transport,action

View File

@@ -3,20 +3,10 @@
<el-table-column prop="MachineId" :label="$t('home.device')" width="90" sortable="custom" ></el-table-column>
<el-table-column prop="Version" :label="$t('home.version')" width="90" sortable="custom"></el-table-column>
<el-table-column prop="tunnel" :label="$t('home.tunnel')" width="86" sortable="custom"></el-table-column>
<el-table-column v-if="tuntap.show" prop="tuntap" :label="$t('home.tuntapIP')" width="160" sortable="custom"></el-table-column>
<el-table-column v-if="socks5.show" prop="socks5" :label="$t('home.proxy')" width="160" sortable="custom"></el-table-column>
<el-table-column label="columns" fixed="right">
<el-table-column prop="tuntap" :label="$t('home.tuntapIP')" width="160" sortable="custom"></el-table-column>
<el-table-column prop="socks5" :label="$t('home.proxy')" width="160" sortable="custom"></el-table-column>
<el-table-column label="..." fixed="right">
<template #header>
<el-dropdown class="show-columns">
<span class="el-dropdown-link">{{$t('home.showItems')}}<el-icon><ArrowDownBold /></el-icon></span>
<template #dropdown>
<el-dropdown-menu>
<el-dropdown-item><el-checkbox v-model="tuntap.show" @change="handleTuntapShow" size="small" style="margin-right:1rem">{{$t('home.tuntap')}}</el-checkbox> </el-dropdown-item>
<el-dropdown-item><el-checkbox v-model="socks5.show" @change="handleSocks5Show" size="small" style="margin-right:1rem">{{$t('home.proxy')}}</el-checkbox> </el-dropdown-item>
<el-dropdown-item><el-checkbox v-model="forward.show" @change="handleForwardShow" size="small" style="margin-right:0rem">{{$t('home.forward')}}</el-checkbox></el-dropdown-item>
</el-dropdown-menu>
</template>
</el-dropdown>
</template>
</el-table-column>
</el-table>

View File

@@ -4,7 +4,7 @@
<div class="head">
<Head></Head>
</div>
<div class="body flex-1 relative">
<div class="body flex-1 relative" id="main-body">
<List></List>
</div>
<div class="status">

View File

@@ -15,7 +15,7 @@
</div>
</dt>
<dd class="tuntap">
<TuntapShow v-if="tuntap.list[item.MachineId]" :item="item"></TuntapShow>
<TuntapShow v-if="item.hook_tuntap" :item="item"></TuntapShow>
</dd>
</dl>
</li>
@@ -32,53 +32,44 @@
</div>
</template>
<script>
import { injectGlobalData } from '@/provide.js'
import { reactive, onMounted, onUnmounted } from 'vue'
import { StarFilled} from '@element-plus/icons-vue'
import { provideTuntap } from '../../components/tuntap/tuntap'
import { provideDevices } from '../../components/device/devices'
import { provideUpdater } from '../../components/updater/updater'
import UpdaterBtn from '../../components/updater/UpdaterBtn.vue'
import DeviceName from '../../components/device/DeviceName.vue'
import TuntapShow from '../../components/tuntap/TuntapShow.vue';
import { provideConnections } from '../../components/connection/connections'
import { provideTunnel } from '@/views/components/tunnel/tunnel'
import { provideConnections } from '../../components/tunnel/connections'
import { provideAccess } from '@/views/components/accesss/access'
import { provideUpdater } from '@/views/components/updater/updater'
export default {
components: {StarFilled,UpdaterBtn,DeviceName,TuntapShow},
setup(props) {
const globalData = injectGlobalData();
const state = reactive({
});
const {devices, machineId, _getSignList, _getSignList1,
handlePageChange, handlePageSizeChange, clearDevicesTimeout} = provideDevices();
const {tuntap,_getTuntapInfo,handleTuntapRefresh,clearTuntapTimeout,handleTuntapEdit,sortTuntapIP} = provideTuntap();
const {_getUpdater,_subscribeUpdater,clearUpdaterTimeout} = provideUpdater();
provideTunnel();
const connections = provideConnections();
const {devices,deviceAddHook,deviceRefreshHook, deviceStartProcess, handlePageChange, handlePageSizeChange,deviceClearTimeout,setSort} = provideDevices();
const {accessDataFn,accessProcessFn,accessRefreshFn} = provideAccess();
deviceAddHook('access',accessDataFn,accessProcessFn,accessRefreshFn);
const {updater, updaterDataFn, updaterProcessFn,updaterRefreshFn,updaterSubscribe, updaterClearTimeout} = provideUpdater();
deviceAddHook('updater',updaterDataFn,updaterProcessFn,updaterRefreshFn);
const {tuntap,tuntapDataFn,tuntapProcessFn,tuntapRefreshFn,getTuntapMachines,sortTuntapIP} = provideTuntap();
deviceAddHook('tuntap',tuntapDataFn,tuntapProcessFn,tuntapRefreshFn);
const {connections,connectionDataFn,connectionProcessFn,connectionRefreshFn } = provideConnections();
deviceAddHook('connection',connectionDataFn,connectionProcessFn,connectionRefreshFn);
onMounted(() => {
handlePageChange();
handleTuntapRefresh();
_getSignList();
_getSignList1();
_getTuntapInfo();
_getUpdater();
_subscribeUpdater();
deviceStartProcess();
});
onUnmounted(() => {
clearDevicesTimeout();
clearTuntapTimeout();
clearUpdaterTimeout();
deviceClearTimeout();
updaterClearTimeout();
});
return {
state,devices, machineId, handlePageChange,handlePageSizeChange,
state,devices, handlePageChange,handlePageSizeChange,
tuntap
}
}