chore: 我好像在别的地方写了一点。。。。 先提交上去吧

This commit is contained in:
zerlei 2024-09-07 14:46:08 +08:00
parent 8d1e08a370
commit cb05dc8215
13 changed files with 202 additions and 517 deletions

View file

@ -16,7 +16,7 @@ public class DirFileConfig
/// 除此外全部忽略最高优先级若有值ExcludeFiles 将被忽略,它是根目录的相对路径 /// 除此外全部忽略最高优先级若有值ExcludeFiles 将被忽略,它是根目录的相对路径
/// </summary> /// </summary>
public List<string>? CherryPicks { get; set; } public List<string>? CherryPicks { get; set; }
public Dir? LocalDirInfo { get; set; } public Dir? DirInfo { get; set; }
} }
public class Config public class Config
@ -26,24 +26,28 @@ public class Config
/// </summary> /// </summary>
public required string Name { get; set; } public required string Name { get; set; }
public Guid Id { get; set; } = Guid.NewGuid();
/// <summary> /// <summary>
/// 远程Url /// 远程Url
/// </summary> /// </summary>
public required string RemoteUrl { get; set; } public required string RemoteUrl { get; set; }
/// <summary> /// <summary>
/// 链接到远程的密码 /// 链接到远程的密码
/// </summary> /// </summary>
public required string RemotePwd {get;set;} public required string RemotePwd { get; set; }
/// <summary> /// <summary>
/// 是否发布数据库 /// 是否发布数据库
/// </summary> /// </summary>
public required bool IsDeployDb {get;set;} public required bool IsDeployDb { get; set; }
/// <summary> /// <summary>
/// 源数据库连接字符串(ip地址相对LocalServer) /// 源数据库连接字符串(ip地址相对LocalServer)
/// </summary> /// </summary>
public required string SrcDbConnection { get; set; } public required string SrcDbConnection { get; set; }
/// <summary> /// <summary>
/// 目标数据库连接字符串(ip地址相对RemoteServer) /// 目标数据库连接字符串(ip地址相对RemoteServer)
/// </summary> /// </summary>
@ -52,12 +56,13 @@ public class Config
/// <summary> /// <summary>
/// 同步的表 /// 同步的表
/// </summary> /// </summary>
public required List<string>? SyncDataTables {get;set;} public required List<string>? SyncDataTables { get; set; }
/// <summary> /// <summary>
/// 是否发布项目 /// 是否发布项目
/// </summary> /// </summary>
public required bool IsDeployProject {get;set;} public required bool IsDeployProject { get; set; }
/// <summary> /// <summary>
/// 项目的绝对路径 空字符串表示不发布不为空LocalRootPath将是发布路径。 /// 项目的绝对路径 空字符串表示不发布不为空LocalRootPath将是发布路径。
/// </summary> /// </summary>

View file

