mirror of
https://github.com/snltty/linker.git
synced 2025-10-20 07:54:36 +08:00
sync
This commit is contained in:
@@ -118,10 +118,8 @@ namespace linker.tunnel
|
|||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public async Task<ITunnelConnection> ConnectAsync(string remoteMachineId, string transactionId)
|
public async Task<ITunnelConnection> ConnectAsync(string remoteMachineId, string transactionId)
|
||||||
{
|
{
|
||||||
if (connectingDic.TryAdd(remoteMachineId, true) == false)
|
if (connectingDic.TryAdd(remoteMachineId, true) == false) return null;
|
||||||
{
|
if (IsBackground(remoteMachineId, transactionId)) return null;
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -221,7 +219,6 @@ namespace linker.tunnel
|
|||||||
{
|
{
|
||||||
connectingDic.TryRemove(remoteMachineId, out _);
|
connectingDic.TryRemove(remoteMachineId, out _);
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -393,5 +390,54 @@ namespace linker.tunnel
|
|||||||
|
|
||||||
tunnelTransportInfo.RemoteEndPoints = eps;
|
tunnelTransportInfo.RemoteEndPoints = eps;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
private ConcurrentDictionary<string, bool> backgroundDic = new ConcurrentDictionary<string, bool>();
|
||||||
|
public void StartBackground(string remoteMachineId, string transactionId)
|
||||||
|
{
|
||||||
|
if (IsBackground(remoteMachineId, transactionId)) return;
|
||||||
|
AddBackground(remoteMachineId, transactionId);
|
||||||
|
Task.Run(async () =>
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
for (int i = 0; i < 10; i++)
|
||||||
|
{
|
||||||
|
await Task.Delay(3000);
|
||||||
|
|
||||||
|
ITunnelConnection connection = await ConnectAsync(remoteMachineId, transactionId);
|
||||||
|
if (connection != null)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
RemoveBackground(remoteMachineId, transactionId);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
private void AddBackground(string remoteMachineId, string transactionId)
|
||||||
|
{
|
||||||
|
backgroundDic.TryAdd(GetBackgroundKey(remoteMachineId, transactionId), true);
|
||||||
|
}
|
||||||
|
private void RemoveBackground(string remoteMachineId, string transactionId)
|
||||||
|
{
|
||||||
|
backgroundDic.TryRemove(GetBackgroundKey(remoteMachineId, transactionId), out _);
|
||||||
|
}
|
||||||
|
private bool IsBackground(string remoteMachineId, string transactionId)
|
||||||
|
{
|
||||||
|
return backgroundDic.ContainsKey(GetBackgroundKey(remoteMachineId, transactionId));
|
||||||
|
}
|
||||||
|
private string GetBackgroundKey(string remoteMachineId, string transactionId)
|
||||||
|
{
|
||||||
|
return $"{remoteMachineId}@{transactionId}";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -277,6 +277,15 @@ namespace linker.tunnel.proxy
|
|||||||
{
|
{
|
||||||
GC.Collect();
|
GC.Collect();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ConnectId GetTcpConnectId()
|
||||||
|
{
|
||||||
|
return new ConnectId(Proxy.ConnectId, Connection.RemoteMachineId.GetHashCode(), Connection.TransactionId.GetHashCode(), (byte)Proxy.Direction);
|
||||||
|
}
|
||||||
|
public ConnectIdUdp GetUdpConnectId()
|
||||||
|
{
|
||||||
|
return new ConnectIdUdp(Proxy.ConnectId, Proxy.SourceEP, Connection.RemoteMachineId.GetHashCode(), Connection.TransactionId.GetHashCode());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -5,6 +5,7 @@ using System.Buffers;
|
|||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
using System.Net.Sockets;
|
using System.Net.Sockets;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
namespace linker.tunnel.proxy
|
namespace linker.tunnel.proxy
|
||||||
{
|
{
|
||||||
@@ -106,7 +107,7 @@ namespace linker.tunnel.proxy
|
|||||||
}
|
}
|
||||||
token.Proxy.Step = ProxyStep.Forward;
|
token.Proxy.Step = ProxyStep.Forward;
|
||||||
//绑定
|
//绑定
|
||||||
tcpConnections.TryAdd(new ConnectId(token.Proxy.ConnectId, token.Connection.GetHashCode(), (byte)ProxyDirection.Reverse), token);
|
tcpConnections.TryAdd(token.GetConnectId(ProxyDirection.Reverse), token);
|
||||||
}
|
}
|
||||||
else if (closeConnect)
|
else if (closeConnect)
|
||||||
{
|
{
|
||||||
@@ -253,12 +254,12 @@ namespace linker.tunnel.proxy
|
|||||||
|
|
||||||
token.Socket.EndConnect(result);
|
token.Socket.EndConnect(result);
|
||||||
token.Socket.KeepAlive();
|
token.Socket.KeepAlive();
|
||||||
|
|
||||||
if (state.Data.Length > 0)
|
if (state.Data.Length > 0)
|
||||||
{
|
{
|
||||||
await token.Socket.SendAsync(state.Data.AsMemory(0, state.Length), SocketFlags.None).ConfigureAwait(false);
|
await token.Socket.SendAsync(state.Data.AsMemory(0, state.Length), SocketFlags.None).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
tcpConnections.TryAdd(new ConnectId(token.Proxy.ConnectId, token.Connection.GetHashCode(), (byte)ProxyDirection.Forward), token);
|
tcpConnections.TryAdd(token.GetConnectId(ProxyDirection.Forward), token);
|
||||||
|
|
||||||
await SendToConnection(token).ConfigureAwait(false);
|
await SendToConnection(token).ConfigureAwait(false);
|
||||||
token.Proxy.Step = ProxyStep.Forward;
|
token.Proxy.Step = ProxyStep.Forward;
|
||||||
@@ -286,7 +287,7 @@ namespace linker.tunnel.proxy
|
|||||||
{
|
{
|
||||||
if (tunnelToken.Proxy.Protocol == ProxyProtocol.Tcp)
|
if (tunnelToken.Proxy.Protocol == ProxyProtocol.Tcp)
|
||||||
{
|
{
|
||||||
ConnectId connectId = new ConnectId(tunnelToken.Proxy.ConnectId, tunnelToken.Connection.GetHashCode(), (byte)tunnelToken.Proxy.Direction);
|
ConnectId connectId = tunnelToken.GetTcpConnectId();
|
||||||
if (tcpConnections.TryGetValue(connectId, out AsyncUserToken token))
|
if (tcpConnections.TryGetValue(connectId, out AsyncUserToken token))
|
||||||
{
|
{
|
||||||
_ = ProcessReceive(token);
|
_ = ProcessReceive(token);
|
||||||
@@ -301,7 +302,7 @@ namespace linker.tunnel.proxy
|
|||||||
{
|
{
|
||||||
if (tunnelToken.Proxy.Protocol == ProxyProtocol.Tcp)
|
if (tunnelToken.Proxy.Protocol == ProxyProtocol.Tcp)
|
||||||
{
|
{
|
||||||
ConnectId connectId = new ConnectId(tunnelToken.Proxy.ConnectId, tunnelToken.Connection.GetHashCode(), (byte)tunnelToken.Proxy.Direction);
|
ConnectId connectId = tunnelToken.GetTcpConnectId();
|
||||||
if (tcpConnections.TryRemove(connectId, out AsyncUserToken token))
|
if (tcpConnections.TryRemove(connectId, out AsyncUserToken token))
|
||||||
{
|
{
|
||||||
CloseClientSocket(token);
|
CloseClientSocket(token);
|
||||||
@@ -316,7 +317,7 @@ namespace linker.tunnel.proxy
|
|||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
private async Task SendToSocketTcp(AsyncUserTunnelToken tunnelToken)
|
private async Task SendToSocketTcp(AsyncUserTunnelToken tunnelToken)
|
||||||
{
|
{
|
||||||
ConnectId connectId = new ConnectId(tunnelToken.Proxy.ConnectId, tunnelToken.Connection.GetHashCode(), (byte)tunnelToken.Proxy.Direction);
|
ConnectId connectId = tunnelToken.GetTcpConnectId();
|
||||||
if (tunnelToken.Proxy.Step == ProxyStep.Close || tunnelToken.Proxy.Data.Length == 0)
|
if (tunnelToken.Proxy.Step == ProxyStep.Close || tunnelToken.Proxy.Data.Length == 0)
|
||||||
{
|
{
|
||||||
if (tcpConnections.TryRemove(connectId, out AsyncUserToken token))
|
if (tcpConnections.TryRemove(connectId, out AsyncUserToken token))
|
||||||
@@ -329,6 +330,7 @@ namespace linker.tunnel.proxy
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
token1.Connection = tunnelToken.Connection;
|
||||||
await token1.Socket.SendAsync(tunnelToken.Proxy.Data, SocketFlags.None).AsTask().WaitAsync(TimeSpan.FromMilliseconds(5000)).ConfigureAwait(false);
|
await token1.Socket.SendAsync(tunnelToken.Proxy.Data, SocketFlags.None).AsTask().WaitAsync(TimeSpan.FromMilliseconds(5000)).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
@@ -348,14 +350,15 @@ namespace linker.tunnel.proxy
|
|||||||
if (token == null) return;
|
if (token == null) return;
|
||||||
if (token.Connection != null)
|
if (token.Connection != null)
|
||||||
{
|
{
|
||||||
tcpConnections.TryRemove(new ConnectId(token.Proxy.ConnectId, token.Connection.GetHashCode(), (byte)token.Proxy.Direction), out _);
|
tcpConnections.TryRemove(token.GetConnectId(), out _);
|
||||||
}
|
}
|
||||||
token.Clear();
|
token.Clear();
|
||||||
}
|
}
|
||||||
private void CloseClientSocketTcp(ITunnelConnection connection)
|
private void CloseClientSocketTcp(ITunnelConnection connection)
|
||||||
{
|
{
|
||||||
int hashcode = connection.GetHashCode();
|
int hashcode1 = connection.RemoteMachineId.GetHashCode();
|
||||||
var tokens = tcpConnections.Where(c => c.Key.hashcode == hashcode).ToList();
|
int hashcode2 = connection.TransactionId.GetHashCode();
|
||||||
|
var tokens = tcpConnections.Where(c => c.Key.hashcode1 == hashcode1 && c.Key.hashcode2 == hashcode2).ToList();
|
||||||
foreach (var item in tokens)
|
foreach (var item in tokens)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
@@ -407,23 +410,25 @@ namespace linker.tunnel.proxy
|
|||||||
{
|
{
|
||||||
public bool Equals(ConnectId x, ConnectId y)
|
public bool Equals(ConnectId x, ConnectId y)
|
||||||
{
|
{
|
||||||
return x.connectId == y.connectId && x.hashcode == y.hashcode && x.direction == y.direction;
|
return x.connectId == y.connectId && x.hashcode1 == y.hashcode1 && x.hashcode2 == y.hashcode2 && x.direction == y.direction;
|
||||||
}
|
}
|
||||||
public int GetHashCode(ConnectId obj)
|
public int GetHashCode(ConnectId obj)
|
||||||
{
|
{
|
||||||
return obj.connectId.GetHashCode() ^ obj.hashcode ^ obj.direction;
|
return obj.connectId.GetHashCode() ^ obj.hashcode1 ^ obj.hashcode2 ^ obj.direction;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public record struct ConnectId
|
public record struct ConnectId
|
||||||
{
|
{
|
||||||
public ulong connectId;
|
public ulong connectId;
|
||||||
public int hashcode;
|
public int hashcode1;
|
||||||
|
public int hashcode2;
|
||||||
public byte direction;
|
public byte direction;
|
||||||
|
|
||||||
public ConnectId(ulong connectId, int hashcode, byte direction)
|
public ConnectId(ulong connectId, int hashcode1, int hashcode2, byte direction)
|
||||||
{
|
{
|
||||||
this.connectId = connectId;
|
this.connectId = connectId;
|
||||||
this.hashcode = hashcode;
|
this.hashcode1 = hashcode1;
|
||||||
|
this.hashcode2 = hashcode2;
|
||||||
this.direction = direction;
|
this.direction = direction;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -450,6 +455,15 @@ namespace linker.tunnel.proxy
|
|||||||
|
|
||||||
GC.Collect();
|
GC.Collect();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ConnectId GetConnectId()
|
||||||
|
{
|
||||||
|
return new ConnectId(Proxy.ConnectId, Connection.RemoteMachineId.GetHashCode(), Connection.TransactionId.GetHashCode(), (byte)Proxy.Direction);
|
||||||
|
}
|
||||||
|
public ConnectId GetConnectId(ProxyDirection proxyDirection)
|
||||||
|
{
|
||||||
|
return new ConnectId(Proxy.ConnectId, Connection.RemoteMachineId.GetHashCode(), Connection.TransactionId.GetHashCode(), (byte)proxyDirection);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
public sealed class ConnectState
|
public sealed class ConnectState
|
||||||
{
|
{
|
||||||
|
@@ -153,7 +153,7 @@ namespace linker.tunnel.proxy
|
|||||||
|
|
||||||
if (tunnelToken.Proxy.Direction == ProxyDirection.Forward)
|
if (tunnelToken.Proxy.Direction == ProxyDirection.Forward)
|
||||||
{
|
{
|
||||||
ConnectIdUdp connectId = new ConnectIdUdp(tunnelToken.Proxy.ConnectId, tunnelToken.Proxy.SourceEP, tunnelToken.Connection.GetHashCode());
|
ConnectIdUdp connectId = tunnelToken.GetUdpConnectId();
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
IPEndPoint target = new IPEndPoint(tunnelToken.Proxy.TargetEP.Address, tunnelToken.Proxy.TargetEP.Port);
|
IPEndPoint target = new IPEndPoint(tunnelToken.Proxy.TargetEP.Address, tunnelToken.Proxy.TargetEP.Port);
|
||||||
@@ -185,6 +185,7 @@ namespace linker.tunnel.proxy
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
asyncUserUdpToken.Connection = tunnelToken.Connection;
|
||||||
if (await ConnectionReceiveUdp(tunnelToken, asyncUserUdpToken).ConfigureAwait(false) == false)
|
if (await ConnectionReceiveUdp(tunnelToken, asyncUserUdpToken).ConfigureAwait(false) == false)
|
||||||
{
|
{
|
||||||
await asyncUserUdpToken.SourceSocket.SendToAsync(tunnelToken.Proxy.Data, tunnelToken.Proxy.SourceEP).ConfigureAwait(false);
|
await asyncUserUdpToken.SourceSocket.SendToAsync(tunnelToken.Proxy.Data, tunnelToken.Proxy.SourceEP).ConfigureAwait(false);
|
||||||
@@ -207,7 +208,7 @@ namespace linker.tunnel.proxy
|
|||||||
await socket.SendToAsync(tunnelToken.Proxy.Data, target).ConfigureAwait(false);
|
await socket.SendToAsync(tunnelToken.Proxy.Data, target).ConfigureAwait(false);
|
||||||
|
|
||||||
|
|
||||||
ConnectIdUdp connectId = new ConnectIdUdp(tunnelToken.Proxy.ConnectId, tunnelToken.Proxy.SourceEP, tunnelToken.Connection.GetHashCode());
|
ConnectIdUdp connectId = tunnelToken.GetUdpConnectId();
|
||||||
AsyncUserUdpTokenTarget udpToken = new AsyncUserUdpTokenTarget
|
AsyncUserUdpTokenTarget udpToken = new AsyncUserUdpTokenTarget
|
||||||
{
|
{
|
||||||
Proxy = new ProxyInfo
|
Proxy = new ProxyInfo
|
||||||
@@ -270,8 +271,8 @@ namespace linker.tunnel.proxy
|
|||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
private async Task SendToConnection(AsyncUserUdpTokenTarget token)
|
private async Task SendToConnection(AsyncUserUdpTokenTarget token)
|
||||||
{
|
{
|
||||||
// SemaphoreSlim semaphoreSlim = token.Proxy.Direction == ProxyDirection.Forward ? semaphoreSlimForward : semaphoreSlimReverse;
|
// SemaphoreSlim semaphoreSlim = token.Proxy.Direction == ProxyDirection.Forward ? semaphoreSlimForward : semaphoreSlimReverse;
|
||||||
// await semaphoreSlim.WaitAsync();
|
// await semaphoreSlim.WaitAsync();
|
||||||
|
|
||||||
|
|
||||||
byte[] connectData = token.Proxy.ToBytes(out int length);
|
byte[] connectData = token.Proxy.ToBytes(out int length);
|
||||||
@@ -290,7 +291,7 @@ namespace linker.tunnel.proxy
|
|||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
token.Proxy.Return(connectData);
|
token.Proxy.Return(connectData);
|
||||||
// semaphoreSlim.Release();
|
// semaphoreSlim.Release();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -325,8 +326,9 @@ namespace linker.tunnel.proxy
|
|||||||
|
|
||||||
private void CloseClientSocketUdp(ITunnelConnection connection)
|
private void CloseClientSocketUdp(ITunnelConnection connection)
|
||||||
{
|
{
|
||||||
int hashcode = connection.GetHashCode();
|
int hashcode1 = connection.RemoteMachineId.GetHashCode();
|
||||||
var tokens = udpConnections.Where(c => c.Key.hashcode == hashcode).ToList();
|
int hashcode2 = connection.TransactionId.GetHashCode();
|
||||||
|
var tokens = udpConnections.Where(c => c.Key.hashcode1 == hashcode1 && c.Key.hashcode2 == hashcode2).ToList();
|
||||||
foreach (var item in tokens)
|
foreach (var item in tokens)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
@@ -437,25 +439,27 @@ namespace linker.tunnel.proxy
|
|||||||
{
|
{
|
||||||
public bool Equals(ConnectIdUdp x, ConnectIdUdp y)
|
public bool Equals(ConnectIdUdp x, ConnectIdUdp y)
|
||||||
{
|
{
|
||||||
return x.source != null && x.source.Equals(y.source) && x.connectId == y.connectId && x.hashcode == y.hashcode;
|
return x.source != null && x.source.Equals(y.source) && x.connectId == y.connectId && x.hashcode1 == y.hashcode1 && x.hashcode2 == y.hashcode2;
|
||||||
}
|
}
|
||||||
public int GetHashCode(ConnectIdUdp obj)
|
public int GetHashCode(ConnectIdUdp obj)
|
||||||
{
|
{
|
||||||
if (obj.source == null) return 0;
|
if (obj.source == null) return 0;
|
||||||
return obj.source.GetHashCode() ^ obj.connectId.GetHashCode() ^ obj.hashcode;
|
return obj.source.GetHashCode() ^ obj.connectId.GetHashCode() ^ obj.hashcode1 ^ obj.hashcode2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public readonly struct ConnectIdUdp
|
public readonly struct ConnectIdUdp
|
||||||
{
|
{
|
||||||
public readonly IPEndPoint source { get; }
|
public readonly IPEndPoint source { get; }
|
||||||
public readonly ulong connectId { get; }
|
public readonly ulong connectId { get; }
|
||||||
public int hashcode { get; }
|
public int hashcode1 { get; }
|
||||||
|
public int hashcode2 { get; }
|
||||||
|
|
||||||
public ConnectIdUdp(ulong connectId, IPEndPoint source, int hashcode)
|
public ConnectIdUdp(ulong connectId, IPEndPoint source, int hashcode1, int hashcode2)
|
||||||
{
|
{
|
||||||
this.connectId = connectId;
|
this.connectId = connectId;
|
||||||
this.source = source;
|
this.source = source;
|
||||||
this.hashcode = hashcode;
|
this.hashcode1 = hashcode1;
|
||||||
|
this.hashcode2 = hashcode2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,7 +1,10 @@
|
|||||||
using Fizzler.Systems.HtmlAgilityPack;
|
using Fizzler.Systems.HtmlAgilityPack;
|
||||||
using HtmlAgilityPack;
|
using HtmlAgilityPack;
|
||||||
using linker.libs;
|
using linker.libs;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.IO.Compression;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
namespace linker.updater
|
namespace linker.updater
|
||||||
{
|
{
|
||||||
@@ -13,17 +16,36 @@ namespace linker.updater
|
|||||||
await Helper.Await();
|
await Helper.Await();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static string rootPath = "./updater";
|
||||||
static void Updater()
|
static void Updater()
|
||||||
{
|
{
|
||||||
Task.Factory.StartNew(async () =>
|
Task.Factory.StartNew(async () =>
|
||||||
{
|
{
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
UpdateInfo updateInfo = GetUpdateInfo();
|
try
|
||||||
if (updateInfo != null)
|
{
|
||||||
|
UpdateInfo updateInfo = GetUpdateInfo();
|
||||||
|
if (updateInfo != null)
|
||||||
|
{
|
||||||
|
if (NeedDownload(updateInfo))
|
||||||
|
{
|
||||||
|
await DownloadUpdate(updateInfo);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (NeedExtract())
|
||||||
|
{
|
||||||
|
ExtractUpdate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception)
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
await Task.Delay(15000);
|
await Task.Delay(15000);
|
||||||
@@ -32,7 +54,75 @@ namespace linker.updater
|
|||||||
|
|
||||||
}, TaskCreationOptions.LongRunning);
|
}, TaskCreationOptions.LongRunning);
|
||||||
}
|
}
|
||||||
|
static bool NeedExtract()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return File.Exists(Path.Join(rootPath, "version.txt"))
|
||||||
|
&& File.Exists(Path.Join(rootPath,"updater.zip"))
|
||||||
|
&& File.Exists(Path.Join(rootPath, "extract.txt"))
|
||||||
|
&& File.ReadAllText(Path.Join(rootPath, "version.txt")) != $"v{FileVersionInfo.GetVersionInfo("linker.exe").FileVersion}";
|
||||||
|
}
|
||||||
|
catch (Exception)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
static void ExtractUpdate()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
ZipFile.ExtractToDirectory(Path.Join(rootPath, "updater.zip"), "./", Encoding.UTF8, true);
|
||||||
|
|
||||||
|
File.Delete(Path.Join(rootPath, "version.txt"));
|
||||||
|
File.Delete(Path.Join(rootPath, "msg.txt"));
|
||||||
|
File.Delete(Path.Join(rootPath, "extract.txt"));
|
||||||
|
File.Delete(Path.Join(rootPath, "updater.zip"));
|
||||||
|
}
|
||||||
|
catch (Exception)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool NeedDownload(UpdateInfo updateInfo)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
return (File.Exists(Path.Join(rootPath, "version.txt")) == false
|
||||||
|
|| File.ReadAllText(Path.Join(rootPath, "version.txt")) != updateInfo.Tag)
|
||||||
|
&& $"v{FileVersionInfo.GetVersionInfo("linker.exe").FileVersion}" != updateInfo.Tag;
|
||||||
|
}
|
||||||
|
catch (Exception)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
static async Task DownloadUpdate(UpdateInfo updateInfo)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (Directory.Exists(rootPath) == false)
|
||||||
|
{
|
||||||
|
Directory.CreateDirectory(rootPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
using FileStream fileStream = new FileStream(Path.Join(rootPath, "updater.zip"), FileMode.OpenOrCreate, FileAccess.ReadWrite);
|
||||||
|
using HttpClient httpClient = new HttpClient();
|
||||||
|
using Stream stream = await httpClient.GetStreamAsync(updateInfo.Url);
|
||||||
|
await stream.CopyToAsync(fileStream);
|
||||||
|
|
||||||
|
fileStream.Flush();
|
||||||
|
fileStream.Close();
|
||||||
|
fileStream.Dispose();
|
||||||
|
|
||||||
|
File.WriteAllText(Path.Join(rootPath, "version.txt"), updateInfo.Tag);
|
||||||
|
File.WriteAllText(Path.Join(rootPath, "msg.txt"), updateInfo.Msg);
|
||||||
|
}
|
||||||
|
catch (Exception)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
static UpdateInfo GetUpdateInfo()
|
static UpdateInfo GetUpdateInfo()
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
|
@@ -41,6 +41,7 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Fizzler.Systems.HtmlAgilityPack" Version="1.2.1" />
|
<PackageReference Include="Fizzler.Systems.HtmlAgilityPack" Version="1.2.1" />
|
||||||
|
<PackageReference Include="System.IO.Compression.ZipFile" Version="4.3.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\linker.libs\linker.libs.csproj" />
|
<ProjectReference Include="..\linker.libs\linker.libs.csproj" />
|
||||||
|
@@ -1,54 +1,106 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<el-dialog v-model="state.show" title="初始化配置" width="500">
|
<el-dialog v-model="state.show" title="初始化配置" width="500" top="2vh">
|
||||||
<div>
|
<div>
|
||||||
|
<div class="head t-c">
|
||||||
|
<el-checkbox v-model="state.form.client" label="客户端" />
|
||||||
|
<el-checkbox v-model="state.form.server" label="服务端" />
|
||||||
|
</div>
|
||||||
<div class="body">
|
<div class="body">
|
||||||
<el-form ref="formDom" :model="state.form" :rules="state.rules" label-width="8rem">
|
<el-card shadow="never" v-if="state.form.client">
|
||||||
<el-form-item label="模式" prop="mode">
|
<template #header>
|
||||||
<el-checkbox v-model="state.form.client" label="客户端" readonly disabled />
|
<div class="card-header"><span>客户端</span></div>
|
||||||
<el-checkbox v-model="state.form.server" label="服务端" readonly disabled />
|
</template>
|
||||||
</el-form-item>
|
<div>
|
||||||
<el-form-item label="" label-width="0">
|
<el-form ref="formDom" :model="state.form" :rules="state.rules" label-width="8rem">
|
||||||
<el-row>
|
<el-form-item label="" label-width="0">
|
||||||
<el-col :span="12">
|
<el-row>
|
||||||
<el-form-item label="机器名" prop="name">
|
<el-col :span="12">
|
||||||
<el-input v-model="state.form.name" maxlength="12" show-word-limit />
|
<el-form-item label="机器名" prop="name">
|
||||||
|
<el-input v-model="state.form.name" maxlength="12" show-word-limit />
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="分组名" prop="groupid">
|
||||||
|
<el-input v-model="state.form.groupid" maxlength="36" show-word-limit />
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="" label-width="0">
|
||||||
|
<el-row>
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="接口端口" prop="api">
|
||||||
|
<el-input v-model="state.form.api" />
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="网页端口" prop="web">
|
||||||
|
<el-input v-model="state.form.web" />
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="" label-width="0">
|
||||||
|
<el-form-item label="接口密码" prop="password">
|
||||||
|
<el-input type="password" v-model="state.form.password" show-password maxlength="36"
|
||||||
|
show-word-limit />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-form-item>
|
||||||
<el-col :span="12">
|
</el-form>
|
||||||
<el-form-item label="分组名" prop="groupid">
|
</div>
|
||||||
<el-input v-model="state.form.groupid" maxlength="36" show-word-limit />
|
</el-card>
|
||||||
</el-form-item>
|
<el-card shadow="never" v-if="state.form.server">
|
||||||
</el-col>
|
<template #header>
|
||||||
</el-row>
|
<div class="card-header"><span>服务端</span></div>
|
||||||
</el-form-item>
|
</template>
|
||||||
<el-form-item label="" label-width="0">
|
<div>
|
||||||
<el-row>
|
<el-form ref="formDom" :model="state.form" :rules="state.rules" label-width="10rem">
|
||||||
<el-col :span="12">
|
<el-form-item label="" label-width="0">
|
||||||
<el-form-item label="接口端口" prop="api">
|
<el-row>
|
||||||
<el-input v-model="state.form.api" />
|
<el-col :span="12">
|
||||||
</el-form-item>
|
<el-form-item label="服务端口" prop="servicePort">
|
||||||
</el-col>
|
<el-input v-model="state.form.servicePort" />
|
||||||
<el-col :span="12">
|
</el-form-item>
|
||||||
<el-form-item label="网页端口" prop="web">
|
</el-col>
|
||||||
<el-input v-model="state.form.web" />
|
<el-col :span="12">
|
||||||
</el-form-item>
|
<el-form-item label="web穿透端口" prop="sforwardPort">
|
||||||
</el-col>
|
<el-input v-model="state.form.sforwardPort" />
|
||||||
</el-row>
|
</el-form-item>
|
||||||
</el-form-item>
|
</el-col>
|
||||||
<el-form-item label="" label-width="0">
|
</el-row>
|
||||||
<el-form-item label="接口密码" prop="password">
|
</el-form-item>
|
||||||
<el-input type="password" v-model="state.form.password" show-password maxlength="36"
|
<el-form-item label="" label-width="0">
|
||||||
show-word-limit />
|
<el-row>
|
||||||
</el-form-item>
|
<el-col :span="12">
|
||||||
</el-form-item>
|
<el-form-item label="开放最小端口" prop="sforwardPort1">
|
||||||
<el-form-item label="重启" prop="mode">
|
<el-input v-model="state.form.sforwardPort1" />
|
||||||
<el-radio-group v-model="state.form.restart">
|
</el-form-item>
|
||||||
<el-radio :value="true">自动重启</el-radio>
|
</el-col>
|
||||||
<el-radio :value="false">手动重启</el-radio>
|
<el-col :span="12">
|
||||||
</el-radio-group>
|
<el-form-item label="开放最大端口" prop="sforwardPort2">
|
||||||
</el-form-item>
|
<el-input v-model="state.form.sforwardPort2" />
|
||||||
</el-form>
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="" label-width="0">
|
||||||
|
<el-row>
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="穿透密钥" prop="sforwardKey">
|
||||||
|
<el-input v-model="state.form.sforwardKey" maxlength="36" show-word-limit />
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="中继密钥" prop="relayKey">
|
||||||
|
<el-input v-model="state.form.relayKey" maxlength="36" show-word-limit />
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
</div>
|
||||||
|
</el-card>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<template #footer>
|
<template #footer>
|
||||||
@@ -73,13 +125,20 @@ export default {
|
|||||||
show: false,
|
show: false,
|
||||||
form: {
|
form: {
|
||||||
client: true,
|
client: true,
|
||||||
server: false,
|
server: true,
|
||||||
restart: false,
|
restart: false,
|
||||||
name: '',
|
name: '',
|
||||||
groupid: '',
|
groupid: '',
|
||||||
api: 0,
|
api: 0,
|
||||||
web: 0,
|
web: 0,
|
||||||
password: ''
|
password: '',
|
||||||
|
|
||||||
|
relayKey:'',
|
||||||
|
sforwardKey:'',
|
||||||
|
servicePort:1802,
|
||||||
|
sforwardPort:80,
|
||||||
|
sforwardPort1:10000,
|
||||||
|
sforwardPort2:60000,
|
||||||
},
|
},
|
||||||
rules: {
|
rules: {
|
||||||
name: [{ required: true, message: "必填", trigger: "blur" }],
|
name: [{ required: true, message: "必填", trigger: "blur" }],
|
||||||
@@ -148,9 +207,10 @@ export default {
|
|||||||
</script>
|
</script>
|
||||||
<style lang="stylus" scoped>
|
<style lang="stylus" scoped>
|
||||||
.body{
|
.body{
|
||||||
padding:1rem 0 2rem 0;
|
padding:1rem 0 0 0;
|
||||||
}
|
}
|
||||||
.footer{
|
.footer{
|
||||||
padding: 1rem 0;
|
padding: 1rem 0;
|
||||||
}
|
}
|
||||||
|
.el-card+.el-card{margin-top:1rem;}
|
||||||
</style>
|
</style>
|
@@ -67,7 +67,7 @@ namespace linker.config
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
private string groupid = "snltty";
|
private string groupid = string.Empty;//"snltty";
|
||||||
#else
|
#else
|
||||||
private string groupid = string.Empty;
|
private string groupid = string.Empty;
|
||||||
#endif
|
#endif
|
||||||
|
@@ -113,6 +113,8 @@ namespace linker.plugins.forward.proxy
|
|||||||
if (connection == null)
|
if (connection == null)
|
||||||
{
|
{
|
||||||
if (LoggerHelper.Instance.LoggerLevel <= LoggerTypes.DEBUG) LoggerHelper.Instance.Debug($"forward relay to {machineId}");
|
if (LoggerHelper.Instance.LoggerLevel <= LoggerTypes.DEBUG) LoggerHelper.Instance.Debug($"forward relay to {machineId}");
|
||||||
|
//转入后台打洞
|
||||||
|
tunnelTransfer.StartBackground(machineId, "forward");
|
||||||
//尝试中继
|
//尝试中继
|
||||||
connection = await relayTransfer.ConnectAsync(config.Data.Client.Id, machineId, "forward").ConfigureAwait(false);
|
connection = await relayTransfer.ConnectAsync(config.Data.Client.Id, machineId, "forward").ConfigureAwait(false);
|
||||||
if (connection != null)
|
if (connection != null)
|
||||||
|
@@ -262,6 +262,7 @@ namespace linker.plugins.tuntap.proxy
|
|||||||
{
|
{
|
||||||
if (LoggerHelper.Instance.LoggerLevel <= LoggerTypes.DEBUG) LoggerHelper.Instance.Debug($"tuntap relay to {machineId}");
|
if (LoggerHelper.Instance.LoggerLevel <= LoggerTypes.DEBUG) LoggerHelper.Instance.Debug($"tuntap relay to {machineId}");
|
||||||
|
|
||||||
|
tunnelTransfer.StartBackground(machineId, "tuntap");
|
||||||
connection = await relayTransfer.ConnectAsync(config.Data.Client.Id, machineId, "tuntap").ConfigureAwait(false);
|
connection = await relayTransfer.ConnectAsync(config.Data.Client.Id, machineId, "tuntap").ConfigureAwait(false);
|
||||||
if (connection != null)
|
if (connection != null)
|
||||||
{
|
{
|
||||||
|
43
linker/plugins/updater/UpdaterStartup.cs
Normal file
43
linker/plugins/updater/UpdaterStartup.cs
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
using linker.config;
|
||||||
|
using linker.libs;
|
||||||
|
using linker.startup;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.Reflection;
|
||||||
|
|
||||||
|
namespace linker.plugins.updater
|
||||||
|
{
|
||||||
|
public sealed class UpdaterStartup : IStartup
|
||||||
|
{
|
||||||
|
public string Name => "updater";
|
||||||
|
|
||||||
|
public bool Required => false;
|
||||||
|
|
||||||
|
public StartupLevel Level => StartupLevel.Normal;
|
||||||
|
|
||||||
|
public string[] Dependent => Array.Empty<string>();
|
||||||
|
|
||||||
|
public StartupLoadType LoadType => StartupLoadType.Normal;
|
||||||
|
|
||||||
|
public void AddClient(ServiceCollection serviceCollection, ConfigWrap config, Assembly[] assemblies)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public void AddServer(ServiceCollection serviceCollection, ConfigWrap config, Assembly[] assemblies)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public void UseClient(ServiceProvider serviceProvider, ConfigWrap config, Assembly[] assemblies)
|
||||||
|
{
|
||||||
|
foreach (var item in Process.GetProcessesByName("linker.updater"))
|
||||||
|
{
|
||||||
|
item.Kill();
|
||||||
|
}
|
||||||
|
//CommandHelper.Execute();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void UseServer(ServiceProvider serviceProvider, ConfigWrap config, Assembly[] assemblies)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
52
linker/plugins/updater/config/config.cs
Normal file
52
linker/plugins/updater/config/config.cs
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
using linker.plugins.updater.config;
|
||||||
|
|
||||||
|
namespace linker.plugins.updater.config
|
||||||
|
{
|
||||||
|
public sealed class UpdaterConfigInfo
|
||||||
|
{
|
||||||
|
private string runWindows = "sc start linker.service";
|
||||||
|
private string stopWindows = "sc stop linker.service & taskkill /F /IM linker.exe & taskkill /F /IM linker.tray.win.exe";
|
||||||
|
|
||||||
|
private string runLinux = "systemctl start linker";
|
||||||
|
private string stopLinux = "systemctl stop linker";
|
||||||
|
|
||||||
|
private string runOsx = "launchctl start linker";
|
||||||
|
private string stopOsx = "launchctl stop linker";
|
||||||
|
|
||||||
|
|
||||||
|
private string runCommand = string.Empty;
|
||||||
|
public string RunCommand
|
||||||
|
{
|
||||||
|
get => runCommand; set
|
||||||
|
{
|
||||||
|
runCommand = value;
|
||||||
|
if (string.IsNullOrWhiteSpace(runCommand))
|
||||||
|
{
|
||||||
|
runCommand = OperatingSystem.IsWindows() ? runWindows : OperatingSystem.IsLinux() ? runLinux : runOsx;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private string stopCommand = string.Empty;
|
||||||
|
public string StopCommand
|
||||||
|
{
|
||||||
|
get => stopCommand; set
|
||||||
|
{
|
||||||
|
stopCommand = value;
|
||||||
|
if (string.IsNullOrWhiteSpace(stopCommand))
|
||||||
|
{
|
||||||
|
stopCommand = OperatingSystem.IsWindows() ? stopWindows : OperatingSystem.IsLinux() ? stopLinux : stopOsx;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
namespace linker.client.config
|
||||||
|
{
|
||||||
|
public sealed partial class ConfigClientInfo
|
||||||
|
{
|
||||||
|
public UpdaterConfigInfo Updater { get; set; } = new UpdaterConfigInfo();
|
||||||
|
}
|
||||||
|
}
|
@@ -27,7 +27,7 @@ for %%r in (win-x64,win-arm64) do (
|
|||||||
|
|
||||||
for %%r in (win-x64,win-arm64,linux-x64,linux-arm64,osx-x64,osx-arm64) do (
|
for %%r in (win-x64,win-arm64,linux-x64,linux-arm64,osx-x64,osx-arm64) do (
|
||||||
|
|
||||||
rem dotnet publish ./linker.updater -c release -f net8.0 -o public/publish/%%r/linker-%%r/ -r %%r -p:PublishSingleFile=true -p:PublishTrimmed=true --self-contained true -p:TrimMode=full -p:TieredPGO=true -p:DebugType=none -p:DebugSymbols=false -p:EnableCompressionInSingleFile=true -p:DebuggerSupport=false -p:EnableUnsafeBinaryFormatterSerialization=false -p:EnableUnsafeUTF7Encoding=false -p:HttpActivityPropagationSupport=false -p:InvariantGlobalization=true -p:MetadataUpdaterSupport=false -p:UseSystemResourceKeys=true
|
rem dotnet publish ./linker.updater -c release -f net8.0 -o public/publish/%%r/linker-%%r/ -r %%r -p:PublishSingleFile=true -p:PublishTrimmed=true --self-contained true -p:TrimMode=partial -p:TieredPGO=true -p:DebugType=none -p:DebugSymbols=false -p:EnableCompressionInSingleFile=true -p:DebuggerSupport=false -p:EnableUnsafeBinaryFormatterSerialization=false -p:EnableUnsafeUTF7Encoding=false -p:HttpActivityPropagationSupport=false -p:InvariantGlobalization=true -p:MetadataUpdaterSupport=false -p:UseSystemResourceKeys=true
|
||||||
|
|
||||||
dotnet publish ./linker -c release -f net8.0 -o ./public/publish/%%r/linker-%%r -r %%r -p:PublishSingleFile=true -p:PublishTrimmed=true --self-contained true -p:TrimMode=partial -p:TieredPGO=true -p:DebugType=none -p:DebugSymbols=false -p:EnableCompressionInSingleFile=true -p:DebuggerSupport=false -p:EnableUnsafeBinaryFormatterSerialization=false -p:EnableUnsafeUTF7Encoding=false -p:HttpActivityPropagationSupport=false -p:InvariantGlobalization=true -p:MetadataUpdaterSupport=false -p:UseSystemResourceKeys=true
|
dotnet publish ./linker -c release -f net8.0 -o ./public/publish/%%r/linker-%%r -r %%r -p:PublishSingleFile=true -p:PublishTrimmed=true --self-contained true -p:TrimMode=partial -p:TieredPGO=true -p:DebugType=none -p:DebugSymbols=false -p:EnableCompressionInSingleFile=true -p:DebuggerSupport=false -p:EnableUnsafeBinaryFormatterSerialization=false -p:EnableUnsafeUTF7Encoding=false -p:HttpActivityPropagationSupport=false -p:InvariantGlobalization=true -p:MetadataUpdaterSupport=false -p:UseSystemResourceKeys=true
|
||||||
echo F|xcopy "public\\extends\\%%r\\linker-%%r\\*" "public\\publish\\%%r\\linker-%%r\\*" /s /f /h /y
|
echo F|xcopy "public\\extends\\%%r\\linker-%%r\\*" "public\\publish\\%%r\\linker-%%r\\*" /s /f /h /y
|
||||||
|
Reference in New Issue
Block a user