计划任务

This commit is contained in:
snltty
2025-03-27 17:21:16 +08:00
parent 5a80a753f7
commit c403bac74b
18 changed files with 702 additions and 64 deletions

View File

@@ -24,6 +24,16 @@
</div>
## Platforms
| | amd64 | x86 | arm64 | arm |
|-------|-------|-------|-------|-------|
| Windows | ✔ | ✔ |✔ |✔ |
| Linux | ✔ | |✔ |✔ |
| Linux Musl | ✔ | |✔ |✔ |
| Openwrt | ✔ | |✔ |✔ |
| Android(soon) | ✔ | | | |
## Overview
Using P2P or server relay, connect multiple LANs to enable communication between any networked devices across these LANs.

View File

@@ -24,6 +24,16 @@
</div>
## 支持平台
| | amd64 | x86 | arm64 | arm |
|-------|-------|-------|-------|-------|
| Windows | ✔ | ✔ |✔ |✔ |
| Linux | ✔ | |✔ |✔ |
| Linux Musl | ✔ | |✔ |✔ |
| Openwrt | ✔ | |✔ |✔ |
| Android(soon) | ✔ | | | |
## 大概意思
使用p2p或者服务器转发让你的各个局域网连通起来让各个局域网内的任意联网设备都可以相互连通
@@ -50,7 +60,7 @@
- [x] 异地组网,使用虚拟网卡,将各个客户端组建为局域网络,`点对点``点对网``网对网`
- [x] 网卡类库,你可以使用`linker.tun` tun网卡库到你的项目中
- [x] 端口转发,将客户端的端口转发到其它客户端的端口
- [x] 服务器穿透,在服务器注册端口或域名,通过访问服务器端口或域名,访问内网服务
- [x] 服务器穿透,在服务器注册端口或域名,通过访问服务器端口或域名,访问内网服务(支持计划任务,定时定长自动开启关闭)
- [x] 权限管理,主客户端拥有完全权限,可导出、配置子客户端配置,分配其管理权限
- [x] 自定义验证,通过`HTTP POST`让你可以自定义认证是否允许`连接信标``中继``内网穿透`
- [x] 流量统计,统计服务器`信标``中继``内网穿透` 的流量情况

View File

@@ -26,9 +26,9 @@ namespace linker.messenger.entry
{
private static ServiceCollection serviceCollection;
private static ServiceProvider serviceProvider;
private static OperatingManager inited = new OperatingManager();
private static OperatingManager builded = new OperatingManager();
private static OperatingManager setuped = new OperatingManager();
private static readonly OperatingManager inited = new OperatingManager();
private static readonly OperatingManager builded = new OperatingManager();
private static readonly OperatingManager setuped = new OperatingManager();
/// <summary>
/// 开始初始化
@@ -90,7 +90,7 @@ namespace linker.messenger.entry
.AddSerializerMemoryPack()
//计划任务
.AddPlan();
.AddPlanClient().AddPlanServer();
}
/// <summary>
/// 注入
@@ -145,7 +145,7 @@ namespace linker.messenger.entry
if (modules.HasFlag(ExcludeModule.Logger) == false)
serviceProvider.UseLogger();
serviceProvider.UseMessenger().UsePlan();
serviceProvider.UseMessenger();
if ((modules & ExcludeModule.StoreFile) != ExcludeModule.StoreFile)
serviceProvider.UseStoreFile(configDic);
@@ -171,6 +171,8 @@ namespace linker.messenger.entry
.UseSignInServer().UseSyncServer().UseTunnelServer().UseFlowServer();
serviceProvider.UseListen();
serviceProvider.UsePlanServer();
}
if ((commonStore.Modes & CommonModes.Client) == CommonModes.Client)
@@ -193,6 +195,8 @@ namespace linker.messenger.entry
serviceProvider.UseExRoute().UseAccessClient().UseDecenterClient().UsePcpClient().UseRelayClient().UseSyncClient().UseTunnelClient().UseFlowClient();
serviceProvider.UseSignInClient();
serviceProvider.UsePlanClient();
}
}

View File

@@ -1,19 +1,41 @@