@ -4,7 +4,7 @@ using System.Text.Json;
namespace Common; namespace Common;
public abstract class AbsPipeLine public abstract class AbsPipeLine(bool isAES)
{ {
public abstract IAsyncEnumerable<int> Work(Func<byte[], bool> receiveCb, string addr = ""); public abstract IAsyncEnumerable<int> Work(Func<byte[], bool> receiveCb, string addr = "");
protected Func<byte[], bool> ReceiveMsg = (byte[] a) => protected Func<byte[], bool> ReceiveMsg = (byte[] a) =>
@ -26,17 +26,16 @@ public abstract class AbsPipeLine
/// <param name="msg"></param> /// <param name="msg"></param>
/// <returns></returns> /// <returns></returns>
public abstract Task SendMsg(SyncMsg msg); public abstract Task SendMsg(SyncMsg msg);
protected readonly bool IsAES = isAES;
} }
public class WebSocPipeLine<TSocket>(TSocket socket) : AbsPipeLine public class WebSocPipeLine<TSocket>(TSocket socket, bool isAES) : AbsPipeLine(isAES)
where TSocket : WebSocket where TSocket : WebSocket
{ {
public readonly TSocket Socket = socket; public readonly TSocket Socket = socket;
public override async IAsyncEnumerable<int> Work( public override async IAsyncEnumerable<int> Work(Func<byte[], bool> receiveCb, string addr = "")
Func<byte[], bool> receiveCb,
string addr = ""
)
{ {
if (Socket is ClientWebSocket CSocket) if (Socket is ClientWebSocket CSocket)
{ {
@ -94,7 +93,9 @@ public class WebSocPipeLine<TSocket>(TSocket socket) : AbsPipeLine
{ {
string msgStr = JsonSerializer.Serialize(msg); string msgStr = JsonSerializer.Serialize(msg);
await Socket.SendAsync( await Socket.SendAsync(
new ArraySegment<byte>(Encoding.UTF8.GetBytes(msgStr)), IsAES
? AESHelper.EncryptStringToBytes_Aes(msgStr)
: new ArraySegment<byte>(Encoding.UTF8.GetBytes(msgStr)),
WebSocketMessageType.Text, WebSocketMessageType.Text,
true, true,
CancellationToken.None CancellationToken.None

View file

@ -13,7 +13,7 @@ public enum SyncProcessStep
DeployProject = 2, DeployProject = 2,
DiffFileAndPack = 3, DiffFileAndPack = 3,
PackSqlServer = 4, PackSqlServer = 4,
Upload = 5, UploadAndUnpack = 5,
Publish = 6 Publish = 6
} }
public class SyncMsg(SyncMsgType msgType, SyncProcessStep step, string body) public class SyncMsg(SyncMsgType msgType, SyncProcessStep step, string body)

View file

@ -1,8 +1,9 @@
using System.Net.NetworkInformation; using System.Net.NetworkInformation;
using System.Text;
using Microsoft.AspNetCore.Mvc;
using Common;
using System.Net.WebSockets; using System.Net.WebSockets;
using System.Text;
using Common;
using Microsoft.AspNetCore.Mvc;
namespace LocalServer.Controllers namespace LocalServer.Controllers
{ {
public class LocalServerController(LocalSyncServerFactory factory) : ControllerBase public class LocalServerController(LocalSyncServerFactory factory) : ControllerBase
@ -16,9 +17,16 @@ namespace LocalServer.Controllers
{ {
try try
{ {
var webSocket = await HttpContext.WebSockets.AcceptWebSocketAsync(); if (Factory.GetServerByName(Name) == null)
var pipeLine = new WebSocPipeLine<WebSocket>(webSocket); {
Factory.CreateLocalSyncServer(pipeLine, Name); var webSocket = await HttpContext.WebSockets.AcceptWebSocketAsync();
var pipeLine = new WebSocPipeLine<WebSocket>(webSocket,false);
Factory.CreateLocalSyncServer(pipeLine, Name);
}
else
{
throw new Exception("LocalServer: 已经存在同名的发布正在进行!");
}
} }
catch (Exception e) catch (Exception e)
{ {

View file

@ -1,6 +1,4 @@
using System.Net.WebSockets; using System.Net.WebSockets;
using System.Text;
using System.Text.Json;
using Common; using Common;
namespace LocalServer; namespace LocalServer;
@ -26,30 +24,27 @@ public class LocalSyncServer
} }
} }
public string Name;
/// <summary> /// <summary>
/// 发布源连接 /// 发布源连接
/// </summary> /// </summary>
public readonly AbsPipeLine LocalPipe; public readonly AbsPipeLine LocalPipe;
public readonly AbsPipeLine RemotePipe = new WebSocPipeLine<ClientWebSocket>( public readonly AbsPipeLine RemotePipe = new WebSocPipeLine<ClientWebSocket>(
new ClientWebSocket() new ClientWebSocket(),false
); );
/// <summary>
/// 发布名称
/// </summary>
public readonly string Name;
/// <summary> /// <summary>
/// 父工程,用于释放资源 /// 父工程,用于释放资源
/// </summary> /// </summary>
public readonly LocalSyncServerFactory Factory; public readonly LocalSyncServerFactory Factory;
public LocalSyncServer(AbsPipeLine pipe, string name, LocalSyncServerFactory factory) public LocalSyncServer(AbsPipeLine pipe, LocalSyncServerFactory factory,string name)
{ {
LocalPipe = pipe; LocalPipe = pipe;
Name = name;
Factory = factory; Factory = factory;
StateHelper = new ConnectAuthorityHelper(this); StateHelper = new ConnectAuthorityHelper(this);
Name = name;
Task.Run(async () => Task.Run(async () =>
{ {

View file

@ -1,4 +1,3 @@
using System.Net.WebSockets;
using Common; using Common;
namespace LocalServer; namespace LocalServer;
@ -6,13 +5,9 @@ public class LocalSyncServerFactory
{ {
private readonly object Lock = new(); private readonly object Lock = new();
public void CreateLocalSyncServer(AbsPipeLine pipeLine, string name) public void CreateLocalSyncServer(AbsPipeLine pipeLine,string name)
{ {
if (Servers.Select(x => x.Name == name).Any()) var server = new LocalSyncServer(pipeLine, this,name);
{
throw new Exception("LocalServer:存在同名发布源!");
}
var server = new LocalSyncServer(pipeLine, name, this);
lock (Lock) lock (Lock)
{ {
Servers.Add(server); Servers.Add(server);
@ -28,4 +23,10 @@ public class LocalSyncServerFactory
Servers.Remove(server); Servers.Remove(server);
} }
} }
public LocalSyncServer? GetServerByName(string name)
{
var it = Servers.Where(x=>x.Name== name).FirstOrDefault();
return it;
}
} }

View file

@ -56,7 +56,7 @@ public abstract class StateHelpBase(
{ {
throw new Exception("Sync step error!"); throw new Exception("Sync step error!");
} }
HandleLocalMsg(syncMsg); HandleRemoteMsg(syncMsg);
return true; return true;
} }
@ -95,7 +95,7 @@ public class ConnectAuthorityHelper(LocalSyncServer context)
{ {
return Context.StateHelper.ReceiveRemoteMsg(b); return Context.StateHelper.ReceiveRemoteMsg(b);
}, },
Context.NotNullSyncConfig.RemoteUrl + "/websoc" Context.NotNullSyncConfig.RemoteUrl + "/websoc?Name=" + Context.Name
); );
await foreach (var r in rs) await foreach (var r in rs)
{ {
@ -135,7 +135,7 @@ public class DeployHelper(LocalSyncServer context)
{ {
FileName = "cmd.exe", // The command to execute (can be any command line tool) FileName = "cmd.exe", // The command to execute (can be any command line tool)
Arguments = Arguments =
$"msdeploy.exe -verb:sync -source:contentPath={Context.NotNullSyncConfig.LocalProjectAbsolutePath} -dest:contentPath={Context.NotNullSyncConfig.LocalRootPath} -disablerule:BackupRule", $" msdeploy.exe -verb:sync -source:contentPath={Context.NotNullSyncConfig.LocalProjectAbsolutePath} -dest:contentPath={Context.NotNullSyncConfig.LocalRootPath} -disablerule:BackupRule",
// The arguments to pass to the command (e.g., list directory contents) // The arguments to pass to the command (e.g., list directory contents)
RedirectStandardOutput = true, // Redirect the standard output to a string RedirectStandardOutput = true, // Redirect the standard output to a string
UseShellExecute = false, // Do not use the shell to execute the command UseShellExecute = false, // Do not use the shell to execute the command
@ -184,8 +184,8 @@ public class DiffFileAndPackHelper(LocalSyncServer context)
//提取本地文件的信息 //提取本地文件的信息
Context.NotNullSyncConfig.DirFileConfigs.ForEach(e => Context.NotNullSyncConfig.DirFileConfigs.ForEach(e =>
{ {
e.LocalDirInfo = new Dir(Context.NotNullSyncConfig.LocalRootPath + e.DirPath); e.DirInfo = new Dir(Context.NotNullSyncConfig.LocalRootPath + e.DirPath);
e.LocalDirInfo.ExtractInfo(e.CherryPicks, e.Excludes); e.DirInfo.ExtractInfo(e.CherryPicks, e.Excludes);
}); });
//将配置信息发送到remoteServer //将配置信息发送到remoteServer
Context Context
@ -195,7 +195,22 @@ public class DiffFileAndPackHelper(LocalSyncServer context)
protected override void HandleLocalMsg(SyncMsg msg) { } protected override void HandleLocalMsg(SyncMsg msg) { }
protected override void HandleRemoteMsg(SyncMsg msg) { } protected override void HandleRemoteMsg(SyncMsg msg)
{
Context.NotNullSyncConfig.DirFileConfigs =
JsonSerializer.Deserialize<List<DirFileConfig>>(msg.Body)
?? throw new Exception("LocalServer: DirFile为空");
var PackOp = new FileDirOpForPack(
Context.NotNullSyncConfig.LocalRootPath,
Context.NotNullSyncConfig.RemoteRootPath
+ "/"
+ Context.NotNullSyncConfig.Id.ToString(),
Context.NotNullSyncConfig.Id.ToString()
);
}
} }
// /// <summary> // /// <summary>

View file

@ -1,34 +1,46 @@
using System.Net.WebSockets;
using System.Text;
using Common;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using RemoteServer.Models; using RemoteServer.Models;
using System.Text;
namespace RemoteServer.Controllers; namespace RemoteServer.Controllers;
public class SyncFilesController(RemoteSyncServerFactory factory, SqliteDbContext db) : ControllerBase public class SyncFilesController(RemoteSyncServerFactory factory, SqliteDbContext db)
: ControllerBase
{ {
private readonly SqliteDbContext _db = db; private readonly SqliteDbContext _db = db;
private readonly RemoteSyncServerFactory Factory = factory; private readonly RemoteSyncServerFactory Factory = factory;
[Route("/websoc")] [Route("/websoc")]
public async Task WebsocketConnection(string Name) public async Task WebsocketConnection(string Name)
{
if (HttpContext.WebSockets.IsWebSocketRequest)
{ {
if (HttpContext.WebSockets.IsWebSocketRequest) try
{ {
try if (Factory.GetServerByName(Name) == null)
{ {
var webSocket = await HttpContext.WebSockets.AcceptWebSocketAsync(); var webSocket = await HttpContext.WebSockets.AcceptWebSocketAsync();
Factory.CreateLocalSyncServer(webSocket, Name); var pipeLine = new WebSocPipeLine<WebSocket>(webSocket,true);
Factory.CreateRemoteSyncServer(pipeLine, Name);
} }
catch (Exception e) else
{ {
HttpContext.Response.Body = new MemoryStream(Encoding.UTF8.GetBytes(e.Message)); throw new Exception("RemoteServer: 存在相同名称的发布正在进行!");
HttpContext.Response.StatusCode = StatusCodes.Status406NotAcceptable;
} }
} }
else catch (Exception e)
{ {
HttpContext.Response.StatusCode = StatusCodes.Status400BadRequest; HttpContext.Response.Body = new MemoryStream(Encoding.UTF8.GetBytes(e.Message));
HttpContext.Response.StatusCode = StatusCodes.Status406NotAcceptable;
} }
} }
else
{
HttpContext.Response.StatusCode = StatusCodes.Status400BadRequest;
}
}
[HttpGet("/GetSyncFilesLogs")] [HttpGet("/GetSyncFilesLogs")]
public IActionResult GetSyncFilesLogs( public IActionResult GetSyncFilesLogs(

View file

@ -9,14 +9,10 @@ ConfigurationBuilder configurationBuilder = new();
// Add services to the container. // Add services to the container.
//添加配置文件路径 //添加配置文件路径
configurationBuilder RemoteSyncServerFactory.NamePwd = [.. (
.SetBasePath(Directory.GetCurrentDirectory()) builder.Configuration.GetSection("NamePwds").Get<Tuple<string, string>[]>() ?? []
.AddJsonFile("appsettings.json"); )];
RemoteSyncServer.TempRootFile = builder.Configuration["TempDir"] ?? "C:/TempPack";
//加载文件
IConfiguration _configuration = configurationBuilder.Build();
RemoteSyncServer.TempRootFile = _configuration["TempDir"] ?? "C:/TempPack";
;
builder.Services.AddControllers(); builder.Services.AddControllers();
builder.Services.AddDbContext<SqliteDbContext>(opions => builder.Services.AddDbContext<SqliteDbContext>(opions =>
{ {
@ -26,6 +22,7 @@ builder.Services.AddDbContext<SqliteDbContext>(opions =>
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle // Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer(); builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen(); builder.Services.AddSwaggerGen();
builder.Services.AddSingleton<RemoteSyncServerFactory>();
var app = builder.Build(); var app = builder.Build();
// Configure the HTTP request pipeline. // Configure the HTTP request pipeline.

View file

@ -1,5 +1,5 @@
using System.Net.WebSockets; using System.Net.WebSockets;
using System.Text.Json;
using Common; using Common;
namespace RemoteServer; namespace RemoteServer;
@ -9,121 +9,68 @@ public class RemoteSyncServer
#pragma warning disable CA2211 // Non-constant fields should not be visible #pragma warning disable CA2211 // Non-constant fields should not be visible
public static string TempRootFile = "C:/TempPack"; public static string TempRootFile = "C:/TempPack";
#pragma warning restore CA2211 // Non-constant fields should not be visible #pragma warning restore CA2211 // Non-constant fields should not be visible
// public StateHelpBase StateHelper; public StateHelpBase StateHelper;
public Config? SyncConfig; public Config? SyncConfig;
public Config NotNullSyncConfig {get { public Config NotNullSyncConfig
if (SyncConfig == null) {
get
{ {
throw new ArgumentNullException("SyncConfig"); if (SyncConfig == null)
{
throw new ArgumentNullException("SyncConfig");
}
return SyncConfig;
} }
return SyncConfig; }
}}
/// <summary> /// <summary>
/// remote server /// 发布源连接
/// </summary> /// </summary>
public readonly WebSocket RemoteSocket; public readonly AbsPipeLine Pipe;
/// <summary>
/// 发布开始时间
/// </summary>
private readonly DateTime StartTime = DateTime.Now;
/// <summary>
/// 发布名称
/// </summary>
public readonly string Name;
/// <summary> /// <summary>
/// 父工程,用于释放资源 /// 父工程,用于释放资源
/// </summary> /// </summary>
public readonly RemoteSyncServerFactory Factory; public readonly RemoteSyncServerFactory Factory;
public string Name;
public RemoteSyncServer(WebSocket socket, string name, RemoteSyncServerFactory factory) public string Pwd;
public RemoteSyncServer(AbsPipeLine pipe, RemoteSyncServerFactory factory,string name,string pwd)
{ {
RemoteSocket = socket; Pipe = pipe;
Name = name;
Factory = factory; Factory = factory;
// StateHelper = new ConnectAuthorityHelper(this); Name = name;
} Pwd = pwd;
StateHelper = new ConnectAuthorityHelper(this);
Task.Run(async () =>
public async Task RemoteSocketListen()
{
string CloseMsg = "任务结束关闭";
try
{ {
//最大1MB!= var rs = Pipe.Work(
var buffer = new byte[1024 * 1024]; (byte[] b) =>
{
while (RemoteSocket.State == WebSocketState.Open) return StateHelper.ReceiveMsg(b);
}
);
try
{ {
var receiveResult = await RemoteSocket.ReceiveAsync( await foreach (var r in rs) { }
new ArraySegment<byte>(buffer),
CancellationToken.None
);
if (receiveResult.MessageType == WebSocketMessageType.Close)
{
Close(receiveResult.CloseStatusDescription);
}
else
{
// StateHelper.ReceiveLocalMsg(
// Encoding.UTF8.GetString(buffer, 0, receiveResult.Count)
// );
}
} }
} catch (Exception e)
catch (Exception e) {
{ Close(e.Message);
CloseMsg = e.Message; }
} });
finally
{
Close(CloseMsg);
}
} }
public async Task RemoteSocketSendMsg(object msgOb)
{
string msg = JsonSerializer.Serialize(msgOb);
var buffer = AESHelper.EncryptStringToBytes_Aes(msg);
await RemoteSocket.SendAsync(
buffer,
WebSocketMessageType.Text,
true,
CancellationToken.None
);
}
public void Close(string? CloseReason) public void Close(string? CloseReason)
{ {
try try
{ {
if (RemoteSocket.State == WebSocketState.Open) Pipe.Close(CloseReason);
{
RemoteSocket
.CloseAsync(
WebSocketCloseStatus.NormalClosure,
CloseReason,
CancellationToken.None
)
.Wait(60 * 1000);
}
if (RemoteSocket.State == WebSocketState.Open)
{
RemoteSocket
.CloseAsync(
WebSocketCloseStatus.NormalClosure,
CloseReason,
CancellationToken.None
)
.Wait(60 * 1000);
}
} }
catch (Exception e) catch (Exception e)
{ {
@ -132,7 +79,7 @@ public class RemoteSyncServer
} }
finally finally
{ {
Factory.RemoveLocalSyncServer(this); Factory.RemoveSyncServer(this);
} }
} }
} }

View file

@ -1,4 +1,4 @@
using System.Net.WebSockets; using Common;
namespace RemoteServer; namespace RemoteServer;
@ -6,30 +6,35 @@ public class RemoteSyncServerFactory
{ {
private readonly object Lock = new(); private readonly object Lock = new();
public void CreateLocalSyncServer(WebSocket socket, string name) #pragma warning disable CA2211 // Non-constant fields should not be visible
public static List<Tuple<string, string>> NamePwd = [];
#pragma warning restore CA2211 // Non-constant fields should not be visible
public void CreateRemoteSyncServer(AbsPipeLine pipeLine, string Name)
{ {
if (Servers.Select(x => x.Name == name).Any()) var pwd =
{ NamePwd.Where(x => x.Item1 == Name).FirstOrDefault()
throw new Exception("RemoteServer:存在同名发布源!"); ?? throw new Exception("RemoteServer: 不被允许的发布名称!");
} var server = new RemoteSyncServer(pipeLine, this, Name, pwd.Item2);
var server = new RemoteSyncServer(socket, name, this);
lock (Lock) lock (Lock)
{ {
Servers.Add(server); Servers.Add(server);
} }
//脱离当前函数栈
Task.Run(async ()=>{
await server.RemoteSocketListen();
});
} }
private readonly List<RemoteSyncServer> Servers = []; private readonly List<RemoteSyncServer> Servers = [];
public void RemoveLocalSyncServer(RemoteSyncServer server) public void RemoveSyncServer(RemoteSyncServer server)
{ {
lock (Lock) lock (Lock)
{ {
Servers.Remove(server); Servers.Remove(server);
} }
} }
public RemoteSyncServer? GetServerByName(string name)
{
var it = Servers.Where(x => x.Name == name).FirstOrDefault();
return it;
}
} }

View file

@ -14,11 +14,11 @@ namespace RemoteServer;
// } // }
public abstract class StateHelpBase( public abstract class StateHelpBase(
LocalSyncServer context, RemoteSyncServer context,
SyncProcessStep step = SyncProcessStep.Connect SyncProcessStep step = SyncProcessStep.Connect
) )
{ {
protected readonly LocalSyncServer Context = context; protected readonly RemoteSyncServer Context = context;
protected readonly SyncProcessStep Step = step; protected readonly SyncProcessStep Step = step;
@ -32,19 +32,7 @@ public abstract class StateHelpBase(
return new SyncMsg(type, Step, body); return new SyncMsg(type, Step, body);
} }
public void ReceiveLocalMsg(string msg) public bool ReceiveMsg(byte[] bytes)
{
var syncMsg =
JsonSerializer.Deserialize<SyncMsg>(msg)
?? throw new NullReferenceException("msg is null");
if (syncMsg.Step != Step)
{
throw new Exception("Sync step error!");
}
HandleLocalMsg(syncMsg);
}
public void ReceiveRemoteMsg(byte[] bytes)
{ {
var msg = AESHelper.DecryptStringFromBytes_Aes(bytes); var msg = AESHelper.DecryptStringFromBytes_Aes(bytes);
@ -55,361 +43,68 @@ public abstract class StateHelpBase(
{ {
throw new Exception("Sync step error!"); throw new Exception("Sync step error!");
} }
HandleLocalMsg(syncMsg); HandleMsg(syncMsg);
return true;
} }
protected abstract void HandleRemoteMsg(SyncMsg msg); protected abstract void HandleMsg(SyncMsg msg);
protected abstract void HandleLocalMsg(SyncMsg msg);
} }
/// <summary> /// <summary>
/// 0. 链接验证 /// 0. 链接验证
/// </summary> /// </summary>
/// <param name="context"></param> /// <param name="context"></param>
public class ConnectAuthorityHelper(LocalSyncServer context) public class ConnectAuthorityHelper(RemoteSyncServer context)
: StateHelpBase(context, SyncProcessStep.Connect) : StateHelpBase(context, SyncProcessStep.Connect)
{ {
// 如果密码错误,那么就直接关闭连接,不会进入这个方法 protected override void HandleMsg(SyncMsg msg)
protected override void HandleRemoteMsg(SyncMsg msg)
{ {
//将remote的消息传递到前端界面 if (msg.Body == Context.Pwd)
Context.LocalSocketSendMsg(msg).Wait();
//下一步
var deployHelper = new DeployHelper(Context);
Context.StateHelper = deployHelper;
deployHelper.DeployProcess();
}
protected override void HandleLocalMsg(SyncMsg msg)
{
//收到配置文件
var config = JsonSerializer.Deserialize<Config>(msg.Body);
Context.SyncConfig = config;
Context.RemoteSocketConnect().Wait(60 * 1000);
Task.Run(async () =>
{ {
if (Context.SyncConfig != null) Context.Pipe.SendMsg(CreateMsg("RemoteServer: 密码验证成功!"));
{
await Context.RemoteSocketSendMsg(CreateMsg(Context.SyncConfig.RemotePwd));
}
else
{
throw new NullReferenceException("Config is null!");
}
await Context.RemoteSocketLiten();
});
}
}
/// <summary>
/// 1. 执行发布步骤
/// </summary>
/// <param name="context"></param>
public class DeployHelper(LocalSyncServer context)
: StateHelpBase(context, SyncProcessStep.DeployProject)
{
public void DeployProcess()
{
if (Context.NotNullSyncConfig.IsDeployProject == false)
{
Context.LocalSocketSendMsg(CreateMsg("配置为不发布跳过此步骤")).Wait();
var h = new DiffFileAndPackHelper(Context);
Context.StateHelper = h;
h.DiffProcess();
} }
else else
{ {
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) throw new Exception("密码错误!");
}
}
}
public class DiffFileHelper(RemoteSyncServer context)
: StateHelpBase(context, SyncProcessStep.DiffFileAndPack)
{
protected override void HandleMsg(SyncMsg msg)
{
Context.SyncConfig = JsonSerializer.Deserialize<Config>(msg.Body);
//文件对比
Context.NotNullSyncConfig.DirFileConfigs.ForEach(e =>
{
if (e.DirInfo == null)
{ {
ProcessStartInfo startInfo = throw new NullReferenceException("RemoteServer: 发布的文件为空!--这个异常应该永远不会发生~");
new()
{
FileName = "cmd.exe", // The command to execute (can be any command line tool)
Arguments =
$"msdeploy.exe -verb:sync -source:contentPath={Context.NotNullSyncConfig.LocalProjectAbsolutePath} -dest:contentPath={Context.NotNullSyncConfig.LocalRootPath} -disablerule:BackupRule",
// The arguments to pass to the command (e.g., list directory contents)
RedirectStandardOutput = true, // Redirect the standard output to a string
UseShellExecute = false, // Do not use the shell to execute the command
CreateNoWindow = true // Do not create a new window for the command
};
using Process process = new() { StartInfo = startInfo };
// Start the process
process.Start();
// Read the output from the process
string output = process.StandardOutput.ReadToEnd();
// Wait for the process to exit
process.WaitForExit();
if (process.ExitCode == 0)
{
Context.LocalSocketSendMsg(CreateMsg("发布成功!")).Wait();
var h = new DiffFileAndPackHelper(Context);
Context.StateHelper = h;
h.DiffProcess();
}
else
{
Context.LocalSocketSendMsg(CreateErrMsg(output)).Wait();
throw new Exception("执行发布错误,错误信息参考上一条消息!");
}
} }
else else
{ {
throw new NotSupportedException("只支持windows!"); var nd = e.DirInfo.Clone();
nd.ResetRootPath(
Context.NotNullSyncConfig.LocalRootPath,
Context.NotNullSyncConfig.RemoteRootPath
);
nd.ExtractInfo(e.CherryPicks, e.Excludes);
var diff = e.DirInfo.Diff(nd);
e.DirInfo = diff;
} }
}
}
protected override void HandleRemoteMsg(SyncMsg msg) { }
protected override void HandleLocalMsg(SyncMsg msg) { }
}
public class DiffFileAndPackHelper(LocalSyncServer context)
: StateHelpBase(context, SyncProcessStep.DiffFileAndPack)
{
public void DiffProcess()
{
//提取本地文件的信息
Context.NotNullSyncConfig.DirFileConfigs.ForEach(e =>
{
e.LocalDirInfo = new Dir(Context.NotNullSyncConfig.LocalRootPath + e.DirPath);
e.LocalDirInfo.ExtractInfo(e.CherryPicks, e.Excludes);
}); });
//将配置信息发送到remoteServer //将对比结果发送到Local
Context Context.Pipe.SendMsg(
.RemoteSocketSendMsg(CreateMsg(JsonSerializer.Serialize(Context.NotNullSyncConfig))) CreateMsg(JsonSerializer.Serialize(Context.NotNullSyncConfig.DirFileConfigs))
.Wait(); );
}
protected override void HandleLocalMsg(SyncMsg msg) { }
protected override void HandleRemoteMsg(SyncMsg msg) {
} }
} }
public class UnPackFilesHelper(RemoteSyncServer context):StateHelpBase(context,SyncProcessStep.UploadAndUnpack)
// /// <summary> {
// /// 0. 发布源验证密码 protected override void HandleMsg(SyncMsg msg)
// /// </summary> {
// /// <param name="context"></param> throw new NotImplementedException();
// public class LocalAuthorityState(LocalSyncServer context) : StateHelpBase(context) }
// { }
// public override void HandleRemoteMsg(SyncMsg? msg)
// {
// throw new NotImplementedException("error usage!");
// }
// public override void HandleLocalMsg(SyncMsg? msg)
// {
// if (msg == null)
// {
// return;
// }
// else
// {
// string Pwd = msg.Body;
// if (Pwd == "Xfs1%$@_fdYU.>>")
// {
// Context.LocalSocketSendMsg(new SyncMsg(SyncMsgType.Success, "源服务密码校验成功!"));
// Context.StateHelper = new WaitingConfigInfoState(Context);
// }
// else
// {
// throw new UnauthorizedAccessException("pwd error!");
// }
// }
// }
// }
// /// <summary>
// /// 1. 获取配置信息,它包含目标的服务器的配置信息
// /// </summary>
// /// <param name="context"></param>
// public class WaitingConfigInfoState(LocalSyncServer context) : StateHelpBase(context)
// {
// public override void HandleRemoteMsg(SyncMsg? msg) { }
// public override void HandleLocalMsg(SyncMsg? msg)
// {
// if (msg == null)
// {
// return;
// }
// else
// {
// string ConfigInfo = msg.Body;
// Context.SyncConfig =
// JsonSerializer.Deserialize<Config>(ConfigInfo)
// ?? throw new NullReferenceException("ConfigInfo is null");
// var task = Context.RemoteSocket.ConnectAsync(
// new Uri(Context.SyncConfig.RemoteUrl),
// CancellationToken.None
// );
// if (task.Wait(10000))
// {
// if (Context.RemoteSocket.State == WebSocketState.Open)
// {
// var state = new RemoteAuthorityState(Context);
// state.SendPwdToRemoteServer();
// Context.StateHelper = state;
// }
// else
// {
// throw new Exception("connect remote server failed!");
// }
// }
// else
// {
// throw new TimeoutException("connect remote server timeout");
// }
// }
// }
// }
// /// <summary>
// /// 2. 目标服务器权限校验
// /// </summary>
// /// <param name="context"></param>
// public class RemoteAuthorityState(LocalSyncServer context) : StateHelpBase(context)
// {
// public override void HandleRemoteMsg(SyncMsg? msg)
// {
// if (msg == null)
// {
// return;
// }
// else
// {
// if (msg.Type == SyncMsgType.Success)
// {
// Context.LocalSocketSendMsg(new SyncMsg(SyncMsgType.Success, "远程服务器校验成功!"));
// var diffState = new DirFilesDiffState(Context);
// diffState.SendSyncConfigToRemote();
// Context.StateHelper = diffState;
// }
// else
// {
// throw new Exception("远程服务器权限校验失败请检查Local Server 的Mac地址是否在 Remote Server 的允许列表内!");
// }
// }
// }
// public override void HandleLocalMsg(SyncMsg? msg) { }
// public void SendPwdToRemoteServer()
// {
// var authorityInfo = new
// {
// Pwd = "xfs@#123hd??1>>|12#4",
// MacAdr = new LocalServer.Controllers.LocalServerController(
// Context.Factory
// ).GetMacAddress()
// };
// Context.RemoteSocketSendMsg(authorityInfo);
// }
// }
// /// <summary>
// /// 3. 文件比较
// /// </summary>
// /// <param name="context"></param>
// public class DirFilesDiffState(LocalSyncServer context) : StateHelpBase(context)
// {
// public override void HandleRemoteMsg(SyncMsg? msg)
// {
// if (msg == null)
// {
// return;
// }
// else
// {
// if (msg.IsSuccess)
// {
// var state = new LocalPackAndUploadState(Context);
// state.PackDiffDir(msg);
// Context.StateHelper = state;
// }
// else
// {
// throw new Exception(msg.Body);
// }
// }
// }
// public override void HandleLocalMsg(SyncMsg? msg) { }
// public void SendSyncConfigToRemote()
// {
// Context.RemoteSocketSendMsg(
// Context.SyncConfig
// ?? throw new NullReferenceException("SyncConfig should't be null here!")
// );
// }
// }
// /// <summary>
// /// 4. 本地打包并上传
// /// </summary>
// /// <param name="context"></param>
// public class LocalPackAndUploadState(LocalSyncServer context) : StateHelpBase(context)
// {
// public override void HandleRemoteMsg(SyncMsg? msg)
// {
// if (msg == null)
// {
// return;
// }
// else { }
// }
// public override void HandleLocalMsg(SyncMsg? msg) { }
// /// <summary>
// /// 打包文件
// /// </summary>
// /// <param name="msg"></param>
// /// <exception cref="Exception"></exception>
// public void PackDiffDir(SyncMsg msg)
// {
// if (msg.IsSuccess)
// {
// var diff = JsonSerializer.Deserialize<Dir>(msg.Body);
// Context.LocalSocketSendMsg(new SyncMsg(SyncMsgType.Success, "文件打包完成!"));
// Context.LocalSocketSendMsg(new SyncMsg(SyncMsgType.Success, "文件上传完成!"));
// }
// else
// {
// throw new Exception(msg.Body);
// }
// }
// private void UploadPackedFiles(string absolutePath)
// {
// //TODO 传递上传进度到前端。
// }
// }
// /// <summary>
// /// 5. 目标服务器解包并发布
// /// </summary>
// /// <param name="context"></param>
// public class RemoteUnPackAndReleaseState(LocalSyncServer context) : StateHelpBase(context)
// {
// public override void HandleRemoteMsg(SyncMsg? msg)
// {
// if (msg == null)
// {
// return;
// }
// else { }
// }
// public override void HandleLocalMsg(SyncMsg? msg) { }
// }

View file

@ -8,5 +8,9 @@
"Microsoft.AspNetCore": "Warning" "Microsoft.AspNetCore": "Warning"
} }
}, },
"AllowedHosts": "*" "AllowedHosts": "*",
} "TempDir":"D:/TempPack2",
"NamePwds":[
["test","testpwd"]
]
}