mirror of
https://github.com/snltty/linker.git
synced 2025-10-20 15:55:17 +08:00
sync
This commit is contained in:
@@ -118,10 +118,8 @@ namespace linker.tunnel
|
||||
/// <returns></returns>
|
||||
public async Task<ITunnelConnection> ConnectAsync(string remoteMachineId, string transactionId)
|
||||
{
|
||||
if (connectingDic.TryAdd(remoteMachineId, true) == false)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
if (connectingDic.TryAdd(remoteMachineId, true) == false) return null;
|
||||
if (IsBackground(remoteMachineId, transactionId)) return null;
|
||||
|
||||
try
|
||||
{
|
||||
@@ -221,7 +219,6 @@ namespace linker.tunnel
|
||||
{
|
||||
connectingDic.TryRemove(remoteMachineId, out _);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
/// <summary>
|
||||
@@ -393,5 +390,54 @@ namespace linker.tunnel
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
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.Net;
|
||||
using System.Net.Sockets;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace linker.tunnel.proxy
|
||||
{
|
||||
@@ -106,7 +107,7 @@ namespace linker.tunnel.proxy
|
||||
}
|
||||
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)
|
||||
{
|
||||
@@ -253,12 +254,12 @@ namespace linker.tunnel.proxy
|
||||
|
||||
token.Socket.EndConnect(result);
|
||||
token.Socket.KeepAlive();
|
||||
|
||||
|
||||
if (state.Data.Length > 0)
|
||||
{
|
||||
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);
|
||||
token.Proxy.Step = ProxyStep.Forward;
|
||||
@@ -286,7 +287,7 @@ namespace linker.tunnel.proxy
|
||||
{
|
||||
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))
|
||||
{
|
||||
_ = ProcessReceive(token);
|
||||
@@ -301,7 +302,7 @@ namespace linker.tunnel.proxy
|
||||
{
|
||||
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))
|
||||
{
|
||||
CloseClientSocket(token);
|
||||
@@ -316,7 +317,7 @@ namespace linker.tunnel.proxy
|
||||
/// <returns></returns>
|
||||
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 (tcpConnections.TryRemove(connectId, out AsyncUserToken token))
|
||||
@@ -329,6 +330,7 @@ namespace linker.tunnel.proxy
|
||||
{
|
||||
try
|
||||
{
|
||||
token1.Connection = tunnelToken.Connection;
|
||||
await token1.Socket.SendAsync(tunnelToken.Proxy.Data, SocketFlags.None).AsTask().WaitAsync(TimeSpan.FromMilliseconds(5000)).ConfigureAwait(false);
|
||||
}
|
||||
catch (Exception ex)
|
||||
@@ -348,14 +350,15 @@ namespace linker.tunnel.proxy
|
||||
if (token == null) return;
|
||||
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();
|
||||
}
|
||||
private void CloseClientSocketTcp(ITunnelConnection connection)
|
||||
{
|
||||
int hashcode = connection.GetHashCode();
|
||||
var tokens = tcpConnections.Where(c => c.Key.hashcode == hashcode).ToList();
|
||||
int hashcode1 = connection.RemoteMachineId.GetHashCode();
|
||||
int hashcode2 = connection.TransactionId.GetHashCode();
|
||||
var tokens = tcpConnections.Where(c => c.Key.hashcode1 == hashcode1 && c.Key.hashcode2 == hashcode2).ToList();
|
||||
foreach (var item in tokens)
|
||||
{
|
||||
try
|
||||
@@ -407,23 +410,25 @@ namespace linker.tunnel.proxy
|
||||
{
|
||||
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)
|
||||
{
|
||||
return obj.connectId.GetHashCode() ^ obj.hashcode ^ obj.direction;
|
||||
return obj.connectId.GetHashCode() ^ obj.hashcode1 ^ obj.hashcode2 ^ obj.direction;
|
||||
}
|
||||
}
|
||||
public record struct ConnectId
|
||||
{
|
||||
public ulong connectId;
|
||||
public int hashcode;
|
||||
public int hashcode1;
|
||||
public int hashcode2;
|
||||
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.hashcode = hashcode;
|
||||
this.hashcode1 = hashcode1;
|
||||
this.hashcode2 = hashcode2;
|
||||
this.direction = direction;
|
||||
}
|
||||
}
|
||||
@@ -450,6 +455,15 @@ namespace linker.tunnel.proxy
|
||||
|
||||
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
|
||||
{
|
||||
|
@@ -153,7 +153,7 @@ namespace linker.tunnel.proxy
|
||||
|
||||
if (tunnelToken.Proxy.Direction == ProxyDirection.Forward)
|
||||
{
|
||||
ConnectIdUdp connectId = new ConnectIdUdp(tunnelToken.Proxy.ConnectId, tunnelToken.Proxy.SourceEP, tunnelToken.Connection.GetHashCode());
|
||||
ConnectIdUdp connectId = tunnelToken.GetUdpConnectId();
|
||||
try
|
||||
{
|
||||
IPEndPoint target = new IPEndPoint(tunnelToken.Proxy.TargetEP.Address, tunnelToken.Proxy.TargetEP.Port);
|
||||
@@ -185,6 +185,7 @@ namespace linker.tunnel.proxy
|
||||
{
|
||||
try
|
||||
{
|
||||
asyncUserUdpToken.Connection = tunnelToken.Connection;
|
||||
if (await ConnectionReceiveUdp(tunnelToken, asyncUserUdpToken).ConfigureAwait(false) == 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);
|
||||
|
||||
|
||||
ConnectIdUdp connectId = new ConnectIdUdp(tunnelToken.Proxy.ConnectId, tunnelToken.Proxy.SourceEP, tunnelToken.Connection.GetHashCode());
|
||||
ConnectIdUdp connectId = tunnelToken.GetUdpConnectId();
|
||||
AsyncUserUdpTokenTarget udpToken = new AsyncUserUdpTokenTarget
|
||||
{
|
||||
Proxy = new ProxyInfo
|
||||
@@ -270,8 +271,8 @@ namespace linker.tunnel.proxy
|
||||
/// <returns></returns>
|
||||
private async Task SendToConnection(AsyncUserUdpTokenTarget token)
|
||||
{
|
||||
// SemaphoreSlim semaphoreSlim = token.Proxy.Direction == ProxyDirection.Forward ? semaphoreSlimForward : semaphoreSlimReverse;
|
||||
// await semaphoreSlim.WaitAsync();
|
||||
// SemaphoreSlim semaphoreSlim = token.Proxy.Direction == ProxyDirection.Forward ? semaphoreSlimForward : semaphoreSlimReverse;
|
||||
// await semaphoreSlim.WaitAsync();
|
||||
|
||||
|
||||
byte[] connectData = token.Proxy.ToBytes(out int length);
|
||||
@@ -290,7 +291,7 @@ namespace linker.tunnel.proxy
|
||||
finally
|
||||
{
|
||||
token.Proxy.Return(connectData);
|
||||
// semaphoreSlim.Release();
|
||||
// semaphoreSlim.Release();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -325,8 +326,9 @@ namespace linker.tunnel.proxy
|
||||
|
||||
private void CloseClientSocketUdp(ITunnelConnection connection)
|
||||
{
|
||||
int hashcode = connection.GetHashCode();
|
||||
var tokens = udpConnections.Where(c => c.Key.hashcode == hashcode).ToList();
|
||||
int hashcode1 = connection.RemoteMachineId.GetHashCode();
|
||||
int hashcode2 = connection.TransactionId.GetHashCode();
|
||||
var tokens = udpConnections.Where(c => c.Key.hashcode1 == hashcode1 && c.Key.hashcode2 == hashcode2).ToList();
|
||||
foreach (var item in tokens)
|
||||
{
|
||||
try
|
||||
@@ -437,25 +439,27 @@ namespace linker.tunnel.proxy
|
||||
{
|
||||
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)
|
||||
{
|
||||
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 IPEndPoint source { 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.source = source;
|
||||
this.hashcode = hashcode;
|
||||
this.hashcode1 = hashcode1;
|
||||
this.hashcode2 = hashcode2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -1,7 +1,10 @@
|
||||
using Fizzler.Systems.HtmlAgilityPack;
|
||||
using HtmlAgilityPack;
|
||||
using linker.libs;
|
||||
using System.Diagnostics;
|
||||
using System.IO.Compression;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
|
||||
namespace linker.updater
|
||||
{
|
||||
@@ -13,17 +16,36 @@ namespace linker.updater
|
||||
await Helper.Await();
|
||||
}
|
||||
|
||||
|
||||
static string rootPath = "./updater";
|
||||
static void Updater()
|
||||
{
|
||||
Task.Factory.StartNew(async () =>
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
UpdateInfo updateInfo = GetUpdateInfo();
|
||||
if (updateInfo != null)
|
||||
try
|
||||
{
|
||||
UpdateInfo updateInfo = GetUpdateInfo();
|
||||
if (updateInfo != null)
|
||||
{
|
||||
if (NeedDownload(updateInfo))
|
||||
{
|
||||
await DownloadUpdate(updateInfo);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
}
|
||||
try
|
||||
{
|
||||
if (NeedExtract())
|
||||
{
|
||||
ExtractUpdate();
|
||||
}
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
await Task.Delay(15000);
|
||||
@@ -32,7 +54,75 @@ namespace linker.updater
|
||||
|
||||
}, 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()
|
||||
{
|
||||
try
|
||||
|
@@ -41,6 +41,7 @@
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Fizzler.Systems.HtmlAgilityPack" Version="1.2.1" />
|
||||
<PackageReference Include="System.IO.Compression.ZipFile" Version="4.3.0" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\linker.libs\linker.libs.csproj" />
|
||||
|
@@ -1,54 +1,106 @@
|
||||
<template>
|
||||
<div>
|
||||
<el-dialog v-model="state.show" title="初始化配置" width="500">
|
||||
<el-dialog v-model="state.show" title="初始化配置" width="500" top="2vh">
|
||||
<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">
|
||||
<el-form ref="formDom" :model="state.form" :rules="state.rules" label-width="8rem">
|
||||
<el-form-item label="模式" prop="mode">
|
||||
<el-checkbox v-model="state.form.client" label="客户端" readonly disabled />
|
||||
<el-checkbox v-model="state.form.server" label="服务端" readonly disabled />
|
||||
</el-form-item>
|
||||
<el-form-item label="" label-width="0">
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="机器名" prop="name">
|
||||
<el-input v-model="state.form.name" maxlength="12" show-word-limit />
|
||||
<el-card shadow="never" v-if="state.form.client">
|
||||
<template #header>
|
||||
<div class="card-header"><span>客户端</span></div>
|
||||
</template>
|
||||
<div>
|
||||
<el-form ref="formDom" :model="state.form" :rules="state.rules" label-width="8rem">
|
||||
<el-form-item label="" label-width="0">
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<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-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-form-item label="重启" prop="mode">
|
||||
<el-radio-group v-model="state.form.restart">
|
||||
<el-radio :value="true">自动重启</el-radio>
|
||||
<el-radio :value="false">手动重启</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
</el-card>
|
||||
<el-card shadow="never" v-if="state.form.server">
|
||||
<template #header>
|
||||
<div class="card-header"><span>服务端</span></div>
|
||||
</template>
|
||||
<div>
|
||||
<el-form ref="formDom" :model="state.form" :rules="state.rules" label-width="10rem">
|
||||
<el-form-item label="" label-width="0">
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="服务端口" prop="servicePort">
|
||||
<el-input v-model="state.form.servicePort" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="web穿透端口" prop="sforwardPort">
|
||||
<el-input v-model="state.form.sforwardPort" />
|
||||
</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="sforwardPort1">
|
||||
<el-input v-model="state.form.sforwardPort1" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="开放最大端口" prop="sforwardPort2">
|
||||
<el-input v-model="state.form.sforwardPort2" />
|
||||
</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>
|
||||
<template #footer>
|
||||
@@ -73,13 +125,20 @@ export default {
|
||||
show: false,
|
||||
form: {
|
||||
client: true,
|
||||
server: false,
|
||||
server: true,
|
||||
restart: false,
|
||||
name: '',
|
||||
groupid: '',
|
||||
api: 0,
|
||||
web: 0,
|
||||
password: ''
|
||||
password: '',
|
||||
|
||||
relayKey:'',
|
||||
sforwardKey:'',
|
||||
servicePort:1802,
|
||||
sforwardPort:80,
|
||||
sforwardPort1:10000,
|
||||
sforwardPort2:60000,
|
||||
},
|
||||
rules: {
|
||||
name: [{ required: true, message: "必填", trigger: "blur" }],
|
||||
@@ -148,9 +207,10 @@ export default {
|
||||
</script>
|
||||
<style lang="stylus" scoped>
|
||||
.body{
|
||||
padding:1rem 0 2rem 0;
|
||||
padding:1rem 0 0 0;
|
||||
}
|
||||
.footer{
|
||||
padding: 1rem 0;
|
||||
}
|
||||
.el-card+.el-card{margin-top:1rem;}
|
||||
</style>
|
@@ -67,7 +67,7 @@ namespace linker.config
|
||||
}
|
||||
}
|
||||
#if DEBUG
|
||||
private string groupid = "snltty";
|
||||
private string groupid = string.Empty;//"snltty";
|
||||
#else
|
||||
private string groupid = string.Empty;
|
||||
#endif
|
||||
|
@@ -113,6 +113,8 @@ namespace linker.plugins.forward.proxy
|
||||
if (connection == null)
|
||||
{
|
||||
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);
|
||||
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}");
|
||||
|
||||
tunnelTransfer.StartBackground(machineId, "tuntap");
|
||||
connection = await relayTransfer.ConnectAsync(config.Data.Client.Id, machineId, "tuntap").ConfigureAwait(false);
|
||||
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 (
|
||||
|
||||
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
|
||||
echo F|xcopy "public\\extends\\%%r\\linker-%%r\\*" "public\\publish\\%%r\\linker-%%r\\*" /s /f /h /y
|
||||
|
Reference in New Issue
Block a user