using linker.messenger.api;
using Microsoft.Extensions.DependencyInjection;
namespace linker.messenger.plan
{
public static class Entry
{
public static ServiceCollection AddPlan(this ServiceCollection serviceCollection)
public static ServiceCollection AddPlanClient(this ServiceCollection serviceCollection)
{
serviceCollection.AddSingleton<PlanTransfer>();
serviceCollection.AddSingleton<PlanApiController>();
serviceCollection.AddSingleton<PlanClientMessenger>();
return serviceCollection;
}
public static ServiceProvider UsePlan(this ServiceProvider serviceProvider)
public static ServiceProvider UsePlanClient(this ServiceProvider serviceProvider)
{
PlanTransfer planTransfer = serviceProvider.GetService<PlanTransfer>();
MessengerResolver messengerResolver = serviceProvider.GetService<MessengerResolver>();
messengerResolver.AddMessenger(new List<IMessenger> { serviceProvider.GetService<PlanClientMessenger>() });
IApiServer apiServer = serviceProvider.GetService<IApiServer>();
apiServer.AddPlugins(new List<libs.api.IApiController> { serviceProvider.GetService<PlanApiController>() });
return serviceProvider;
}
public static ServiceCollection AddPlanServer(this ServiceCollection serviceCollection)
{
serviceCollection.AddSingleton<PlanServerMessenger>();
return serviceCollection;
}
public static ServiceProvider UsePlanServer(this ServiceProvider serviceProvider)
{
MessengerResolver messengerResolver = serviceProvider.GetService<MessengerResolver>();
messengerResolver.AddMessenger(new List<IMessenger> { serviceProvider.GetService<PlanClientMessenger>() });
return serviceProvider;
}

View File

@@ -2,10 +2,10 @@
{
public interface IPlanStore
{
public bool Add(PlanStoreInfo info);
public IEnumerable<PlanStoreInfo> Get();
public IEnumerable<PlanStoreInfo> Get(string category);
public PlanStoreInfo Get(string category, string key);
public bool Add(PlanInfo info);
public IEnumerable<PlanInfo> Get();
public IEnumerable<PlanInfo> Get(string category);
public PlanInfo Get(string category, string key);
public bool Remove(int id);
}
@@ -24,7 +24,7 @@
public Task HandleAsync(string handle, string key, string value);
}
public sealed class PlanStoreInfo
public sealed class PlanInfo
{
public int Id { get; set; }
@@ -39,6 +39,22 @@
public PlanMethod Method { get; set; }
public string Rule { get; set; }
}
public sealed class PlanGetInfo
{
public string MachineId { get; set; }
public string Category { get; set; }
public string Key { get; set; }
}
public sealed class PlanAddInfo
{
public string MachineId { get; set; }
public PlanInfo Plan { get; set; }
}
public sealed class PlanRemoveInfo
{
public string MachineId { get; set; }
public int PlanId { get; set; }
}
/// <summary>
/// 计划任务方法

View File

@@ -0,0 +1,79 @@
using linker.libs;
using linker.libs.api;
using linker.libs.extends;
using linker.messenger.signin;
namespace linker.messenger.plan
{
/// <summary>
/// 中继管理接口
/// </summary>
public sealed class PlanApiController : IApiController
{
private readonly SignInClientState signInClientState;
private readonly IMessengerSender messengerSender;
private readonly ISerializer serializer;
private readonly ISignInClientStore signInClientStore;
private readonly PlanTransfer planTransfer;
public PlanApiController( SignInClientState signInClientState, IMessengerSender messengerSender, ISerializer serializer, ISignInClientStore signInClientStore, PlanTransfer planTransfer)
{
this.signInClientState = signInClientState;
this.messengerSender = messengerSender;
this.serializer = serializer;
this.signInClientStore = signInClientStore;
this.planTransfer = planTransfer;
}
public async Task<List<PlanInfo>> Get(ApiControllerParamsInfo param)
{
PlanGetInfo info = param.Content.DeJson<PlanGetInfo>();
if (info.MachineId == signInClientStore.Id)
{
return planTransfer.Get(info.Category).ToList();
}
MessageResponeInfo resp = await messengerSender.SendReply(new MessageRequestWrap
{
Connection = signInClientState.Connection,
MessengerId = (ushort)PlanMessengerIds.GetForward,
Payload = serializer.Serialize(info)
}).ConfigureAwait(false);
if(resp.Code == MessageResponeCodes.OK)
{
return serializer.Deserialize<List<PlanInfo>>(resp.Data.Span);
}
return new List<PlanInfo>();
}
public async Task<bool> Add(ApiControllerParamsInfo param)
{
PlanAddInfo info = param.Content.DeJson<PlanAddInfo>();
if (info.MachineId == signInClientStore.Id)
{
return planTransfer.Add(info.Plan);
}
MessageResponeInfo resp = await messengerSender.SendReply(new MessageRequestWrap
{
Connection = signInClientState.Connection,
MessengerId = (ushort)PlanMessengerIds.AddForward,
Payload = serializer.Serialize(info)
}).ConfigureAwait(false);
return resp.Code == MessageResponeCodes.OK && resp.Data.Span.SequenceEqual(Helper.TrueArray);
}
public async Task<bool> Remove(ApiControllerParamsInfo param)
{
PlanRemoveInfo info = param.Content.DeJson<PlanRemoveInfo>();
if (info.MachineId == signInClientStore.Id)
{
return planTransfer.Remove(info.PlanId);
}
MessageResponeInfo resp = await messengerSender.SendReply(new MessageRequestWrap
{
Connection = signInClientState.Connection,
MessengerId = (ushort)PlanMessengerIds.RemoveForward,
Payload = serializer.Serialize(info)
}).ConfigureAwait(false);
return resp.Code == MessageResponeCodes.OK && resp.Data.Span.SequenceEqual(Helper.TrueArray);
}
}
}

View File

@@ -0,0 +1,151 @@
using linker.libs;
using linker.messenger.signin;
namespace linker.messenger.plan
{
/// <summary>
/// 计划任务客户端
/// </summary>
public class PlanClientMessenger : IMessenger
{
private readonly PlanTransfer planTransfer;
private readonly ISerializer serializer;
public PlanClientMessenger(PlanTransfer planTransfer, ISerializer serializer)
{
this.planTransfer = planTransfer;
this.serializer = serializer;
}
/// <summary>
/// 获取
/// </summary>
/// <param name="connection"></param>
[MessengerId((ushort)PlanMessengerIds.Get)]
public void Get(IConnection connection)
{
PlanGetInfo info = serializer.Deserialize<PlanGetInfo>(connection.ReceiveRequestWrap.Payload.Span);
List<PlanInfo> result = planTransfer.Get(info.Category).ToList();
connection.Write(serializer.Serialize(result));
}
/// <summary>
/// 添加
/// </summary>
/// <param name="connection"></param>
[MessengerId((ushort)PlanMessengerIds.Add)]
public void AddClient(IConnection connection)
{
PlanAddInfo info = serializer.Deserialize<PlanAddInfo>(connection.ReceiveRequestWrap.Payload.Span);
planTransfer.Add(info.Plan);
connection.Write(Helper.TrueArray);
}
// <summary>
/// 删除
/// </summary>
/// <param name="connection"></param>
[MessengerId((ushort)PlanMessengerIds.Remove)]
public void RemoveClient(IConnection connection)
{
PlanRemoveInfo info = serializer.Deserialize<PlanRemoveInfo>(connection.ReceiveRequestWrap.Payload.Span);
planTransfer.Remove(info.PlanId);
connection.Write(Helper.TrueArray);
}
}
/// <summary>
/// 计划任务服务端
/// </summary>
public class PlanServerMessenger : IMessenger
{
private readonly IMessengerSender messengerSender;
private readonly SignInServerCaching signCaching;
private readonly ISerializer serializer;
public PlanServerMessenger(IMessengerSender messengerSender, SignInServerCaching signCaching, ISerializer serializer)
{
this.messengerSender = messengerSender;
this.signCaching = signCaching;
this.serializer = serializer;
}
[MessengerId((ushort)PlanMessengerIds.GetForward)]
public async Task GetForward(IConnection connection)
{
PlanGetInfo info = serializer.Deserialize<PlanGetInfo>(connection.ReceiveRequestWrap.Payload.Span);
if (signCaching.TryGet(info.MachineId, out SignCacheInfo cacheTo) && signCaching.TryGet(connection.Id, out SignCacheInfo cacheFrom) && cacheFrom.GroupId == cacheTo.GroupId)
{
uint requestid = connection.ReceiveRequestWrap.RequestId;
await messengerSender.SendReply(new MessageRequestWrap
{
Connection = cacheTo.Connection,
MessengerId = (ushort)PlanMessengerIds.Get,
Payload = connection.ReceiveRequestWrap.Payload
}).ContinueWith(async (result) =>
{
if (result.Result.Code == MessageResponeCodes.OK)
{
await messengerSender.ReplyOnly(new MessageResponseWrap
{
Connection = connection,
Code = MessageResponeCodes.OK,
Payload = result.Result.Data,
RequestId = requestid
}, (ushort)PlanMessengerIds.GetForward).ConfigureAwait(false);
}
}).ConfigureAwait(false);
}
}
[MessengerId((ushort)PlanMessengerIds.AddForward)]
public async Task AddForward(IConnection connection)
{
PlanAddInfo info = serializer.Deserialize<PlanAddInfo>(connection.ReceiveRequestWrap.Payload.Span);
if (signCaching.TryGet(info.MachineId, out SignCacheInfo cacheTo) && signCaching.TryGet(connection.Id, out SignCacheInfo cacheFrom) && cacheFrom.GroupId == cacheTo.GroupId)
{
uint requestid = connection.ReceiveRequestWrap.RequestId;
await messengerSender.SendReply(new MessageRequestWrap
{
Connection = cacheTo.Connection,
MessengerId = (ushort)PlanMessengerIds.Add,
Payload = connection.ReceiveRequestWrap.Payload
}).ContinueWith(async (result) =>
{
if (result.Result.Code == MessageResponeCodes.OK)
{
await messengerSender.ReplyOnly(new MessageResponseWrap
{
Connection = connection,
Code = MessageResponeCodes.OK,
Payload = result.Result.Data,
RequestId = requestid
}, (ushort)PlanMessengerIds.AddForward).ConfigureAwait(false);
}
}).ConfigureAwait(false);
}
}
[MessengerId((ushort)PlanMessengerIds.RemoveForward)]
public async Task RemoveForward(IConnection connection)
{
PlanRemoveInfo info = serializer.Deserialize<PlanRemoveInfo>(connection.ReceiveRequestWrap.Payload.Span);
if (signCaching.TryGet(info.MachineId, out SignCacheInfo cacheTo) && signCaching.TryGet(connection.Id, out SignCacheInfo cacheFrom) && cacheFrom.GroupId == cacheTo.GroupId)
{
uint requestid = connection.ReceiveRequestWrap.RequestId;
await messengerSender.SendReply(new MessageRequestWrap
{
Connection = cacheTo.Connection,
MessengerId = (ushort)PlanMessengerIds.Remove,
Payload = connection.ReceiveRequestWrap.Payload
}).ContinueWith(async (result) =>
{
if (result.Result.Code == MessageResponeCodes.OK)
{
await messengerSender.ReplyOnly(new MessageResponseWrap
{
Connection = connection,
Code = MessageResponeCodes.OK,
Payload = result.Result.Data,
RequestId = requestid
}, (ushort)PlanMessengerIds.RemoveForward).ConfigureAwait(false);
}
}).ConfigureAwait(false);
}
}
}
}

View File

@@ -0,0 +1,18 @@
namespace linker.messenger.plan
{
public enum PlanMessengerIds : ushort
{
Min = 3000,
Add = 3001,
AddForward = 3002,
Remove = 3003,
RemoveForward = 3004,
Get = 3005,
GetForward = 3006,
Max = 3099
}
}

View File

@@ -27,16 +27,16 @@ namespace linker.messenger.plan
handles.AddOrUpdate(handle.CategoryName, handle, (a, b) => handle);
}
public IEnumerable<PlanStoreInfo> Get(string category)
public IEnumerable<PlanInfo> Get(string category)
{
return planStore.Get(category);
}
public bool Add(PlanStoreInfo info)
public bool Add(PlanInfo info)
{
bool result = planStore.Add(info);
caches.TryRemove(info.Id, out _);
PlanExecCacheInfo cache = new PlanExecCacheInfo { Store = info };
PlanExecCacheInfo cache = new PlanExecCacheInfo { Plan = info };
cache.Active = UpdateNextTime(cache) && string.IsNullOrWhiteSpace(info.TriggerHandle);
caches.TryAdd(info.Id, cache);
return result;
@@ -56,12 +56,12 @@ namespace linker.messenger.plan
}
private void Load()
{
foreach (PlanStoreInfo info in planStore.Get())
foreach (PlanInfo info in planStore.Get())
{
try
{
PlanExecCacheInfo cache = new PlanExecCacheInfo { Store = info };
cache.Active = (cache.Store.Method < PlanMethod.At) || (UpdateNextTime(cache) && cache.Store.Method != PlanMethod.Trigger);
PlanExecCacheInfo cache = new PlanExecCacheInfo { Plan = info };
cache.Active = (cache.Plan.Method < PlanMethod.At) || (UpdateNextTime(cache) && cache.Plan.Method != PlanMethod.Trigger);
caches.TryAdd(info.Id, cache);
}
catch (Exception)
@@ -71,33 +71,33 @@ namespace linker.messenger.plan
}
private void RunSetup()
{
foreach (PlanExecCacheInfo item in caches.Values.Where(c => c.Store.Method == PlanMethod.Setup && c.Store.Disabled == false && c.Running == false))
foreach (PlanExecCacheInfo item in caches.Values.Where(c => c.Plan.Method == PlanMethod.Setup && c.Plan.Disabled == false && c.Running == false))
{
Run(item);
}
}
private void RunLoop()
{
foreach (PlanExecCacheInfo item in caches.Values.Where(c => c.NextTime <= DateTime.Now && c.Store.Method >= PlanMethod.At))
foreach (PlanExecCacheInfo item in caches.Values.Where(c => c.NextTime <= DateTime.Now && c.Plan.Method >= PlanMethod.At))
{
Run(item);
}
}
private void Run(PlanExecCacheInfo item)
{
if(item.Store.Disabled || item.Active == false || item.Running || handles.TryGetValue(item.Store.Category, out IPlanHandle handle) == false)
if(item.Plan.Disabled || item.Active == false || item.Running || handles.TryGetValue(item.Plan.Category, out IPlanHandle handle) == false)
{
return;
}
item.Running = true;
item.Active = (item.Store.Method < PlanMethod.At) || (UpdateNextTime(item) && item.Store.Method != PlanMethod.Trigger);
item.Active = (item.Plan.Method < PlanMethod.At) || (UpdateNextTime(item) && item.Plan.Method != PlanMethod.Trigger);
item.LastTime = DateTime.Now;
handle.HandleAsync(item.Store.Handle, item.Store.Key, item.Store.Value).ContinueWith((result) =>
handle.HandleAsync(item.Plan.Handle, item.Plan.Key, item.Plan.Value).ContinueWith((result) =>
{
item.Running = false;
PlanExecCacheInfo trigger = caches.Values.FirstOrDefault(c => c.Store.Category == item.Store.Category && c.Store.Key == item.Store.Key && c.Store.TriggerHandle == item.Store.Handle && c.Store.TriggerHandle != c.Store.Handle && c.Store.Method == PlanMethod.Trigger);
PlanExecCacheInfo trigger = caches.Values.FirstOrDefault(c => c.Plan.Category == item.Plan.Category && c.Plan.Key == item.Plan.Key && c.Plan.TriggerHandle == item.Plan.Handle && c.Plan.TriggerHandle != c.Plan.Handle && c.Plan.Method == PlanMethod.Trigger);
if (trigger != null)
{
trigger.Active = UpdateNextTime(trigger);
@@ -109,19 +109,19 @@ namespace linker.messenger.plan
{
try
{
if (cache.Store.Method == PlanMethod.At)
if (cache.Plan.Method == PlanMethod.At)
{
return NextTimeAt(cache);
}
else if (cache.Store.Method == PlanMethod.Timer)
else if (cache.Plan.Method == PlanMethod.Timer)
{
return NextTimeTimer(cache);
}
else if (cache.Store.Method == PlanMethod.Cron)
else if (cache.Plan.Method == PlanMethod.Cron)
{
return NextTimeCorn(cache);
}
else if (cache.Store.Method == PlanMethod.Trigger)
else if (cache.Plan.Method == PlanMethod.Trigger)
{
return NextTimeAfter(cache);
}
@@ -136,7 +136,7 @@ namespace linker.messenger.plan
{
try
{
CronExpression cron = CronExpression.Parse(cache.Store.Rule, CronFormat.IncludeSeconds);
CronExpression cron = CronExpression.Parse(cache.Plan.Rule, CronFormat.IncludeSeconds);
DateTimeOffset? nextOccurrence = cron.GetNextOccurrence(DateTimeOffset.Now, TimeZoneInfo.Local);
if (nextOccurrence.HasValue)
{
@@ -153,15 +153,15 @@ namespace linker.messenger.plan
}
private bool NextTimeAt(PlanExecCacheInfo cache)
{
if (Regex.IsMatch(cache.Store.Rule, regex) == false)
if (Regex.IsMatch(cache.Plan.Rule, regex) == false)
{
cache.Error = $"{cache.Store.Rule} format error";
cache.Error = $"{cache.Plan.Rule} format error";
return false;
}
DateTime from = DateTime.Now;
GroupCollection groups = Regex.Match(cache.Store.Rule, regex).Groups;
GroupCollection groups = Regex.Match(cache.Plan.Rule, regex).Groups;
int year = groups[1].Value == "?" ? from.Year : int.Parse(groups[1].Value);
int month = groups[2].Value == "?" ? from.Month : int.Parse(groups[2].Value);
int day = groups[3].Value == "?" ? from.Day : int.Parse(groups[3].Value);
@@ -183,13 +183,13 @@ namespace linker.messenger.plan
}
private bool NextTimeTimer(PlanExecCacheInfo cache)
{
if (Regex.IsMatch(cache.Store.Rule, regex) == false)
if (Regex.IsMatch(cache.Plan.Rule, regex) == false)
{
cache.Error = $"{cache.Store.Rule} format error";
cache.Error = $"{cache.Plan.Rule} format error";
return false;
}
GroupCollection groups = Regex.Match(cache.Store.Rule, regex).Groups;
GroupCollection groups = Regex.Match(cache.Plan.Rule, regex).Groups;
int year = groups[1].Value == "?" ? 0 : int.Parse(groups[1].Value);
int month = groups[2].Value == "?" ? 0 : int.Parse(groups[2].Value);
int day = groups[3].Value == "?" ? 0 : int.Parse(groups[3].Value);
@@ -202,13 +202,13 @@ namespace linker.messenger.plan
}
private bool NextTimeAfter(PlanExecCacheInfo cache)
{
if (Regex.IsMatch(cache.Store.Rule, regex) == false)
if (Regex.IsMatch(cache.Plan.Rule, regex) == false)
{
cache.Error = $"{cache.Store.Rule} format error";
cache.Error = $"{cache.Plan.Rule} format error";
return false;
}
GroupCollection groups = Regex.Match(cache.Store.Rule, regex).Groups;
GroupCollection groups = Regex.Match(cache.Plan.Rule, regex).Groups;
int year = groups[1].Value == "?" ? 0 : int.Parse(groups[1].Value);
int month = groups[2].Value == "?" ? 0 : int.Parse(groups[2].Value);
int day = groups[3].Value == "?" ? 0 : int.Parse(groups[3].Value);
@@ -224,7 +224,7 @@ namespace linker.messenger.plan
public sealed class PlanExecCacheInfo
{
public PlanStoreInfo Store { get; set; }
public PlanInfo Plan { get; set; }
public DateTime LastTime { get; set; }
public DateTime NextTime { get; set; }

View File

@@ -26,7 +26,7 @@ namespace linker.messenger.serializer.memorypack
MemoryPackFormatterProvider.Register(new SignInConfigSetNameInfoFormatter());
MemoryPackFormatterProvider.Register(new SignInNamesResponseItemInfoFormatter());
MemoryPackFormatterProvider.Register(new SignInPushArgInfoFormatter());
MemoryPackFormatterProvider.Register(new SyncInfoFormatter());
@@ -51,7 +51,7 @@ namespace linker.messenger.serializer.memorypack
MemoryPackFormatterProvider.Register(new UpdaterConfirmServerInfoFormatter());
MemoryPackFormatterProvider.Register(new UpdaterClientInfoFormatter());
MemoryPackFormatterProvider.Register(new UpdaterClientInfo170Formatter());
MemoryPackFormatterProvider.Register(new UpdaterInfoFormatter());
MemoryPackFormatterProvider.Register(new UpdaterInfo170Formatter());
@@ -127,6 +127,12 @@ namespace linker.messenger.serializer.memorypack
MemoryPackFormatterProvider.Register(new TuntapLanInfoFormatter());
MemoryPackFormatterProvider.Register(new LeaseInfoFormatter());
MemoryPackFormatterProvider.Register(new PlanInfoFormatter());
MemoryPackFormatterProvider.Register(new PlanGetInfoFormatter());
MemoryPackFormatterProvider.Register(new PlanAddInfoFormatter());
MemoryPackFormatterProvider.Register(new PlanRemoveInfoFormatter());
return serviceCollection;
}
public static ServiceProvider UseSerializerMemoryPack(this ServiceProvider serviceProvider)

View File

@@ -0,0 +1,251 @@
using linker.messenger.plan;
using MemoryPack;
namespace linker.messenger.serializer.memorypack
{
[MemoryPackable]
public readonly partial struct SerializablePlanInfo
{
[MemoryPackIgnore]
public readonly PlanInfo info;
[MemoryPackInclude]
int Id => info.Id;
[MemoryPackInclude]
string Category => info.Category;
[MemoryPackInclude]
string Key => info.Key;
[MemoryPackInclude]
string Handle => info.Handle;
[MemoryPackInclude]
string Value => info.Value;
[MemoryPackInclude]
bool Disabled => info.Disabled;
[MemoryPackInclude]
string TriggerHandle => info.TriggerHandle;
[MemoryPackInclude]
PlanMethod Method => info.Method;
[MemoryPackInclude]
string Rule => info.Rule;
[MemoryPackConstructor]
SerializablePlanInfo(int id, string category, string key, string handle, string value, bool disabled, string triggerHandle, PlanMethod method, string rule)
{
var info = new PlanInfo
{
Id = id,
Category = category,
Key = key,
Handle = handle,
Value = value,
Disabled = disabled,
TriggerHandle = triggerHandle,
Method = method,
Rule = rule
};
this.info = info;
}
public SerializablePlanInfo(PlanInfo info)
{
this.info = info;
}
}
public class PlanInfoFormatter : MemoryPackFormatter<PlanInfo>
{
public override void Serialize<TBufferWriter>(ref MemoryPackWriter<TBufferWriter> writer, scoped ref PlanInfo value)
{
if (value == null)
{
writer.WriteNullObjectHeader();
return;
}
writer.WritePackable(new SerializablePlanInfo(value));
}
public override void Deserialize(ref MemoryPackReader reader, scoped ref PlanInfo value)
{
if (reader.PeekIsNull())
{
reader.Advance(1); // skip null block
value = null;
return;
}
var wrapped = reader.ReadPackable<SerializablePlanInfo>();
value = wrapped.info;
}
}
[MemoryPackable]
public readonly partial struct SerializablePlanGetInfo
{
[MemoryPackIgnore]
public readonly PlanGetInfo info;
[MemoryPackInclude]
string MachineId => info.MachineId;
[MemoryPackInclude]
string Category => info.Category;
[MemoryPackInclude]
string Key => info.Key;
[MemoryPackConstructor]
SerializablePlanGetInfo(string machineId, string category, string key)
{
var info = new PlanGetInfo
{
MachineId = machineId,
Category = category,
Key = key
};
this.info = info;
}
public SerializablePlanGetInfo(PlanGetInfo info)
{
this.info = info;
}
}
public class PlanGetInfoFormatter : MemoryPackFormatter<PlanGetInfo>
{
public override void Serialize<TBufferWriter>(ref MemoryPackWriter<TBufferWriter> writer, scoped ref PlanGetInfo value)
{
if (value == null)
{
writer.WriteNullObjectHeader();
return;
}
writer.WritePackable(new SerializablePlanGetInfo(value));
}
public override void Deserialize(ref MemoryPackReader reader, scoped ref PlanGetInfo value)
{
if (reader.PeekIsNull())
{
reader.Advance(1); // skip null block
value = null;
return;
}
var wrapped = reader.ReadPackable<SerializablePlanGetInfo>();
value = wrapped.info;
}
}
[MemoryPackable]
public readonly partial struct SerializablePlanAddInfo
{
[MemoryPackIgnore]
public readonly PlanAddInfo info;
[MemoryPackInclude]
string MachineId => info.MachineId;
[MemoryPackInclude, MemoryPackAllowSerialize]
PlanInfo Plan => info.Plan;
[MemoryPackConstructor]
SerializablePlanAddInfo(string machineId, PlanInfo plan)
{
var info = new PlanAddInfo
{
MachineId = machineId,
Plan = plan
};
this.info = info;
}
public SerializablePlanAddInfo(PlanAddInfo info)
{
this.info = info;
}
}
public class PlanAddInfoFormatter : MemoryPackFormatter<PlanAddInfo>
{
public override void Serialize<TBufferWriter>(ref MemoryPackWriter<TBufferWriter> writer, scoped ref PlanAddInfo value)
{
if (value == null)
{
writer.WriteNullObjectHeader();
return;
}
writer.WritePackable(new SerializablePlanAddInfo(value));
}
public override void Deserialize(ref MemoryPackReader reader, scoped ref PlanAddInfo value)
{
if (reader.PeekIsNull())
{
reader.Advance(1); // skip null block
value = null;
return;
}
var wrapped = reader.ReadPackable<SerializablePlanAddInfo>();
value = wrapped.info;
}
}
[MemoryPackable]
public readonly partial struct SerializablePlanRemoveInfo
{
[MemoryPackIgnore]
public readonly PlanRemoveInfo info;
[MemoryPackInclude]
string MachineId => info.MachineId;
[MemoryPackInclude, MemoryPackAllowSerialize]
int PlanId => info.PlanId;
[MemoryPackConstructor]
SerializablePlanRemoveInfo(string machineId, int planid)
{
var info = new PlanRemoveInfo
{
MachineId = machineId,
PlanId = planid
};
this.info = info;
}
public SerializablePlanRemoveInfo(PlanRemoveInfo info)
{
this.info = info;
}
}
public class PlanRemoveInfoFormatter : MemoryPackFormatter<PlanRemoveInfo>
{
public override void Serialize<TBufferWriter>(ref MemoryPackWriter<TBufferWriter> writer, scoped ref PlanRemoveInfo value)
{
if (value == null)
{
writer.WriteNullObjectHeader();
return;
}
writer.WritePackable(new SerializablePlanRemoveInfo(value));
}
public override void Deserialize(ref MemoryPackReader reader, scoped ref PlanRemoveInfo value)
{
if (reader.PeekIsNull())
{
reader.Advance(1); // skip null block
value = null;
return;
}
var wrapped = reader.ReadPackable<SerializablePlanRemoveInfo>();
value = wrapped.info;
}
}
}

View File

@@ -115,12 +115,13 @@ namespace linker.messenger.sforward.client
return forwardTransfer.Add(info.Data);
}
if (accessStore.HasAccess(AccessValue.ForwardOther) == false) return false;
return await messengerSender.SendOnly(new MessageRequestWrap
MessageResponeInfo resp = await messengerSender.SendReply(new MessageRequestWrap
{
Connection = signInClientState.Connection,
MessengerId = (ushort)SForwardMessengerIds.AddClientForward,
Payload = serializer.Serialize(info)
}).ConfigureAwait(false);
return resp.Code == MessageResponeCodes.OK && resp.Data.Span.SequenceEqual(Helper.TrueArray);
}
/// <summary>
@@ -137,12 +138,13 @@ namespace linker.messenger.sforward.client
return forwardTransfer.Remove(info.Id);
}
if (accessStore.HasAccess(AccessValue.ForwardOther) == false) return false;
return await messengerSender.SendOnly(new MessageRequestWrap
MessageResponeInfo resp = await messengerSender.SendReply(new MessageRequestWrap
{
Connection = signInClientState.Connection,
MessengerId = (ushort)SForwardMessengerIds.RemoveClientForward,
Payload = serializer.Serialize(info)
}).ConfigureAwait(false);
return resp.Code == MessageResponeCodes.OK && resp.Data.Span.SequenceEqual(Helper.TrueArray);
}
/// <summary>

View File

@@ -30,6 +30,22 @@ namespace linker.messenger.sforward.client
this.serializer = serializer;
}
public void Start(int id)
{
SForwardInfo forwardInfo = sForwardClientStore.Get(id);
if(forwardInfo != null)
{
Start(forwardInfo);
}
}
public void Stop(int id)
{
SForwardInfo forwardInfo = sForwardClientStore.Get(id);
if (forwardInfo != null)
{
Stop(forwardInfo);
}
}
private void Start()
{
foreach (var item in sForwardClientStore.Get())
@@ -70,7 +86,7 @@ namespace linker.messenger.sforward.client
forwardInfo.BufferSize = sForwardAddResultInfo.BufferSize;
if (sForwardAddResultInfo.Success)
{
sForwardClientStore.Update(forwardInfo.Id, forwardInfo.Started,true, string.Empty);
sForwardClientStore.Update(forwardInfo.Id, forwardInfo.Started, true, string.Empty);
LoggerHelper.Instance.Debug(sForwardAddResultInfo.Message);
OnOpen(forwardInfo.Id);
}
@@ -89,7 +105,7 @@ namespace linker.messenger.sforward.client
LoggerHelper.Instance.Error(ex);
OnChanged();
}
}
private void Stop(SForwardInfo forwardInfo)
{
@@ -117,7 +133,7 @@ namespace linker.messenger.sforward.client
}
else
{
sForwardClientStore.Update(forwardInfo.Id, true, forwardInfo.Proxy, string.Empty);
sForwardClientStore.Update(forwardInfo.Id, forwardInfo.Started, forwardInfo.Proxy, string.Empty);
LoggerHelper.Instance.Error(sForwardAddResultInfo.Message);
}
}
@@ -129,7 +145,7 @@ namespace linker.messenger.sforward.client
{
LoggerHelper.Instance.Error(ex);
}
}
public bool Add(SForwardInfo forwardInfo)

View File

@@ -7,12 +7,27 @@ namespace linker.messenger.sforward.client
public string CategoryName => "sforward";
public SForwardPlanHandle()
private readonly SForwardClientTransfer sForwardClientTransfer;
public SForwardPlanHandle(SForwardClientTransfer sForwardClientTransfer)
{
this.sForwardClientTransfer = sForwardClientTransfer;
}
public async Task HandleAsync(string handle, string key, string value)
{
Console.WriteLine($"[{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")}] exec plan {CategoryName} {handle} {key}->{value}");
if (int.TryParse(key, out int id) == false) return;
switch (handle)
{
case "start":
sForwardClientTransfer.Start(id);
break;
case "stop":
sForwardClientTransfer.Stop(id);
break;
default:
break;
}
await Task.CompletedTask;
}
}

View File

@@ -237,7 +237,7 @@ namespace linker.plugins.sforward.messenger
RequestId = requestid
}, (ushort)SForwardMessengerIds.GetForward).ConfigureAwait(false);
}
});
}).ConfigureAwait(false);
}
}
/// <summary>
@@ -251,11 +251,23 @@ namespace linker.plugins.sforward.messenger
if (signCaching.TryGet(info.MachineId, out SignCacheInfo cacheTo) && signCaching.TryGet(connection.Id, out SignCacheInfo cacheFrom) && cacheFrom.GroupId == cacheTo.GroupId)
{
uint requestid = connection.ReceiveRequestWrap.RequestId;
await sender.SendOnly(new MessageRequestWrap
await sender.SendReply(new MessageRequestWrap
{
Connection = cacheTo.Connection,
MessengerId = (ushort)SForwardMessengerIds.AddClient,
Payload = serializer.Serialize(info.Data)
}).ContinueWith(async (result) =>
{
if (result.Result.Code == MessageResponeCodes.OK)
{
await sender.ReplyOnly(new MessageResponseWrap
{
Connection = connection,
Code = MessageResponeCodes.OK,
Payload = result.Result.Data,
RequestId = requestid
}, (ushort)SForwardMessengerIds.AddClientForward).ConfigureAwait(false);
}
}).ConfigureAwait(false);
}
}
@@ -270,11 +282,23 @@ namespace linker.plugins.sforward.messenger
if (signCaching.TryGet(info.MachineId, out SignCacheInfo cacheTo) && signCaching.TryGet(connection.Id, out SignCacheInfo cacheFrom) && cacheFrom.GroupId == cacheTo.GroupId)
{
uint requestid = connection.ReceiveRequestWrap.RequestId;
await sender.SendOnly(new MessageRequestWrap
await sender.SendReply(new MessageRequestWrap
{
Connection = cacheTo.Connection,
MessengerId = (ushort)SForwardMessengerIds.RemoveClient,
Payload = serializer.Serialize(info.Id)
}).ContinueWith(async (result) =>
{
if (result.Result.Code == MessageResponeCodes.OK)
{
await sender.ReplyOnly(new MessageResponseWrap
{
Connection = connection,
Code = MessageResponeCodes.OK,
Payload = result.Result.Data,
RequestId = requestid
}, (ushort)SForwardMessengerIds.RemoveClientForward).ConfigureAwait(false);
}
}).ConfigureAwait(false);
}
}
@@ -404,6 +428,7 @@ namespace linker.plugins.sforward.messenger
{
SForwardInfo sForwardInfo = serializer.Deserialize<SForwardInfo>(connection.ReceiveRequestWrap.Payload.Span);
sForwardTransfer.Add(sForwardInfo);
connection.Write(Helper.TrueArray);
}
// <summary>
/// 删除
@@ -414,6 +439,7 @@ namespace linker.plugins.sforward.messenger
{
int id = serializer.Deserialize<int>(connection.ReceiveRequestWrap.Payload.Span);
sForwardTransfer.Remove(id);
connection.Write(Helper.TrueArray);
}
// <summary>
/// 测试

