mirror of
https://github.com/snltty/linker.git
synced 2025-10-29 19:52:11 +08:00
171
This commit is contained in:
2
.github/workflows/dotnet.yml
vendored
2
.github/workflows/dotnet.yml
vendored
@@ -35,7 +35,7 @@ jobs:
|
|||||||
release_name: v1.7.1.${{ steps.date.outputs.today }}
|
release_name: v1.7.1.${{ steps.date.outputs.today }}
|
||||||
draft: false
|
draft: false
|
||||||
prerelease: false
|
prerelease: false
|
||||||
body: "1. 优化数据同步\r\n2. 优化linux的tun网卡网卡,读写分离,提高性能\r\n3. 优化windows网卡的禁用自动启用\r\n4. 增加TCP包合并。网卡IP包多个合并一起发送\r\n5. 建议更新"
|
body: "1. 优化数据同步\r\n2. 优化linux的tun网卡网卡,读写分离,提高性能\r\n3. 优化windows网卡的禁用自动启用\r\n4. 增加TCP包合并。网卡IP包多个合并一起发送\r\n5. 内网穿透的计划任务\r\n6. 建议更新"
|
||||||
- name: publish projects
|
- name: publish projects
|
||||||
run: ./publish.bat
|
run: ./publish.bat
|
||||||
- name: upload-win-x86-oss
|
- name: upload-win-x86-oss
|
||||||
|
|||||||
@@ -54,19 +54,19 @@
|
|||||||
## 已有功能
|
## 已有功能
|
||||||
- [x] 配置加密,配置文件加密
|
- [x] 配置加密,配置文件加密
|
||||||
- [x] 通信加密,所有通信均`ssl加密`
|
- [x] 通信加密,所有通信均`ssl加密`
|
||||||
- [x] 打洞连接,TCP(支持IPV6)打洞、UDP打洞
|
- [x] 打洞连接,`TCP打洞、UDP打洞,(支持IPV6)`
|
||||||
- [x] 打洞类库,你可以使用`linker.tunnel`打洞库到你的项目中
|
- [x] 打洞类库,你可以使用`linker.tunnel`打洞库到你的项目中
|
||||||
- [x] 中继连接,先中继连接,然后偷偷打洞,打洞成功则无缝切换线路
|
- [x] 中继连接,先中继连接,然后偷偷打洞,打洞成功则无缝切换线路
|
||||||
- [x] 异地组网,使用虚拟网卡,将各个客户端组建为局域网络,`点对点`,`点对网`,`网对网`
|
- [x] 异地组网,使用虚拟网卡,将各个客户端组建为局域网络,`点对点`,`点对网`,`网对网`
|
||||||
- [x] 网卡类库,你可以使用`linker.tun` tun网卡库到你的项目中
|
- [x] 网卡类库,你可以使用`linker.tun` tun网卡库到你的项目中
|
||||||
- [x] 端口转发,将客户端的端口转发到其它客户端的端口
|
- [x] 端口转发,将客户端的端口转发到其它客户端的端口
|
||||||
- [x] 服务器穿透,在服务器注册端口或域名,通过访问服务器端口或域名,访问内网服务(支持计划任务,定时定长自动开启关闭)
|
- [x] 服务器穿透,在服务器注册端口或域名,通过访问服务器端口或域名,访问内网服务(支持`计划任务`,定时定长自动开启关闭)
|
||||||
- [x] 权限管理,主客户端拥有完全权限,可导出、配置子客户端配置,分配其管理权限
|
- [x] 权限管理,主客户端拥有完全权限,可导出、配置子客户端配置,分配其管理权限
|
||||||
- [x] 自定义验证,通过`HTTP POST`让你可以自定义认证是否允许`连接信标`,`中继`,`内网穿透`
|
- [x] 自定义验证,通过`HTTP POST`让你可以自定义认证是否允许`连接信标`,`中继`,`内网穿透`
|
||||||
- [x] 流量统计,统计服务器`信标`、`中继`、`内网穿透` 的流量情况
|
- [x] 流量统计,统计服务器`信标`、`中继`、`内网穿透` 的流量情况
|
||||||
- [x] 网络配置,主客户端设置网络,所有客户端自动分配IP
|
- [x] 网络配置,主客户端设置网络,所有客户端自动分配IP
|
||||||
- [x] 分布式,多中继服务器节点,承载海量设备
|
- [x] 分布式,多中继服务器节点,承载海量设备
|
||||||
- [x] socks5代理,端口转发需要指定端口,而socks5代理可以代理所有端口
|
- [x] socks5代理,端口转发需要指定端口,而`socks5代理`可以代理所有端口
|
||||||
- [x] 集成linker,使用`linker.messenger.entry`入口库,轻松集成到你的项目中
|
- [x] 集成linker,使用`linker.messenger.entry`入口库,轻松集成到你的项目中
|
||||||
- [x] CDKEY,可以临时解锁一些限制,中继,内外穿透什么的
|
- [x] CDKEY,可以临时解锁一些限制,中继,内外穿透什么的
|
||||||
|
|
||||||
|
|||||||
@@ -49,6 +49,15 @@ namespace linker.messenger.plan
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void Trigger(string category,string key,string handle)
|
||||||
|
{
|
||||||
|
PlanExecCacheInfo trigger = caches.Values.FirstOrDefault(c => c.Plan.Category == category && c.Plan.Key == key && c.Plan.TriggerHandle == handle && c.Plan.TriggerHandle != c.Plan.Handle && c.Plan.Method == PlanMethod.Trigger);
|
||||||
|
if (trigger != null)
|
||||||
|
{
|
||||||
|
trigger.Active = UpdateNextTime(trigger);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void PlanTask()
|
private void PlanTask()
|
||||||
{
|
{
|
||||||
Load();
|
Load();
|
||||||
|
|||||||
@@ -44,8 +44,6 @@ namespace linker.messenger.sforward
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public string LocalMsg { get; set; }
|
public string LocalMsg { get; set; }
|
||||||
|
|
||||||
public bool Proxy { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 端口范围
|
/// 端口范围
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -62,15 +62,6 @@
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="id"></param>
|
/// <param name="id"></param>
|
||||||
/// <param name="started"></param>
|
/// <param name="started"></param>
|
||||||
/// <param name="proxy"></param>
|
|
||||||
/// <param name="msg"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public bool Update(long id,bool started,bool proxy,string msg);
|
|
||||||
/// <summary>
|
|
||||||
/// 更新
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="id"></param>
|
|
||||||
/// <param name="started"></param>
|
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public bool Update(long id,bool started);
|
public bool Update(long id,bool started);
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -18,8 +18,9 @@ namespace linker.messenger.sforward.client
|
|||||||
private readonly ISForwardClientStore sForwardClientStore;
|
private readonly ISForwardClientStore sForwardClientStore;
|
||||||
private readonly ISerializer serializer;
|
private readonly ISerializer serializer;
|
||||||
private readonly IAccessStore accessStore;
|
private readonly IAccessStore accessStore;
|
||||||
|
private readonly SForwardPlanHandle sForwardPlanHandle;
|
||||||
|
|
||||||
public SForwardApiController(SForwardClientTransfer forwardTransfer, IMessengerSender messengerSender, SignInClientState signInClientState, ISignInClientStore signInClientStore, SForwardDecenter sForwardDecenter, ISForwardClientStore sForwardClientStore, ISerializer serializer, IAccessStore accessStore)
|
public SForwardApiController(SForwardClientTransfer forwardTransfer, IMessengerSender messengerSender, SignInClientState signInClientState, ISignInClientStore signInClientStore, SForwardDecenter sForwardDecenter, ISForwardClientStore sForwardClientStore, ISerializer serializer, IAccessStore accessStore, SForwardPlanHandle sForwardPlanHandle)
|
||||||
{
|
{
|
||||||
this.forwardTransfer = forwardTransfer;
|
this.forwardTransfer = forwardTransfer;
|
||||||
this.messengerSender = messengerSender;
|
this.messengerSender = messengerSender;
|
||||||
@@ -29,6 +30,7 @@ namespace linker.messenger.sforward.client
|
|||||||
this.sForwardClientStore = sForwardClientStore;
|
this.sForwardClientStore = sForwardClientStore;
|
||||||
this.serializer = serializer;
|
this.serializer = serializer;
|
||||||
this.accessStore = accessStore;
|
this.accessStore = accessStore;
|
||||||
|
this.sForwardPlanHandle = sForwardPlanHandle;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -146,6 +148,42 @@ namespace linker.messenger.sforward.client
|
|||||||
}).ConfigureAwait(false);
|
}).ConfigureAwait(false);
|
||||||
return resp.Code == MessageResponeCodes.OK && resp.Data.Span.SequenceEqual(Helper.TrueArray);
|
return resp.Code == MessageResponeCodes.OK && resp.Data.Span.SequenceEqual(Helper.TrueArray);
|
||||||
}
|
}
|
||||||
|
public async Task<bool> Start(ApiControllerParamsInfo param)
|
||||||
|
{
|
||||||
|
SForwardRemoveForwardInfo info = param.Content.DeJson<SForwardRemoveForwardInfo>();
|
||||||
|
if (info.MachineId == signInClientStore.Id)
|
||||||
|
{
|
||||||
|
if (accessStore.HasAccess(AccessValue.ForwardSelf) == false) return false;
|
||||||
|
forwardTransfer.Start(info.Id);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (accessStore.HasAccess(AccessValue.ForwardOther) == false) return false;
|
||||||
|
await messengerSender.SendOnly(new MessageRequestWrap
|
||||||
|
{
|
||||||
|
Connection = signInClientState.Connection,
|
||||||
|
MessengerId = (ushort)SForwardMessengerIds.StartClientForward,
|
||||||
|
Payload = serializer.Serialize(info)
|
||||||
|
}).ConfigureAwait(false);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
public async Task<bool> Stop(ApiControllerParamsInfo param)
|
||||||
|
{
|
||||||
|
SForwardRemoveForwardInfo info = param.Content.DeJson<SForwardRemoveForwardInfo>();
|
||||||
|
if (info.MachineId == signInClientStore.Id)
|
||||||
|
{
|
||||||
|
if (accessStore.HasAccess(AccessValue.ForwardSelf) == false) return false;
|
||||||
|
forwardTransfer.Stop(info.Id);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (accessStore.HasAccess(AccessValue.ForwardOther) == false) return false;
|
||||||
|
await messengerSender.SendOnly(new MessageRequestWrap
|
||||||
|
{
|
||||||
|
Connection = signInClientState.Connection,
|
||||||
|
MessengerId = (ushort)SForwardMessengerIds.StopClientForward,
|
||||||
|
Payload = serializer.Serialize(info)
|
||||||
|
}).ConfigureAwait(false);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 测试服务
|
/// 测试服务
|
||||||
|
|||||||
@@ -9,8 +9,8 @@ namespace linker.messenger.sforward.client
|
|||||||
public sealed class SForwardClientTransfer
|
public sealed class SForwardClientTransfer
|
||||||
{
|
{
|
||||||
public Action OnChanged { get; set; } = () => { };
|
public Action OnChanged { get; set; } = () => { };
|
||||||
public Action<long> OnOpen = (id) => { };
|
public Action<long, string> OnOpen = (id,flag) => { };
|
||||||
public Action<long> OnClose = (id) => { };
|
public Action<long, string> OnClose = (id, flag) => { };
|
||||||
|
|
||||||
private readonly SignInClientState signInClientState;
|
private readonly SignInClientState signInClientState;
|
||||||
private readonly IMessengerSender messengerSender;
|
private readonly IMessengerSender messengerSender;
|
||||||
@@ -25,50 +25,32 @@ namespace linker.messenger.sforward.client
|
|||||||
this.signInClientStore = signInClientStore;
|
this.signInClientStore = signInClientStore;
|
||||||
this.sForwardClientStore = sForwardClientStore;
|
this.sForwardClientStore = sForwardClientStore;
|
||||||
|
|
||||||
//也有可能是服务端重启导致重新上线,所以不能在首次登录启动,要每次登录都尝试添加一下
|
|
||||||
signInClientState.OnSignInSuccess += (i) => Start();
|
|
||||||
this.serializer = serializer;
|
this.serializer = serializer;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Start(int id)
|
public void Start(long id,string flag = "")
|
||||||
{
|
|
||||||
SForwardInfo forwardInfo = sForwardClientStore.Get(id);
|
|
||||||
if(forwardInfo != null)
|
|
||||||
{
|
|
||||||
Start(forwardInfo);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public void Stop(int id)
|
|
||||||
{
|
{
|
||||||
SForwardInfo forwardInfo = sForwardClientStore.Get(id);
|
SForwardInfo forwardInfo = sForwardClientStore.Get(id);
|
||||||
if (forwardInfo != null)
|
if (forwardInfo != null)
|
||||||
{
|
{
|
||||||
Stop(forwardInfo);
|
Start(forwardInfo, flag);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
private void Start()
|
public void Stop(long id, string flag = "")
|
||||||
{
|
{
|
||||||
foreach (var item in sForwardClientStore.Get())
|
SForwardInfo forwardInfo = sForwardClientStore.Get(id);
|
||||||
|
if (forwardInfo != null)
|
||||||
{
|
{
|
||||||
if (item.Started)
|
Stop(forwardInfo, flag);
|
||||||
{
|
|
||||||
Start(item);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Stop(item);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
private void Start(SForwardInfo forwardInfo)
|
private void Start(SForwardInfo forwardInfo, string flag = "")
|
||||||
{
|
{
|
||||||
if (forwardInfo.Proxy) return;
|
|
||||||
if (forwardInfo.RemotePort == 0 && string.IsNullOrWhiteSpace(forwardInfo.Domain))
|
if (forwardInfo.RemotePort == 0 && string.IsNullOrWhiteSpace(forwardInfo.Domain))
|
||||||
{
|
{
|
||||||
sForwardClientStore.Update(forwardInfo.Id, false, forwardInfo.Proxy, $"Please use port or domain");
|
sForwardClientStore.Update(forwardInfo.Id, false, $"Please use port or domain");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (LoggerHelper.Instance.LoggerLevel <= LoggerTypes.DEBUG)
|
if (LoggerHelper.Instance.LoggerLevel <= LoggerTypes.DEBUG)
|
||||||
@@ -86,16 +68,21 @@ namespace linker.messenger.sforward.client
|
|||||||
forwardInfo.BufferSize = sForwardAddResultInfo.BufferSize;
|
forwardInfo.BufferSize = sForwardAddResultInfo.BufferSize;
|
||||||
if (sForwardAddResultInfo.Success)
|
if (sForwardAddResultInfo.Success)
|
||||||
{
|
{
|
||||||
sForwardClientStore.Update(forwardInfo.Id, forwardInfo.Started, true, string.Empty);
|
sForwardClientStore.Update(forwardInfo.Id, true, string.Empty);
|
||||||
LoggerHelper.Instance.Debug(sForwardAddResultInfo.Message);
|
LoggerHelper.Instance.Debug(sForwardAddResultInfo.Message);
|
||||||
OnOpen(forwardInfo.Id);
|
OnOpen(forwardInfo.Id, flag);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
sForwardClientStore.Update(forwardInfo.Id, false, forwardInfo.Proxy, sForwardAddResultInfo.Message);
|
sForwardClientStore.Update(forwardInfo.Id, false, sForwardAddResultInfo.Message);
|
||||||
LoggerHelper.Instance.Error(sForwardAddResultInfo.Message);
|
LoggerHelper.Instance.Error(sForwardAddResultInfo.Message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
sForwardClientStore.Update(forwardInfo.Id, false, string.Empty);
|
||||||
|
}
|
||||||
|
|
||||||
OnChanged();
|
OnChanged();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -107,39 +94,23 @@ namespace linker.messenger.sforward.client
|
|||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
private void Stop(SForwardInfo forwardInfo)
|
private void Stop(SForwardInfo forwardInfo, string flag = "")
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (forwardInfo.Proxy)
|
if (LoggerHelper.Instance.LoggerLevel <= LoggerTypes.DEBUG)
|
||||||
|
LoggerHelper.Instance.Info($"stop sforward {forwardInfo.ToJson()}");
|
||||||
|
messengerSender.SendReply(new MessageRequestWrap
|
||||||
{
|
{
|
||||||
if (LoggerHelper.Instance.LoggerLevel <= LoggerTypes.DEBUG)
|
Connection = signInClientState.Connection,
|
||||||
LoggerHelper.Instance.Info($"stop sforward {forwardInfo.ToJson()}");
|
MessengerId = (ushort)SForwardMessengerIds.Remove,
|
||||||
messengerSender.SendReply(new MessageRequestWrap
|
Payload = serializer.Serialize(new SForwardAddInfo { Domain = forwardInfo.Domain, RemotePort = forwardInfo.RemotePort, SecretKey = sForwardClientStore.SecretKey })
|
||||||
{
|
}).ContinueWith((result) =>
|
||||||
Connection = signInClientState.Connection,
|
{
|
||||||
MessengerId = (ushort)SForwardMessengerIds.Remove,
|
OnClose(forwardInfo.Id, flag);
|
||||||
Payload = serializer.Serialize(new SForwardAddInfo { Domain = forwardInfo.Domain, RemotePort = forwardInfo.RemotePort, SecretKey = sForwardClientStore.SecretKey })
|
sForwardClientStore.Update(forwardInfo.Id, false, string.Empty);
|
||||||
}).ContinueWith((result) =>
|
OnChanged();
|
||||||
{
|
});
|
||||||
if (result.Result.Code == MessageResponeCodes.OK)
|
|
||||||
{
|
|
||||||
SForwardAddResultInfo sForwardAddResultInfo = serializer.Deserialize<SForwardAddResultInfo>(result.Result.Data.Span);
|
|
||||||
if (sForwardAddResultInfo.Success)
|
|
||||||
{
|
|
||||||
sForwardClientStore.Update(forwardInfo.Id, forwardInfo.Started, false, string.Empty);
|
|
||||||
LoggerHelper.Instance.Debug(sForwardAddResultInfo.Message);
|
|
||||||
OnClose(forwardInfo.Id);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
sForwardClientStore.Update(forwardInfo.Id, forwardInfo.Started, forwardInfo.Proxy, string.Empty);
|
|
||||||
LoggerHelper.Instance.Error(sForwardAddResultInfo.Message);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
OnChanged();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
@@ -151,14 +122,11 @@ namespace linker.messenger.sforward.client
|
|||||||
public bool Add(SForwardInfo forwardInfo)
|
public bool Add(SForwardInfo forwardInfo)
|
||||||
{
|
{
|
||||||
sForwardClientStore.Add(forwardInfo);
|
sForwardClientStore.Add(forwardInfo);
|
||||||
Start();
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
public bool Remove(int id)
|
public bool Remove(int id)
|
||||||
{
|
{
|
||||||
sForwardClientStore.Update(id, false);
|
Stop(id);
|
||||||
Start();
|
|
||||||
|
|
||||||
sForwardClientStore.Remove(id);
|
sForwardClientStore.Remove(id);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,12 +6,19 @@ namespace linker.messenger.sforward.client
|
|||||||
{
|
{
|
||||||
public string CategoryName => "sforward";
|
public string CategoryName => "sforward";
|
||||||
|
|
||||||
|
public string flag = "plan";
|
||||||
|
|
||||||
private readonly SForwardClientTransfer sForwardClientTransfer;
|
private readonly SForwardClientTransfer sForwardClientTransfer;
|
||||||
public SForwardPlanHandle(SForwardClientTransfer sForwardClientTransfer)
|
private readonly PlanTransfer planTransfer;
|
||||||
|
public SForwardPlanHandle(SForwardClientTransfer sForwardClientTransfer, PlanTransfer planTransfer)
|
||||||
{
|
{
|
||||||
this.sForwardClientTransfer = sForwardClientTransfer;
|
this.sForwardClientTransfer = sForwardClientTransfer;
|
||||||
|
this.planTransfer = planTransfer;
|
||||||
|
|
||||||
|
sForwardClientTransfer.OnOpen += (id, _flag) => { if (_flag != flag) planTransfer.Trigger(CategoryName, id.ToString(), "start"); };
|
||||||
|
sForwardClientTransfer.OnClose += (id, _flag) => { if (_flag != flag) planTransfer.Trigger(CategoryName, id.ToString(), "stop"); };
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task HandleAsync(string handle, string key, string value)
|
public async Task HandleAsync(string handle, string key, string value)
|
||||||
{
|
{
|
||||||
if (int.TryParse(key, out int id) == false) return;
|
if (int.TryParse(key, out int id) == false) return;
|
||||||
@@ -19,10 +26,10 @@ namespace linker.messenger.sforward.client
|
|||||||
switch (handle)
|
switch (handle)
|
||||||
{
|
{
|
||||||
case "start":
|
case "start":
|
||||||
sForwardClientTransfer.Start(id);
|
sForwardClientTransfer.Start(id, flag);
|
||||||
break;
|
break;
|
||||||
case "stop":
|
case "stop":
|
||||||
sForwardClientTransfer.Stop(id);
|
sForwardClientTransfer.Stop(id, flag);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -302,6 +302,35 @@ namespace linker.plugins.sforward.messenger
|
|||||||
}).ConfigureAwait(false);
|
}).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[MessengerId((ushort)SForwardMessengerIds.StartClientForward)]
|
||||||
|
public async Task StartClientForward(IConnection connection)
|
||||||
|
{
|
||||||
|
SForwardRemoveForwardInfo info = serializer.Deserialize<SForwardRemoveForwardInfo>(connection.ReceiveRequestWrap.Payload.Span);
|
||||||
|
if (signCaching.TryGet(info.MachineId, out SignCacheInfo cacheTo) && signCaching.TryGet(connection.Id, out SignCacheInfo cacheFrom) && cacheFrom.GroupId == cacheTo.GroupId)
|
||||||
|
{
|
||||||
|
await sender.SendOnly(new MessageRequestWrap
|
||||||
|
{
|
||||||
|
Connection = cacheTo.Connection,
|
||||||
|
MessengerId = (ushort)SForwardMessengerIds.StartClient,
|
||||||
|
Payload = serializer.Serialize(info.Id)
|
||||||
|
}).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
[MessengerId((ushort)SForwardMessengerIds.StopClientForward)]
|
||||||
|
public async Task StopClientForward(IConnection connection)
|
||||||
|
{
|
||||||
|
SForwardRemoveForwardInfo info = serializer.Deserialize<SForwardRemoveForwardInfo>(connection.ReceiveRequestWrap.Payload.Span);
|
||||||
|
if (signCaching.TryGet(info.MachineId, out SignCacheInfo cacheTo) && signCaching.TryGet(connection.Id, out SignCacheInfo cacheFrom) && cacheFrom.GroupId == cacheTo.GroupId)
|
||||||
|
{
|
||||||
|
await sender.SendOnly(new MessageRequestWrap
|
||||||
|
{
|
||||||
|
Connection = cacheTo.Connection,
|
||||||
|
MessengerId = (ushort)SForwardMessengerIds.StopClient,
|
||||||
|
Payload = serializer.Serialize(info.Id)
|
||||||
|
}).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 测试对端的穿透记录
|
/// 测试对端的穿透记录
|
||||||
@@ -401,12 +430,14 @@ namespace linker.plugins.sforward.messenger
|
|||||||
private readonly SForwardClientTransfer sForwardTransfer;
|
private readonly SForwardClientTransfer sForwardTransfer;
|
||||||
private readonly ISForwardClientStore sForwardClientStore;
|
private readonly ISForwardClientStore sForwardClientStore;
|
||||||
private readonly ISerializer serializer;
|
private readonly ISerializer serializer;
|
||||||
public SForwardClientMessenger(SForwardProxy proxy, SForwardClientTransfer sForwardTransfer, ISForwardClientStore sForwardClientStore, ISerializer serializer)
|
private readonly SForwardPlanHandle sForwardPlanHandle;
|
||||||
|
public SForwardClientMessenger(SForwardProxy proxy, SForwardClientTransfer sForwardTransfer, ISForwardClientStore sForwardClientStore, ISerializer serializer, SForwardPlanHandle sForwardPlanHandle)
|
||||||
{
|
{
|
||||||
this.proxy = proxy;
|
this.proxy = proxy;
|
||||||
this.sForwardTransfer = sForwardTransfer;
|
this.sForwardTransfer = sForwardTransfer;
|
||||||
this.sForwardClientStore = sForwardClientStore;
|
this.sForwardClientStore = sForwardClientStore;
|
||||||
this.serializer = serializer;
|
this.serializer = serializer;
|
||||||
|
this.sForwardPlanHandle = sForwardPlanHandle;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -441,6 +472,19 @@ namespace linker.plugins.sforward.messenger
|
|||||||
sForwardTransfer.Remove(id);
|
sForwardTransfer.Remove(id);
|
||||||
connection.Write(Helper.TrueArray);
|
connection.Write(Helper.TrueArray);
|
||||||
}
|
}
|
||||||
|
[MessengerId((ushort)SForwardMessengerIds.StartClient)]
|
||||||
|
public void StartClient(IConnection connection)
|
||||||
|
{
|
||||||
|
int id = serializer.Deserialize<int>(connection.ReceiveRequestWrap.Payload.Span);
|
||||||
|
sForwardTransfer.Start(id);
|
||||||
|
}
|
||||||
|
[MessengerId((ushort)SForwardMessengerIds.StopClient)]
|
||||||
|
public void StopClient(IConnection connection)
|
||||||
|
{
|
||||||
|
int id = serializer.Deserialize<int>(connection.ReceiveRequestWrap.Payload.Span);
|
||||||
|
sForwardTransfer.Stop(id);
|
||||||
|
}
|
||||||
|
|
||||||
// <summary>
|
// <summary>
|
||||||
/// 测试
|
/// 测试
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -20,6 +20,12 @@
|
|||||||
TestClient = 2311,
|
TestClient = 2311,
|
||||||
TestClientForward = 2312,
|
TestClientForward = 2312,
|
||||||
|
|
||||||
|
|
||||||
|
StartClient = 2313,
|
||||||
|
StartClientForward = 2314,
|
||||||
|
StopClient = 2315,
|
||||||
|
StopClientForward = 2316,
|
||||||
|
|
||||||
Max = 2399
|
Max = 2399
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,25 +6,13 @@ namespace linker.messenger.store.file.forward
|
|||||||
{
|
{
|
||||||
public sealed class ForwardClientStore : IForwardClientStore
|
public sealed class ForwardClientStore : IForwardClientStore
|
||||||
{
|
{
|
||||||
private readonly RunningConfig runningConfig;
|
|
||||||
private readonly Storefactory dBfactory;
|
private readonly Storefactory dBfactory;
|
||||||
private readonly ILiteCollection<ForwardInfo> liteCollection;
|
private readonly ILiteCollection<ForwardInfo> liteCollection;
|
||||||
public ForwardClientStore(RunningConfig runningConfig, Storefactory dBfactory)
|
public ForwardClientStore(Storefactory dBfactory)
|
||||||
{
|
{
|
||||||
this.dBfactory = dBfactory;
|
this.dBfactory = dBfactory;
|
||||||
liteCollection = dBfactory.GetCollection<ForwardInfo>("forward");
|
liteCollection = dBfactory.GetCollection<ForwardInfo>("forward");
|
||||||
this.runningConfig = runningConfig;
|
liteCollection.UpdateMany(c => new ForwardInfo { Proxy = false }, c => c.Proxy == true);
|
||||||
|
|
||||||
foreach (var item in runningConfig.Data.Forwards)
|
|
||||||
{
|
|
||||||
item.Proxy = false;
|
|
||||||
item.Id = 0;
|
|
||||||
liteCollection.Insert(item);
|
|
||||||
}
|
|
||||||
runningConfig.Data.Forwards = new List<ForwardInfo>();
|
|
||||||
runningConfig.Data.Update();
|
|
||||||
|
|
||||||
liteCollection.UpdateMany(c => new ForwardInfo { Proxy = false },c=>c.Proxy==true);
|
|
||||||
}
|
}
|
||||||
public int Count()
|
public int Count()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ namespace linker.messenger.store.file
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 服务器穿透列表
|
/// 服务器穿透列表
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public List<SForwardInfo> SForwards { get; set; } = new List<SForwardInfo>();
|
//public List<SForwardInfo> SForwards { get; set; } = new List<SForwardInfo>();
|
||||||
}
|
}
|
||||||
public sealed partial class ConfigClientInfo
|
public sealed partial class ConfigClientInfo
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -11,28 +11,16 @@ namespace linker.messenger.store.file.sforward
|
|||||||
public string SecretKey => fileConfig.Data.Client.SForward.SecretKey;
|
public string SecretKey => fileConfig.Data.Client.SForward.SecretKey;
|
||||||
|
|
||||||
private readonly FileConfig fileConfig;
|
private readonly FileConfig fileConfig;
|
||||||
private readonly RunningConfig runningConfig;
|
|
||||||
private readonly Storefactory dBfactory;
|
private readonly Storefactory dBfactory;
|
||||||
private readonly ILiteCollection<SForwardInfo> liteCollection;
|
private readonly ILiteCollection<SForwardInfo> liteCollection;
|
||||||
|
|
||||||
public SForwardClientStore(FileConfig fileConfig, RunningConfig runningConfig, Storefactory dBfactory)
|
public SForwardClientStore(FileConfig fileConfig, Storefactory dBfactory)
|
||||||
{
|
{
|
||||||
|
this.fileConfig = fileConfig;
|
||||||
|
|
||||||
this.dBfactory = dBfactory;
|
this.dBfactory = dBfactory;
|
||||||
liteCollection = dBfactory.GetCollection<SForwardInfo>("sforward");
|
liteCollection = dBfactory.GetCollection<SForwardInfo>("sforward");
|
||||||
|
liteCollection.UpdateMany(c => new SForwardInfo { Started = false }, c => c.Started == true);
|
||||||
this.fileConfig = fileConfig;
|
|
||||||
this.runningConfig = runningConfig;
|
|
||||||
|
|
||||||
foreach (var item in runningConfig.Data.SForwards)
|
|
||||||
{
|
|
||||||
item.Proxy = false;
|
|
||||||
item.Id = 0;
|
|
||||||
liteCollection.Insert(item);
|
|
||||||
}
|
|
||||||
runningConfig.Data.SForwards = new List<SForwardInfo>();
|
|
||||||
runningConfig.Data.Update();
|
|
||||||
|
|
||||||
liteCollection.UpdateMany(c => new SForwardInfo { Proxy = false }, c => c.Proxy == true);
|
|
||||||
}
|
}
|
||||||
public bool SetSecretKey(string key)
|
public bool SetSecretKey(string key)
|
||||||
{
|
{
|
||||||
@@ -104,10 +92,6 @@ namespace linker.messenger.store.file.sforward
|
|||||||
{
|
{
|
||||||
return liteCollection.UpdateMany(c => new SForwardInfo { Started = started, Msg = msg }, c => c.Id == id) > 0;
|
return liteCollection.UpdateMany(c => new SForwardInfo { Started = started, Msg = msg }, c => c.Id == id) > 0;
|
||||||
}
|
}
|
||||||
public bool Update(long id, bool started, bool proxy, string msg)
|
|
||||||
{
|
|
||||||
return liteCollection.UpdateMany(c => new SForwardInfo { Started = started, Proxy = proxy, Msg = msg }, c => c.Id == id) > 0;
|
|
||||||
}
|
|
||||||
public bool Update(long id, bool started)
|
public bool Update(long id, bool started)
|
||||||
{
|
{
|
||||||
return liteCollection.UpdateMany(c => new SForwardInfo { Started = started }, c => c.Id == id) > 0;
|
return liteCollection.UpdateMany(c => new SForwardInfo { Started = started }, c => c.Id == id) > 0;
|
||||||
|
|||||||
@@ -132,7 +132,7 @@ namespace linker.messenger.updater
|
|||||||
MachineId = string.Empty,
|
MachineId = string.Empty,
|
||||||
Current = info.Current,
|
Current = info.Current,
|
||||||
Length = info.Length,
|
Length = info.Length,
|
||||||
Status = info.Status,
|
Status = info.Status,
|
||||||
Version = info.Version
|
Version = info.Version
|
||||||
};
|
};
|
||||||
connection.Write(serializer.Serialize(result));
|
connection.Write(serializer.Serialize(result));
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ using System.Reflection;
|
|||||||
using System.Security.Authentication;
|
using System.Security.Authentication;
|
||||||
using System.Security.Cryptography.X509Certificates;
|
using System.Security.Cryptography.X509Certificates;
|
||||||
using linker.libs.extends;
|
using linker.libs.extends;
|
||||||
using System.Diagnostics;
|
|
||||||
|
|
||||||
namespace linker.messenger
|
namespace linker.messenger
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<project ver="10" name="linker.tray.win" libEmbed="true" icon="..\linker\favicon.ico" ui="win" output="linker.tray.win.exe" CompanyName="snltty" FileDescription="linker.tray.win" LegalCopyright="Copyright (C) snltty 2024" ProductName="linker.tray.win" InternalName="linker.install.win" FileVersion="0.0.0.231" ProductVersion="0.0.0.231" publishDir="/dist/" dstrip="false" local="false" ignored="false">
|
<project ver="10" name="linker.tray.win" libEmbed="true" icon="..\linker\favicon.ico" ui="win" output="linker.tray.win.exe" CompanyName="snltty" FileDescription="linker.tray.win" LegalCopyright="Copyright (C) snltty 2024" ProductName="linker.tray.win" InternalName="linker.install.win" FileVersion="0.0.0.232" ProductVersion="0.0.0.232" publishDir="/dist/" dstrip="false" local="false" ignored="false">
|
||||||
<file name="main.aardio" path="main.aardio" comment="main.aardio"/>
|
<file name="main.aardio" path="main.aardio" comment="main.aardio"/>
|
||||||
<folder name="资源文件" path="res" embed="true" local="false" ignored="false">
|
<folder name="资源文件" path="res" embed="true" local="false" ignored="false">
|
||||||
<file name="favicon.ico" path="res\favicon.ico" comment="res\favicon.ico"/>
|
<file name="favicon.ico" path="res\favicon.ico" comment="res\favicon.ico"/>
|
||||||
|
|||||||
BIN
src/linker.tray.win/dist/linker.tray.win.exe
vendored
BIN
src/linker.tray.win/dist/linker.tray.win.exe
vendored
Binary file not shown.
@@ -1 +1 @@
|
|||||||
.table-sort th[data-v-754b053a]{border-bottom:0}.dropdown[data-v-2f0ed5e0]{border:1px solid #ddd;padding:.4rem;font-size:1.3rem;border-radius:.4rem;position:relative}.dropdown .el-icon[data-v-2f0ed5e0]{vertical-align:middle}.dropdown .badge[data-v-2f0ed5e0]{position:absolute;right:-1rem;top:-50%;border-radius:10px;background-color:#f1ae05;color:#fff;padding:.2rem .6rem;font-size:1.2rem}a[data-v-56c0e8be]{color:#666;text-decoration:underline}a.green[data-v-56c0e8be]{color:green;font-weight:700}a.download[data-v-56c0e8be]{margin-left:.6rem}a.download .el-icon[data-v-56c0e8be]{vertical-align:middle;font-weight:700;margin-left:.3rem}a.download .el-icon.loading[data-v-56c0e8be]{animation:loading-56c0e8be 1s linear infinite}a.download+a.download[data-v-56c0e8be]{margin-left:.2rem}@keyframes loading-56c0e8be{0%{transform:rotate(0deg)}to{transform:rotate(1turn)}}img.system[data-v-9f58a72e]{height:1.6rem;vertical-align:middle;margin-right:.4rem}.self[data-v-9f58a72e]{color:#d400ff}.self .el-icon[data-v-9f58a72e]{vertical-align:text-bottom}.ipaddress span[data-v-5db71b03]{vertical-align:middle}.el-input[data-v-5db71b03]{width:12rem;margin-right:.6rem}.el-col[data-v-7a697708]{text-align:left}div.point[data-v-41d1beca]{margin:-.2rem .3rem 0 -1.3rem;position:absolute}span.point[data-v-41d1beca]{width:.8rem;height:.8rem;border-radius:50%;display:inline-block;vertical-align:middle;background-color:#eee;border:1px solid #ddd;cursor:pointer;transition:.3s}span.point[data-v-41d1beca]:hover{transform:scale(2)}span.point.p2p[data-v-41d1beca]{background-color:#01c901;border:1px solid #049538}span.point.relay[data-v-41d1beca]{background-color:#e3e811;border:1px solid #b3c410}span.point.node[data-v-41d1beca]{background-color:#09dda9;border:1px solid #0cac90}.el-icon.loading[data-v-5ce8d590],a.loading[data-v-5ce8d590]{vertical-align:middle;font-weight:700;animation:loading-5ce8d590 1s linear infinite}.el-switch.is-disabled[data-v-5ce8d590]{opacity:1}.el-input[data-v-5ce8d590]{width:8rem}.delay[data-v-5ce8d590]{position:absolute;right:0;bottom:0;line-height:normal}.switch-btn[data-v-5ce8d590]{font-size:1.5rem}.any[data-v-5ce8d590]{position:absolute;left:-7px;top:-2px;line-height:normal}.any.green[data-v-5ce8d590]{background:linear-gradient(270deg,#caff00,green,#0d6d23,#e38a00,green);background-clip:text;-webkit-background-clip:text;-webkit-text-fill-color:hsla(0,0%,100%,0)}@keyframes loading-5ce8d590{0%{transform:rotate(0deg)}to{transform:rotate(1turn)}}.wrap[data-v-786fe646]{padding-right:1rem}.remark[data-v-786fe646]{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.wrap[data-v-286c7cac]{padding-right:1rem}.el-switch.is-disabled[data-v-d52cdcd0]{opacity:1}.upgrade-wrap[data-v-d52cdcd0]{border:1px solid #ddd;margin-bottom:2rem;padding:0 0 1rem 0}.el-switch.is-disabled[data-v-67ed3552]{opacity:1}.calc span[data-v-67ed3552]{display:inline-block}.calc span.label[data-v-67ed3552]{width:6rem}.el-icon.loading[data-v-3a4bfe6c],a.loading[data-v-3a4bfe6c]{vertical-align:middle;font-weight:700;animation:loading-3a4bfe6c 1s linear infinite}.el-switch.is-disabled[data-v-3a4bfe6c]{opacity:1}.el-input[data-v-3a4bfe6c]{width:8rem}.switch-btn[data-v-3a4bfe6c]{font-size:1.5rem}@keyframes loading-3a4bfe6c{0%{transform:rotate(0deg)}to{transform:rotate(1turn)}}.el-switch.is-disabled[data-v-022e3781]{opacity:1}.upgrade-wrap[data-v-022e3781]{border:1px solid #ddd;margin-bottom:2rem;padding:1rem 0 1rem 0}.lan-item[data-v-022e3781]{margin-bottom:0}.el-switch.is-disabled[data-v-64b81c5b]{opacity:1}.green[data-v-64b81c5b]{font-weight:700}img.system[data-v-64b81c5b]{height:1.4rem;margin-right:.4rem;border:1px solid #eee}.el-switch.is-disabled[data-v-6941c158]{opacity:1}ul li[data-v-6941c158]{padding-left:2rem}a[data-v-2ee190a4]{text-decoration:underline}a+a[data-v-2ee190a4]{margin-left:1rem}a.green[data-v-2ee190a4]{font-weight:700}.head[data-v-6897ed85]{padding-bottom:1rem}.green[data-v-6897ed85]{color:green;font-weight:700}.error[data-v-6897ed85]{font-weight:700}.error .el-icon[data-v-6897ed85]{vertical-align:text-bottom}.head[data-v-7d65167d]{padding-bottom:1rem}.error[data-v-7d65167d]{font-weight:700}.error .el-icon[data-v-7d65167d]{vertical-align:text-bottom}.head[data-v-8c388c86]{padding-bottom:1rem}.blue[data-v-8c388c86]{color:#409eff}.dropdown[data-v-8c388c86]{border:1px solid #ddd;padding:.4rem;font-size:1.3rem;border-radius:.4rem;position:relative}.dropdown .el-icon[data-v-8c388c86]{vertical-align:middle}.dropdown .badge[data-v-8c388c86]{position:absolute;right:-1rem;top:-50%;border-radius:10px;background-color:#f1ae05;color:#fff;padding:.2rem .6rem;font-size:1.2rem}.table-sort.el-table th.el-table__cell.is-leaf{border-bottom:0}.table-sort.el-table .el-table__inner-wrapper:before{height:0}.home-list-wrap[data-v-4766ad40]{padding:1rem}.home-list-wrap .page[data-v-4766ad40]{padding-top:1rem}.home-list-wrap .page-wrap[data-v-4766ad40]{display:inline-block}
|
.table-sort th[data-v-754b053a]{border-bottom:0}.dropdown[data-v-2f0ed5e0]{border:1px solid #ddd;padding:.4rem;font-size:1.3rem;border-radius:.4rem;position:relative}.dropdown .el-icon[data-v-2f0ed5e0]{vertical-align:middle}.dropdown .badge[data-v-2f0ed5e0]{position:absolute;right:-1rem;top:-50%;border-radius:10px;background-color:#f1ae05;color:#fff;padding:.2rem .6rem;font-size:1.2rem}a[data-v-56c0e8be]{color:#666;text-decoration:underline}a.green[data-v-56c0e8be]{color:green;font-weight:700}a.download[data-v-56c0e8be]{margin-left:.6rem}a.download .el-icon[data-v-56c0e8be]{vertical-align:middle;font-weight:700;margin-left:.3rem}a.download .el-icon.loading[data-v-56c0e8be]{animation:loading-56c0e8be 1s linear infinite}a.download+a.download[data-v-56c0e8be]{margin-left:.2rem}@keyframes loading-56c0e8be{0%{transform:rotate(0deg)}to{transform:rotate(1turn)}}img.system[data-v-9f58a72e]{height:1.6rem;vertical-align:middle;margin-right:.4rem}.self[data-v-9f58a72e]{color:#d400ff}.self .el-icon[data-v-9f58a72e]{vertical-align:text-bottom}.ipaddress span[data-v-5db71b03]{vertical-align:middle}.el-input[data-v-5db71b03]{width:12rem;margin-right:.6rem}.el-col[data-v-7a697708]{text-align:left}div.point[data-v-41d1beca]{margin:-.2rem .3rem 0 -1.3rem;position:absolute}span.point[data-v-41d1beca]{width:.8rem;height:.8rem;border-radius:50%;display:inline-block;vertical-align:middle;background-color:#eee;border:1px solid #ddd;cursor:pointer;transition:.3s}span.point[data-v-41d1beca]:hover{transform:scale(2)}span.point.p2p[data-v-41d1beca]{background-color:#01c901;border:1px solid #049538}span.point.relay[data-v-41d1beca]{background-color:#e3e811;border:1px solid #b3c410}span.point.node[data-v-41d1beca]{background-color:#09dda9;border:1px solid #0cac90}.el-icon.loading[data-v-5ce8d590],a.loading[data-v-5ce8d590]{vertical-align:middle;font-weight:700;animation:loading-5ce8d590 1s linear infinite}.el-switch.is-disabled[data-v-5ce8d590]{opacity:1}.el-input[data-v-5ce8d590]{width:8rem}.delay[data-v-5ce8d590]{position:absolute;right:0;bottom:0;line-height:normal}.switch-btn[data-v-5ce8d590]{font-size:1.5rem}.any[data-v-5ce8d590]{position:absolute;left:-7px;top:-2px;line-height:normal}.any.green[data-v-5ce8d590]{background:linear-gradient(270deg,#caff00,green,#0d6d23,#e38a00,green);background-clip:text;-webkit-background-clip:text;-webkit-text-fill-color:hsla(0,0%,100%,0)}@keyframes loading-5ce8d590{0%{transform:rotate(0deg)}to{transform:rotate(1turn)}}.wrap[data-v-786fe646]{padding-right:1rem}.remark[data-v-786fe646]{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.wrap[data-v-286c7cac]{padding-right:1rem}.el-switch.is-disabled[data-v-d52cdcd0]{opacity:1}.upgrade-wrap[data-v-d52cdcd0]{border:1px solid #ddd;margin-bottom:2rem;padding:0 0 1rem 0}.el-switch.is-disabled[data-v-67ed3552]{opacity:1}.calc span[data-v-67ed3552]{display:inline-block}.calc span.label[data-v-67ed3552]{width:6rem}.el-icon.loading[data-v-3a4bfe6c],a.loading[data-v-3a4bfe6c]{vertical-align:middle;font-weight:700;animation:loading-3a4bfe6c 1s linear infinite}.el-switch.is-disabled[data-v-3a4bfe6c]{opacity:1}.el-input[data-v-3a4bfe6c]{width:8rem}.switch-btn[data-v-3a4bfe6c]{font-size:1.5rem}@keyframes loading-3a4bfe6c{0%{transform:rotate(0deg)}to{transform:rotate(1turn)}}.el-switch.is-disabled[data-v-022e3781]{opacity:1}.upgrade-wrap[data-v-022e3781]{border:1px solid #ddd;margin-bottom:2rem;padding:1rem 0 1rem 0}.lan-item[data-v-022e3781]{margin-bottom:0}.el-switch.is-disabled[data-v-64b81c5b]{opacity:1}.green[data-v-64b81c5b]{font-weight:700}img.system[data-v-64b81c5b]{height:1.4rem;margin-right:.4rem;border:1px solid #eee}.el-switch.is-disabled[data-v-6941c158]{opacity:1}ul li[data-v-6941c158]{padding-left:2rem}a[data-v-2ee190a4]{text-decoration:underline}a+a[data-v-2ee190a4]{margin-left:1rem}a.green[data-v-2ee190a4]{font-weight:700}.head[data-v-190226d8]{padding-bottom:1rem}.green[data-v-190226d8]{color:green;font-weight:700}.error[data-v-190226d8]{font-weight:700}.error .el-icon[data-v-190226d8]{vertical-align:text-bottom}.head[data-v-380ee730]{padding-bottom:1rem}.error[data-v-380ee730]{font-weight:700}.error .el-icon[data-v-380ee730]{vertical-align:text-bottom}.plan .el-icon[data-v-380ee730]{vertical-align:middle;margin-right:.4rem}.head[data-v-8c388c86]{padding-bottom:1rem}.blue[data-v-8c388c86]{color:#409eff}.dropdown[data-v-8c388c86]{border:1px solid #ddd;padding:.4rem;font-size:1.3rem;border-radius:.4rem;position:relative}.dropdown .el-icon[data-v-8c388c86]{vertical-align:middle}.dropdown .badge[data-v-8c388c86]{position:absolute;right:-1rem;top:-50%;border-radius:10px;background-color:#f1ae05;color:#fff;padding:.2rem .6rem;font-size:1.2rem}.table-sort.el-table th.el-table__cell.is-leaf{border-bottom:0}.table-sort.el-table .el-table__inner-wrapper:before{height:0}.home-list-wrap[data-v-4766ad40]{padding:1rem}.home-list-wrap .page[data-v-4766ad40]{padding-top:1rem}.home-list-wrap .page-wrap[data-v-4766ad40]{display:inline-block}
|
||||||
File diff suppressed because one or more lines are too long
@@ -1 +1 @@
|
|||||||
<!doctype html><html lang=""><head><meta charset="utf-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width,initial-scale=1"><link rel="icon" href="favicon.ico"><title>linker.web</title><link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css" integrity="sha256-p4NxAoJBhIIN+hmNHrzRCf9tD/miZyoHS5obTRR9BMY=" crossorigin=""/><script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js" integrity="sha256-20nQCchB9co0qIjJZRGuk2/Z9VM+kNiyxNV1lvTlZBo=" crossorigin=""></script><script defer="defer" src="js/chunk-vendors.3be25225.js"></script><script defer="defer" src="js/app.3d2b2fb0.js"></script><link href="css/chunk-vendors.d8267b33.css" rel="stylesheet"><link href="css/app.7bd6c330.css" rel="stylesheet"></head><body><noscript><strong>We're sorry but linker.web doesn't work properly without JavaScript enabled. Please enable it to continue.</strong></noscript><div id="app"></div></body></html>
|
<!doctype html><html lang=""><head><meta charset="utf-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width,initial-scale=1"><link rel="icon" href="favicon.ico"><title>linker.web</title><link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css" integrity="sha256-p4NxAoJBhIIN+hmNHrzRCf9tD/miZyoHS5obTRR9BMY=" crossorigin=""/><script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js" integrity="sha256-20nQCchB9co0qIjJZRGuk2/Z9VM+kNiyxNV1lvTlZBo=" crossorigin=""></script><script defer="defer" src="js/chunk-vendors.a0b07350.js"></script><script defer="defer" src="js/app.875e12ef.js"></script><link href="css/chunk-vendors.d8267b33.css" rel="stylesheet"><link href="css/app.e96fbec3.css" rel="stylesheet"></head><body><noscript><strong>We're sorry but linker.web doesn't work properly without JavaScript enabled. Please enable it to continue.</strong></noscript><div id="app"></div></body></html>
|
||||||
1
src/linker.tray.win/web/js/148.a3bc4504.js
Normal file
1
src/linker.tray.win/web/js/148.a3bc4504.js
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -24,4 +24,11 @@ export const addSForwardInfo = (data) => {
|
|||||||
|
|
||||||
export const testLocalSForwardInfo = (data) => {
|
export const testLocalSForwardInfo = (data) => {
|
||||||
return sendWebsocketMsg('sforward/TestLocal', data);
|
return sendWebsocketMsg('sforward/TestLocal', data);
|
||||||
|
}
|
||||||
|
|
||||||
|
export const startSForwardInfo = (data) => {
|
||||||
|
return sendWebsocketMsg('sforward/start', data);
|
||||||
|
}
|
||||||
|
export const stopSForwardInfo = (data) => {
|
||||||
|
return sendWebsocketMsg('sforward/start', data);
|
||||||
}
|
}
|
||||||
@@ -2,7 +2,8 @@
|
|||||||
<el-dialog v-model="state.show" @open="handleOnShowList" append-to=".app-wrap" :title="`【${state.machineName}】的端口转发`" top="1vh" width="780">
|
<el-dialog v-model="state.show" @open="handleOnShowList" append-to=".app-wrap" :title="`【${state.machineName}】的端口转发`" top="1vh" width="780">
|
||||||
<div>
|
<div>
|
||||||
<div class="t-c head">
|
<div class="t-c head">
|
||||||
<el-button type="success" size="small" @click="handleAdd">添加</el-button>
|
<el-button type="success" size="small" @click="handleAdd" :loading="state.loading">添加</el-button>
|
||||||
|
<el-button size="small" @click="handleRefresh">刷新</el-button>
|
||||||
</div>
|
</div>
|
||||||
<el-table :data="state.data" size="small" border height="500" @cell-dblclick="handleCellClick">
|
<el-table :data="state.data" size="small" border height="500" @cell-dblclick="handleCellClick">
|
||||||
<el-table-column property="Name" label="名称" width="100">
|
<el-table-column property="Name" label="名称" width="100">
|
||||||
@@ -199,6 +200,10 @@ export default {
|
|||||||
state.timer1 = setTimeout(_getForwardInfo,1000);
|
state.timer1 = setTimeout(_getForwardInfo,1000);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
const handleRefresh = () => {
|
||||||
|
_getForwardInfo();
|
||||||
|
ElMessage.success('已刷新')
|
||||||
|
}
|
||||||
|
|
||||||
const _getSignInNames = ()=>{
|
const _getSignInNames = ()=>{
|
||||||
getSignInNames().then((res)=>{
|
getSignInNames().then((res)=>{
|
||||||
@@ -278,10 +283,13 @@ export default {
|
|||||||
saveRow(row);
|
saveRow(row);
|
||||||
}
|
}
|
||||||
const saveRow = (row) => {
|
const saveRow = (row) => {
|
||||||
|
state.loading = true;
|
||||||
row.Port = parseInt(row.Port);
|
row.Port = parseInt(row.Port);
|
||||||
addForwardInfo({machineId:state.machineId,data:row}).then(() => {
|
addForwardInfo({machineId:state.machineId,data:row}).then(() => {
|
||||||
|
state.loading = false;
|
||||||
_getForwardInfo();
|
_getForwardInfo();
|
||||||
}).catch((err) => {
|
}).catch((err) => {
|
||||||
|
state.loading = false;
|
||||||
ElMessage.error(err);
|
ElMessage.error(err);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -298,7 +306,7 @@ export default {
|
|||||||
});
|
});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
state, handleOnShowList, handleCellClick, handleAdd, handleEdit, handleEditBlur, handleDel, handleStartChange,
|
state, handleOnShowList, handleCellClick,handleRefresh, handleAdd, handleEdit, handleEditBlur, handleDel, handleStartChange,
|
||||||
handleSearch,handlePageChange
|
handleSearch,handlePageChange
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,7 +15,6 @@
|
|||||||
{{ state.ruleForm.Rule }}
|
{{ state.ruleForm.Rule }}
|
||||||
</strong>
|
</strong>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
<el-form-item label="在" prop="Rule" v-if="state.ruleForm.Method == 100">
|
<el-form-item label="在" prop="Rule" v-if="state.ruleForm.Method == 100">
|
||||||
<div class="w-100">
|
<div class="w-100">
|
||||||
<el-select v-model="state.ruleAt.type" style="width:10rem" @change="handleChange">
|
<el-select v-model="state.ruleAt.type" style="width:10rem" @change="handleChange">
|
||||||
@@ -75,6 +74,9 @@
|
|||||||
<span>后</span>
|
<span>后</span>
|
||||||
</div>
|
</div>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
<el-form-item label="内容" prop="Value">
|
||||||
|
<el-input type="textarea" resize="none" rows="5" v-model="state.ruleForm.Value"></el-input>
|
||||||
|
</el-form-item>
|
||||||
<el-form-item label="禁用" prop="Disabled">
|
<el-form-item label="禁用" prop="Disabled">
|
||||||
<el-switch v-model="state.ruleForm.Disabled" />
|
<el-switch v-model="state.ruleForm.Disabled" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
@@ -82,7 +84,7 @@
|
|||||||
<el-form-item label="" prop="Btns">
|
<el-form-item label="" prop="Btns">
|
||||||
<div class="t-c w-100">
|
<div class="t-c w-100">
|
||||||
<el-button @click="state.show = false">取消</el-button>
|
<el-button @click="state.show = false">取消</el-button>
|
||||||
<el-button type="primary" @click="handleSave">确认</el-button>
|
<el-button type="primary" @click="handleSave" :loading="state.loading">确认</el-button>
|
||||||
</div>
|
</div>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-form>
|
</el-form>
|
||||||
@@ -90,19 +92,26 @@
|
|||||||
</el-dialog>
|
</el-dialog>
|
||||||
</template>
|
</template>
|
||||||
<script>
|
<script>
|
||||||
import { inject, reactive, ref, watch } from 'vue';
|
import { addPlan } from '@/apis/plan';
|
||||||
|
import { inject, onMounted, reactive, ref, watch } from 'vue';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
props: ['data','modelValue'],
|
props: ['data','modelValue'],
|
||||||
emits: ['change','update:modelValue'],
|
emits: ['change','update:modelValue'],
|
||||||
setup(props, { emit }) {
|
setup(props, { emit }) {
|
||||||
|
|
||||||
|
const regex = /(\d+|\*)-(\d+|\*)-(\d+|\*)\s+(\d+|\*):(\d+|\*):(\d+|\*)/;
|
||||||
|
const regexNumber = /(\d+)-(\d+)-(\d+)\s+(\d+):(\d+):(\d+)/;
|
||||||
|
const regexCorn = /(.+)\s+(.+)\s+(.+)\s+(.+)\s+(.+)\s+(.+)/;
|
||||||
const ruleFormRef = ref(null);
|
const ruleFormRef = ref(null);
|
||||||
const plan = inject('plan');
|
const plan = inject('plan');
|
||||||
if(!plan.value.current.TriggerHandle && plan.value.triggers.length > 0){
|
if(!plan.value.current.TriggerHandle && plan.value.triggers.length > 0){
|
||||||
plan.value.current.TriggerHandle = plan.value.triggers[0].value;
|
plan.value.current.TriggerHandle = plan.value.triggers[0].value;
|
||||||
}
|
}
|
||||||
|
|
||||||
const state = reactive({
|
const state = reactive({
|
||||||
show: true,
|
show: true,
|
||||||
|
loading: false,
|
||||||
ruleCron:{
|
ruleCron:{
|
||||||
week:'*',
|
week:'*',
|
||||||
month:'*',
|
month:'*',
|
||||||
@@ -112,9 +121,9 @@ export default {
|
|||||||
sec:'30',
|
sec:'30',
|
||||||
},
|
},
|
||||||
ruleAt:{
|
ruleAt:{
|
||||||
type:2,
|
type:3,
|
||||||
month:1,
|
month:'*',
|
||||||
day:1,
|
day:'*',
|
||||||
hour:0,
|
hour:0,
|
||||||
min:0,
|
min:0,
|
||||||
sec:0,
|
sec:0,
|
||||||
@@ -155,8 +164,74 @@ export default {
|
|||||||
}, 300);
|
}, 300);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const decodeRuleJson = {
|
||||||
|
100:(rule)=>{
|
||||||
|
rule = rule || `*-*-* 0:0:0`;
|
||||||
|
if(regex.test(rule) == false){
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
console.log(rule.match(regex));
|
||||||
|
const [,year,month,day,hour,minute,second] = rule.match(regex);
|
||||||
|
if(minute == '*') state.ruleAt.type = 5;
|
||||||
|
else if(hour == '*') state.ruleAt.type = 4;
|
||||||
|
else if(day == '*') state.ruleAt.type = 3;
|
||||||
|
else if(month == '*') state.ruleAt.type = 2;
|
||||||
|
state.ruleAt.year = year;
|
||||||
|
state.ruleAt.month = month;
|
||||||
|
state.ruleAt.day = day;
|
||||||
|
state.ruleAt.hour = hour;
|
||||||
|
state.ruleAt.min = minute;
|
||||||
|
state.ruleAt.sec = second;
|
||||||
|
},
|
||||||
|
101:(rule)=>{
|
||||||
|
rule = rule || `0-0-0 0:0:30`;
|
||||||
|
if(regexNumber.test(rule) == false){
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const [,year,month,day,hour,minute,second] = rule.match(regexNumber);
|
||||||
|
state.ruleTimer.year = year;
|
||||||
|
state.ruleTimer.month = month;
|
||||||
|
state.ruleTimer.day = day;
|
||||||
|
state.ruleTimer.hour = hour;
|
||||||
|
state.ruleTimer.min = minute;
|
||||||
|
state.ruleTimer.sec = second;
|
||||||
|
},
|
||||||
|
102:(rule)=>{
|
||||||
|
rule = rule || `30 * * * * ?`;
|
||||||
|
if(regexCorn.test(rule) == false){
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const [,second,minute,hour,day,month,week] = rule.match(regexCorn);
|
||||||
|
state.ruleCron.sec = second;
|
||||||
|
state.ruleCron.min = minute;
|
||||||
|
state.ruleCron.hour = hour;
|
||||||
|
state.ruleCron.day = day;
|
||||||
|
state.ruleCron.month = month;
|
||||||
|
state.ruleCron.week = week;
|
||||||
|
console.log(rule.match(regexCorn));
|
||||||
|
},
|
||||||
|
103:(rule)=>{
|
||||||
|
rule = rule || `0-0-0 0:0:30`;
|
||||||
|
if(regexNumber.test(rule) == false){
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const [,year,month,day,hour,minute,second] = rule.match(regexNumber);
|
||||||
|
state.ruleTrigger.year = year;
|
||||||
|
state.ruleTrigger.month = month;
|
||||||
|
state.ruleTrigger.day = day;
|
||||||
|
state.ruleTrigger.hour = hour;
|
||||||
|
state.ruleTrigger.min = minute;
|
||||||
|
state.ruleTrigger.sec = second;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const decodeRule = ()=>{
|
||||||
|
if(state.ruleForm.Method in decodeRuleJson){
|
||||||
|
decodeRuleJson[state.ruleForm.Method](state.ruleForm.Rule);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const buildRule = {
|
const buildRuleJson = {
|
||||||
100:()=>{
|
100:()=>{
|
||||||
switch (state.ruleAt.type) {
|
switch (state.ruleAt.type) {
|
||||||
case 2:
|
case 2:
|
||||||
@@ -178,18 +253,34 @@ export default {
|
|||||||
102:()=>`${state.ruleCron.sec} ${state.ruleCron.min} ${state.ruleCron.hour} ${state.ruleCron.day} ${state.ruleCron.month} ${state.ruleCron.week}`,
|
102:()=>`${state.ruleCron.sec} ${state.ruleCron.min} ${state.ruleCron.hour} ${state.ruleCron.day} ${state.ruleCron.month} ${state.ruleCron.week}`,
|
||||||
103:()=>`${state.ruleTrigger.year}-${state.ruleTrigger.month}-${state.ruleTrigger.day} ${state.ruleTrigger.hour}:${state.ruleTrigger.min}:${state.ruleTrigger.sec}`,
|
103:()=>`${state.ruleTrigger.year}-${state.ruleTrigger.month}-${state.ruleTrigger.day} ${state.ruleTrigger.hour}:${state.ruleTrigger.min}:${state.ruleTrigger.sec}`,
|
||||||
}
|
}
|
||||||
const handleChange = () => {
|
const buildRule= ()=>{
|
||||||
if(state.ruleForm.Method in buildRule){
|
if(state.ruleForm.Method in buildRuleJson){
|
||||||
state.ruleForm.Rule = buildRule[state.ruleForm.Method]();
|
state.ruleForm.Rule = buildRuleJson[state.ruleForm.Method]();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
const handleChange = () => {
|
||||||
|
buildRule();
|
||||||
|
}
|
||||||
|
|
||||||
const handleSave = () => {
|
const handleSave = () => {
|
||||||
|
const json = JSON.parse(JSON.stringify(state.ruleForm));
|
||||||
|
|
||||||
|
state.loading = true;
|
||||||
|
addPlan(plan.value.machineid,json).then((res)=>{
|
||||||
|
state.loading = false;
|
||||||
|
state.show = false;
|
||||||
|
}).catch(()=>{
|
||||||
|
state.loading = false;
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
onMounted(()=>{
|
||||||
|
decodeRule();
|
||||||
|
handleChange();
|
||||||
|
});
|
||||||
|
return {
|
||||||
state, ruleFormRef,plan,handleChange, handleSave
|
state, ruleFormRef,plan,handleChange, handleSave
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -15,12 +15,14 @@ export default {
|
|||||||
setup (props) {
|
setup (props) {
|
||||||
|
|
||||||
const plan = ref({
|
const plan = ref({
|
||||||
|
machineid:props.machineid,
|
||||||
timer:0,
|
timer:0,
|
||||||
list:{},
|
list:{},
|
||||||
current:{},
|
current:{},
|
||||||
showEdit:false,
|
showEdit:false,
|
||||||
category:props.category||'',
|
category:props.category||'',
|
||||||
handles:props.handles||[],
|
handles:props.handles||[],
|
||||||
|
handleJson:(props.handles||[]).reduce((json,item,index)=>{ json[item.value] = item.label; return json; },{}),
|
||||||
triggers:[],
|
triggers:[],
|
||||||
methods:[
|
methods:[
|
||||||
{label:'手动',value:0},
|
{label:'手动',value:0},
|
||||||
@@ -34,8 +36,11 @@ export default {
|
|||||||
provide('plan',plan);
|
provide('plan',plan);
|
||||||
const _getPlans = () => {
|
const _getPlans = () => {
|
||||||
clearTimeout(plan.value.timer);
|
clearTimeout(plan.value.timer);
|
||||||
getPlans(props.machineid,props.category).then((res) => {
|
getPlans(plan.value.machineid,props.category).then((res) => {
|
||||||
console.log(res);
|
plan.value.list = res.reduce((json,item,index)=>{
|
||||||
|
json[`${item.Key}-${item.Handle}`] = item;
|
||||||
|
return json;
|
||||||
|
},{});
|
||||||
|
|
||||||
plan.value.timer = setTimeout(_getPlans,1000);
|
plan.value.timer = setTimeout(_getPlans,1000);
|
||||||
}).catch(()=>{
|
}).catch(()=>{
|
||||||
@@ -44,7 +49,6 @@ export default {
|
|||||||
}
|
}
|
||||||
onMounted(()=>{
|
onMounted(()=>{
|
||||||
_getPlans();
|
_getPlans();
|
||||||
console.log(props);
|
|
||||||
});
|
});
|
||||||
onUnmounted(()=>{
|
onUnmounted(()=>{
|
||||||
clearTimeout(plan.value.timer);
|
clearTimeout(plan.value.timer);
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<a href="javascript:;" class="a-line" @click="handleEdit">
|
<a href="javascript:;" class="a-line" @click="handleEdit">
|
||||||
<span v-if="item">{{ item.Rule }}</span>
|
<span v-if="item">{{ rule }}</span>
|
||||||
<span v-else>未设置</span>
|
<span v-else>未设置</span>
|
||||||
</a>
|
</a>
|
||||||
</template>
|
</template>
|
||||||
@@ -12,8 +12,65 @@ export default {
|
|||||||
props: ['keyid','handle'],
|
props: ['keyid','handle'],
|
||||||
setup (props) {
|
setup (props) {
|
||||||
|
|
||||||
|
const regex = /(\d+|\*)-(\d+|\*)-(\d+|\*)\s+(\d+|\*):(\d+|\*):(\d+|\*)/;
|
||||||
|
const regexNumber = /(\d+)-(\d+)-(\d+)\s+(\d+):(\d+):(\d+)/;
|
||||||
|
const ruleTrans = {
|
||||||
|
0:()=>`手动`,
|
||||||
|
1:()=>`网络启动后`,
|
||||||
|
100:(item,rule)=>{
|
||||||
|
if(regex.test(rule) == false){
|
||||||
|
return rule;
|
||||||
|
}
|
||||||
|
const [,year,month,day,hour,minute,second] = rule.match(regex);
|
||||||
|
if(minute == '*') return `每分钟的${second}秒`;
|
||||||
|
if(hour == '*') return `每小时的${minute}分${second}秒`;
|
||||||
|
if(day == '*') return `每天的${hour}时${minute}分${second}秒`;
|
||||||
|
if(month == '*') return `每月的${day}日${hour}时${minute}分${second}秒`;
|
||||||
|
if(year == '*') return `每年的${month}月${day}日${hour}时${minute}分${second}秒`;
|
||||||
|
},
|
||||||
|
101:(item,rule)=>{
|
||||||
|
if(regexNumber.test(rule) == false){
|
||||||
|
return rule;
|
||||||
|
}
|
||||||
|
const [,year,month,day,hour,minute,second] = rule.match(regexNumber);
|
||||||
|
const arr = [];
|
||||||
|
if(year != '0') arr.push(`${year}年`);
|
||||||
|
if(month != '0') arr.push(`${month}月`);
|
||||||
|
if(day != '0') arr.push(`${day}日`);
|
||||||
|
if(hour != '0') arr.push(`${hour}时`);
|
||||||
|
if(minute != '0') arr.push(`${minute}分`);
|
||||||
|
if(second != '0') arr.push(`${second}秒`);
|
||||||
|
return `每${arr.join('')}`
|
||||||
|
},
|
||||||
|
102:(item,rule)=>{
|
||||||
|
return `Cron : ${rule}`;
|
||||||
|
},
|
||||||
|
103:(item,rule)=>{
|
||||||
|
if(regexNumber.test(rule) == false){
|
||||||
|
return rule;
|
||||||
|
}
|
||||||
|
const [,year,month,day,hour,minute,second] = rule.match(regexNumber);
|
||||||
|
const arr = [];
|
||||||
|
if(year != '0') arr.push(`${year}年`);
|
||||||
|
if(month != '0') arr.push(`${month}月`);
|
||||||
|
if(day != '0') arr.push(`${day}日`);
|
||||||
|
if(hour != '0') arr.push(`${hour}时`);
|
||||||
|
if(minute != '0') arr.push(`${minute}分`);
|
||||||
|
if(second != '0') arr.push(`${second}秒`);
|
||||||
|
return `在【${plan.value.handleJson[item.TriggerHandle]}】的${arr.join('')}后`
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
const plan = inject('plan');
|
const plan = inject('plan');
|
||||||
const item = computed(()=>plan.value.list[`${props.keyid}-${props.handle}`]);
|
const item = computed(()=>plan.value.list[`${props.keyid}-${props.handle}`]);
|
||||||
|
const rule = computed(()=>{
|
||||||
|
if(!item.value) return '';
|
||||||
|
const method = item.value.Method;
|
||||||
|
if(ruleTrans[method]){
|
||||||
|
return ruleTrans[method](item.value,item.value.Rule);
|
||||||
|
}
|
||||||
|
return item.value.Rule;
|
||||||
|
});
|
||||||
const handleEdit = () => {
|
const handleEdit = () => {
|
||||||
plan.value.current = item.value || {
|
plan.value.current = item.value || {
|
||||||
Id:0,
|
Id:0,
|
||||||
@@ -23,14 +80,14 @@ export default {
|
|||||||
Value:'',
|
Value:'',
|
||||||
Disabled:false,
|
Disabled:false,
|
||||||
TriggerHandle:'',
|
TriggerHandle:'',
|
||||||
Method:103,
|
Method:100,
|
||||||
Rule:''
|
Rule:''
|
||||||
};
|
};
|
||||||
plan.value.triggers = JSON.parse(JSON.stringify(plan.value.handles.filter(c=>c.value != props.handle)));
|
plan.value.triggers = JSON.parse(JSON.stringify(plan.value.handles.filter(c=>c.value != props.handle)));
|
||||||
plan.value.showEdit = true;
|
plan.value.showEdit = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return {item,handleEdit}
|
return {item,rule,handleEdit}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -18,7 +18,7 @@
|
|||||||
</template>
|
</template>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column prop="Plan" label="计划" width="200">
|
<el-table-column prop="Plan" label="开启和关闭计划" width="200">
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
<div class="plan">
|
<div class="plan">
|
||||||
<p><el-icon><Select /></el-icon><PlanShow handle="start" :keyid="scope.row.Id"></PlanShow></p>
|
<p><el-icon><Select /></el-icon><PlanShow handle="start" :keyid="scope.row.Id"></PlanShow></p>
|
||||||
@@ -64,8 +64,8 @@
|
|||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column property="Started" label="状态" width="60">
|
<el-table-column property="Started" label="状态" width="60">
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
<el-switch v-model="scope.row.Started" @change="handleStartChange(scope.row)" inline-prompt
|
<el-switch disabled v-model="scope.row.Started" inline-prompt
|
||||||
active-text="是" inactive-text="否" />
|
active-text="是" inactive-text="否" @click="handleStartChange(scope.row)" />
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column label="操作" width="54">
|
<el-table-column label="操作" width="54">
|
||||||
@@ -85,7 +85,7 @@
|
|||||||
</template>
|
</template>
|
||||||
<script>
|
<script>
|
||||||
import { onMounted, onUnmounted, reactive, watch } from 'vue';
|
import { onMounted, onUnmounted, reactive, watch } from 'vue';
|
||||||
import { getSForwardInfo, removeSForwardInfo, addSForwardInfo,testLocalSForwardInfo } from '@/apis/sforward'
|
import { getSForwardInfo, removeSForwardInfo, addSForwardInfo,testLocalSForwardInfo, stopSForwardInfo, startSForwardInfo } from '@/apis/sforward'
|
||||||
import { ElMessage } from 'element-plus';
|
import { ElMessage } from 'element-plus';
|
||||||
import {WarnTriangleFilled,Delete,Select,CloseBold} from '@element-plus/icons-vue'
|
import {WarnTriangleFilled,Delete,Select,CloseBold} from '@element-plus/icons-vue'
|
||||||
import { injectGlobalData } from '@/provide';
|
import { injectGlobalData } from '@/provide';
|
||||||
@@ -206,7 +206,18 @@ export default {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
const handleStartChange = (row) => {
|
const handleStartChange = (row) => {
|
||||||
saveRow(row);
|
state.loading = true;
|
||||||
|
|
||||||
|
const func = row.Started
|
||||||
|
? stopSForwardInfo({machineid:sforward.value.machineid,id:row.Id})
|
||||||
|
: startSForwardInfo({machineid:sforward.value.machineid,id:row.Id});
|
||||||
|
func.then(() => {
|
||||||
|
state.loading = false;
|
||||||
|
_getSForwardInfo();
|
||||||
|
}).catch((err) => {
|
||||||
|
state.loading = false;
|
||||||
|
ElMessage.error(err);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
const saveRow = (row) => {
|
const saveRow = (row) => {
|
||||||
if(!row.Temp) return;
|
if(!row.Temp) return;
|
||||||
@@ -259,7 +270,8 @@ export default {
|
|||||||
}
|
}
|
||||||
.plan{
|
.plan{
|
||||||
.el-icon{
|
.el-icon{
|
||||||
vertical-align:middle
|
vertical-align:middle;
|
||||||
|
margin-right:0.4rem;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
@@ -24,7 +24,8 @@
|
|||||||
2. 优化linux的tun网卡网卡,读写分离,提高性能
|
2. 优化linux的tun网卡网卡,读写分离,提高性能
|
||||||
3. 优化windows网卡的禁用自动启用
|
3. 优化windows网卡的禁用自动启用
|
||||||
4. 增加TCP包合并。网卡IP包多个合并一起发送
|
4. 增加TCP包合并。网卡IP包多个合并一起发送
|
||||||
5. 建议更新</Description>
|
5. 内网穿透的计划任务
|
||||||
|
6. 建议更新</Description>
|
||||||
<Copyright>snltty</Copyright>
|
<Copyright>snltty</Copyright>
|
||||||
<PackageProjectUrl>https://github.com/snltty/linker</PackageProjectUrl>
|
<PackageProjectUrl>https://github.com/snltty/linker</PackageProjectUrl>
|
||||||
<RepositoryUrl>https://github.com/snltty/linker</RepositoryUrl>
|
<RepositoryUrl>https://github.com/snltty/linker</RepositoryUrl>
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
v1.7.1
|
v1.7.1
|
||||||
2025-03-28 17:28:46
|
2025-03-29 23:06:39
|
||||||
1. 优化数据同步
|
1. 优化数据同步
|
||||||
2. 优化linux的tun网卡网卡,读写分离,提高性能
|
2. 优化linux的tun网卡网卡,读写分离,提高性能
|
||||||
3. 优化windows网卡的禁用自动启用
|
3. 优化windows网卡的禁用自动启用
|
||||||
4. 增加TCP包合并。网卡IP包多个合并一起发送
|
4. 增加TCP包合并。网卡IP包多个合并一起发送
|
||||||
5. 建议更新
|
5. 内网穿透的计划任务
|
||||||
|
6. 建议更新
|
||||||
Reference in New Issue
Block a user