View File

@@ -6,13 +6,13 @@ namespace linker.messenger.store.file.plan
public sealed class PlanStore : IPlanStore
{
private readonly Storefactory dBfactory;
private readonly ILiteCollection<PlanStoreInfo> liteCollection;
private readonly ILiteCollection<PlanInfo> liteCollection;
public PlanStore(Storefactory dBfactory)
{
this.dBfactory = dBfactory;
liteCollection = dBfactory.GetCollection<PlanStoreInfo>("plan");
liteCollection = dBfactory.GetCollection<PlanInfo>("plan");
}
public bool Add(PlanStoreInfo info)
public bool Add(PlanInfo info)
{
if (info.Id == 0)
{
@@ -27,16 +27,16 @@ namespace linker.messenger.store.file.plan
return liteCollection.Update(info);
}
public IEnumerable<PlanStoreInfo> Get()
public IEnumerable<PlanInfo> Get()
{
return liteCollection.FindAll();
}
public IEnumerable<PlanStoreInfo> Get(string category)
public IEnumerable<PlanInfo> Get(string category)
{
return liteCollection.Find(c => c.Category == category);
}
public PlanStoreInfo Get(string category, string key)
public PlanInfo Get(string category, string key)
{
return liteCollection.FindOne(c => c.Category == category && c.Key == key);
}

View File

@@ -2,7 +2,7 @@
<el-dialog v-model="state.show" @open="handleOnShowList" append-to=".app-wrap" :title="`【${machineName}】的内网穿透`" top="1vh" width="700">
<div>
<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>
<el-table :data="state.data" size="small" border height="500" @cell-dblclick="handleCellClick">
@@ -100,6 +100,7 @@ export default {
timer:0,
timer1:0,
editing:false,
loading:false,
});
watch(() => state.show, (val) => {
if (!val) {
@@ -147,12 +148,15 @@ export default {
ElMessage.success('已刷新')
}
const handleAdd = () => {
state.loading = true;
const row = { Id: 0, Name: '', RemotePort: 0, LocalEP: '127.0.0.1:80',Domain:'',Temp:'' };
addSForwardInfo({machineid:sforward.value.machineid,data:row}).then(() => {
state.loading = false;
setTimeout(()=>{
_getSForwardInfo();
},100)
}).catch((err) => {
state.loading = false;
ElMessage.error(err);
});
}
@@ -181,9 +185,15 @@ export default {
saveRow(row);
}
const handleDel = (id) => {
removeSForwardInfo({machineid:sforward.value.machineid,id:id}).then(() => {
state.loading = true;
removeSForwardInfo({machineid:sforward.value.machineid,id:id})
.then(() => {
state.loading = false;
_getSForwardInfo();
})
}).catch((err) => {
state.loading = false;
ElMessage.error(err);
});
}
const handleStartChange = (row) => {
saveRow(row);
@@ -195,13 +205,15 @@ export default {
}else{
row.Domain = row.Temp;
}
state.loading = true;
addSForwardInfo({machineid:sforward.value.machineid,data:row}).then((res) => {
state.loading = false;
if(res == false){
ElMessage.error('操作失败,可能存在相同值');
}
_getSForwardInfo();
}).catch((err) => {
state.loading = false;
ElMessage.error(err);
});
}

View File

@@ -1,5 +1,5 @@
v1.7.1
2025-03-26 23:10:35
2025-03-27 17:21:16
1. 优化数据同步
2. 优化linux的tun网卡网卡读写分离提高性能
3. 优化windows网卡的禁用自动启用