FileSqlServerSync/Server/LocalServer/StateHelper.cs

670 lines
23 KiB
C#
Raw Normal View History

2024-09-05 01:59:57 +00:00
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Text;
2024-07-31 09:14:07 +00:00
using System.Text.Json;
2024-09-24 09:46:52 +00:00
using System.Text.Json.Serialization;
2024-07-31 09:14:07 +00:00
using Common;
namespace LocalServer;
// enum StateWhenMsg
// {
// Authority = 0,
// ConfigInfo = 1,
// LocalPackAndUpload = 2,
// RemoteUnPackAndRelease = 3,
// }
2024-09-05 01:59:57 +00:00
public abstract class StateHelpBase(
LocalSyncServer context,
SyncProcessStep step = SyncProcessStep.Connect
)
2024-07-31 09:14:07 +00:00
{
protected readonly LocalSyncServer Context = context;
public readonly SyncProcessStep Step = step;
2024-07-31 09:14:07 +00:00
2024-09-05 01:59:57 +00:00
public SyncMsg CreateErrMsg(string Body)
{
return new SyncMsg
{
Body = Body,
Step = Step,
Type = SyncMsgType.Error
};
2024-09-05 01:59:57 +00:00
}
public SyncMsg CreateMsg(string body, SyncMsgType type = SyncMsgType.General)
{
return new SyncMsg
{
Body = body,
Step = Step,
Type = type
};
2024-09-05 01:59:57 +00:00
}
public bool ReceiveLocalMsg(byte[] msg)
2024-09-05 01:59:57 +00:00
{
var syncMsg =
JsonSerializer.Deserialize<SyncMsg>(msg)
?? throw new NullReferenceException("msg is null");
if (syncMsg.Step != Step)
{
throw new Exception("Sync step error!");
}
HandleLocalMsg(syncMsg);
return true;
2024-09-05 01:59:57 +00:00
}
public bool ReceiveRemoteMsg(byte[] bytes)
2024-09-05 01:59:57 +00:00
{
var msg = Encoding.UTF8.GetString(bytes);
2024-09-05 01:59:57 +00:00
var syncMsg =
JsonSerializer.Deserialize<SyncMsg>(msg)
?? throw new NullReferenceException("msg is null");
if (syncMsg.Step != Step)
{
throw new Exception("Sync step error!");
}
HandleRemoteMsg(syncMsg);
return true;
2024-09-05 01:59:57 +00:00
}
protected abstract void HandleRemoteMsg(SyncMsg msg);
protected abstract void HandleLocalMsg(SyncMsg msg);
2024-07-31 09:14:07 +00:00
}
/// <summary>
2024-09-05 01:59:57 +00:00
/// 0. 链接验证
2024-07-31 09:14:07 +00:00
/// </summary>
/// <param name="context"></param>
2024-09-05 01:59:57 +00:00
public class ConnectAuthorityHelper(LocalSyncServer context)
: StateHelpBase(context, SyncProcessStep.Connect)
2024-07-31 09:14:07 +00:00
{
2024-09-05 01:59:57 +00:00
// 如果密码错误,那么就直接关闭连接,不会进入这个方法
protected override void HandleRemoteMsg(SyncMsg msg)
2024-07-31 09:14:07 +00:00
{
2024-09-05 01:59:57 +00:00
//将remote的消息传递到前端界面
Context.LocalPipe.SendMsg(msg);
2024-09-05 01:59:57 +00:00
//下一步
var deployHelper = new DeployHelper(Context);
Context.SetStateHelper(deployHelper);
2024-09-05 01:59:57 +00:00
deployHelper.DeployProcess();
2024-07-31 09:14:07 +00:00
}
2024-09-05 01:59:57 +00:00
protected override void HandleLocalMsg(SyncMsg msg)
2024-07-31 09:14:07 +00:00
{
2024-09-05 01:59:57 +00:00
//收到配置文件
var config = JsonSerializer.Deserialize<Config>(msg.Body);
Context.SyncConfig = config;
Task.Run(async () =>
2024-07-31 09:14:07 +00:00
{
try
2024-07-31 09:14:07 +00:00
{
var rs = Context.RemotePipe.Work(
(byte[] b) =>
{
var x = Context.GetStateHelper().Step;
return Context.GetStateHelper().ReceiveRemoteMsg(b);
},
Context.NotNullSyncConfig.RemoteUrl + "/websoc?Name=" + Context.Name
);
await foreach (var r in rs)
{
if (r == 0)
{
await Context.RemotePipe.SendMsg(
CreateMsg(Context.NotNullSyncConfig.RemotePwd)
);
}
}
2024-07-31 09:14:07 +00:00
}
catch (Exception e)
{
await Context.LocalPipe.Close(e.Message);
}
2024-09-05 01:59:57 +00:00
});
2024-07-31 09:14:07 +00:00
}
}
/// <summary>
2024-09-05 01:59:57 +00:00
/// 1. 执行发布步骤
2024-07-31 09:14:07 +00:00
/// </summary>
/// <param name="context"></param>
2024-09-05 01:59:57 +00:00
public class DeployHelper(LocalSyncServer context)
: StateHelpBase(context, SyncProcessStep.DeployProject)
2024-07-31 09:14:07 +00:00
{
2024-09-05 01:59:57 +00:00
public void DeployProcess()
2024-07-31 09:14:07 +00:00
{
2024-09-05 01:59:57 +00:00
if (Context.NotNullSyncConfig.IsDeployProject == false)
2024-07-31 09:14:07 +00:00
{
Context.LocalPipe.SendMsg(CreateMsg("配置为不发布跳过此步骤")).Wait();
2024-09-05 01:59:57 +00:00
var h = new DiffFileAndPackHelper(Context);
Context.SetStateHelper(h);
2024-09-05 01:59:57 +00:00
h.DiffProcess();
2024-07-31 09:14:07 +00:00
}
else
{
2024-09-05 01:59:57 +00:00
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
2024-07-31 09:14:07 +00:00
{
//构建
//var OutputPath = LocalSyncServer.GetProjectOutPath(
// Context.NotNullSyncConfig.LocalProjectAbsolutePath
//);
//var AbOutPath = Path.Combine(
// Context.NotNullSyncConfig.LocalProjectAbsolutePath,
// OutputPath
//);
ProcessStartInfo startbuildInfo =
2024-09-05 01:59:57 +00:00
new()
{
FileName = LocalSyncServer.MSBuildAbPath, // The command to execute (can be any command line tool)
2024-09-05 01:59:57 +00:00
Arguments =
$" {Context.NotNullSyncConfig.LocalProjectAbsolutePath} /t:ResolveReferences"
+ $" /t:Compile /p:Configuration=Release /t:_CopyWebApplication /p:OutputPath={LocalSyncServer.TempRootFile}/bin"
+ $" /p:WebProjectOutputDir={LocalSyncServer.TempRootFile}",
2024-09-05 01:59:57 +00:00
// The arguments to pass to the command (e.g., list directory contents)
RedirectStandardOutput = true, // Redirect the standard output to a string
RedirectStandardError = true,
StandardOutputEncoding = System.Text.Encoding.UTF8,
2024-09-05 01:59:57 +00:00
UseShellExecute = false, // Do not use the shell to execute the command
CreateNoWindow = true // Do not create a new window for the command
};
using Process bprocess = new() { StartInfo = startbuildInfo };
2024-09-05 01:59:57 +00:00
// Start the process
bprocess.Start();
2024-09-05 01:59:57 +00:00
// Read the output from the process
string boutput = bprocess.StandardOutput.ReadToEnd();
2024-09-05 01:59:57 +00:00
// Wait for the process to exit
bprocess.WaitForExit();
2024-09-05 01:59:57 +00:00
if (bprocess.ExitCode == 0)
2024-07-31 09:14:07 +00:00
{
Context.LocalPipe.SendMsg(CreateMsg("本地编译成功!")).Wait();
2024-07-31 09:14:07 +00:00
}
else
{
var aTexts = boutput.Split('\n');
if (aTexts.Length > 10)
{
boutput = string.Join('\n', aTexts.Skip(aTexts.Length - 10));
}
Context.LocalPipe.SendMsg(CreateErrMsg(boutput)).Wait();
throw new Exception("执行编译错误,错误信息参考上一条消息!");
2024-07-31 09:14:07 +00:00
}
//发布
//ProcessStartInfo startInfo =
// new()
// {
// FileName = LocalSyncServer.MsdeployAbPath, // The command to execute (can be any command line tool)
// Arguments =
// $" -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.LocalPipe.SendMsg(CreateMsg("本地发布成功!")).Wait();
// var h = new DiffFileAndPackHelper(Context);
// Context.SetStateHelper(h);
// h.DiffProcess();
//}
//else
//{
// Context.LocalPipe.SendMsg(CreateErrMsg(output)).Wait();
// throw new Exception("执行发布错误,错误信息参考上一条消息!");
//}
2024-07-31 09:14:07 +00:00
}
else
{
2024-09-05 01:59:57 +00:00
throw new NotSupportedException("只支持windows!");
2024-07-31 09:14:07 +00:00
}
}
}
2024-09-05 01:59:57 +00:00
protected override void HandleRemoteMsg(SyncMsg msg) { }
protected override void HandleLocalMsg(SyncMsg msg) { }
2024-07-31 09:14:07 +00:00
}
2024-09-05 01:59:57 +00:00
public class DiffFileAndPackHelper(LocalSyncServer context)
: StateHelpBase(context, SyncProcessStep.DiffFileAndPack)
2024-07-31 09:14:07 +00:00
{
2024-09-05 01:59:57 +00:00
public void DiffProcess()
2024-07-31 09:14:07 +00:00
{
2024-09-05 01:59:57 +00:00
//提取本地文件的信息
Context.NotNullSyncConfig.DirFileConfigs.ForEach(e =>
2024-07-31 09:14:07 +00:00
{
e.LocalDirInfo = new Dir
{
Path = Context.NotNullSyncConfig.LocalRootPath + e.DirPath,
Children = []
};
e.LocalDirInfo.ExtractInfo(e.CherryPicks, e.Excludes);
2024-09-05 01:59:57 +00:00
});
2024-09-05 01:59:57 +00:00
//将配置信息发送到remoteServer
2024-09-24 09:46:52 +00:00
var options = new JsonSerializerOptions { WriteIndented = true };
2024-09-05 01:59:57 +00:00
Context
2024-09-24 09:46:52 +00:00
.RemotePipe.SendMsg(
CreateMsg(JsonSerializer.Serialize(Context.NotNullSyncConfig, options))
)
2024-09-05 01:59:57 +00:00
.Wait();
2024-07-31 09:14:07 +00:00
}
2024-09-05 01:59:57 +00:00
protected override void HandleLocalMsg(SyncMsg msg) { }
protected override void HandleRemoteMsg(SyncMsg msg)
{
var diffConfig =
JsonSerializer.Deserialize<List<DirFileConfig>>(msg.Body)
?? throw new Exception("LocalServer: DirFile为空");
for (var i = 0; i < diffConfig.Count; ++i)
{
Context.NotNullSyncConfig.DirFileConfigs[i].DiffDirInfo = diffConfig[i].DiffDirInfo;
}
var PackOp = new FileDirOpForPack(
Context.NotNullSyncConfig.LocalRootPath,
LocalSyncServer.TempRootFile + "/" + Context.NotNullSyncConfig.Id.ToString()
);
Directory.CreateDirectory(
LocalSyncServer.TempRootFile + "/" + Context.NotNullSyncConfig.Id.ToString()
);
2024-09-22 05:27:52 +00:00
Context.NotNullSyncConfig.DirFileConfigs.ForEach(e =>
{
if (e.DiffDirInfo != null)
2024-09-22 05:27:52 +00:00
{
e.DiffDirInfo.ResetRootPath(
2024-09-22 05:27:52 +00:00
Context.NotNullSyncConfig.RemoteRootPath,
Context.NotNullSyncConfig.LocalRootPath
);
e.DiffDirInfo.WriteByThisInfo(PackOp);
2024-09-22 05:27:52 +00:00
}
});
var n = new DeployMSSqlHelper(Context);
Context.SetStateHelper(n);
2024-09-22 05:27:52 +00:00
n.PackSqlServerProcess();
}
}
2024-09-22 05:27:52 +00:00
public class DeployMSSqlHelper(LocalSyncServer context)
: StateHelpBase(context, SyncProcessStep.PackSqlServer)
{
private void PackAndSwitchNext()
{
FileDirOpForPack.FinallyCompress(
LocalSyncServer.TempRootFile + "/" + Context.NotNullSyncConfig.Id.ToString(),
Context.NotNullSyncConfig.Id.ToString()
);
var h = new UploadPackedHelper(Context);
Context.SetStateHelper(h);
2024-09-22 05:27:52 +00:00
h.UpLoadPackedFile();
}
public void PackSqlServerProcess()
{
if (Context.NotNullSyncConfig.IsDeployDb == false)
{
Context.LocalPipe.SendMsg(CreateMsg("配置为不发布数据库跳过此步骤")).Wait();
PackAndSwitchNext();
}
else
{
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
var arguments =
2024-09-24 09:46:52 +00:00
$" /Action:Extract /TargetFile:{LocalSyncServer.TempRootFile}/{Context.NotNullSyncConfig.Id.ToString()}/{Context.NotNullSyncConfig.Id.ToString()}.dacpac"
// 不要log file 了
//+ $" /DiagnosticsFile:{LocalSyncServer.TempRootFile}/{Context.NotNullSyncConfig.Id.ToString()}/{Context.NotNullSyncConfig.Id.ToString()}.log"
+ $" /p:ExtractAllTableData=false /p:VerifyExtraction=true /SourceServerName:{Context.NotNullSyncConfig.SrcDb.ServerName}"
+ $" /SourceDatabaseName:{Context.NotNullSyncConfig.SrcDb.DatebaseName} /SourceUser:{Context.NotNullSyncConfig.SrcDb.User}"
+ $" /SourcePassword:{Context.NotNullSyncConfig.SrcDb.Password} /SourceTrustServerCertificate:{Context.NotNullSyncConfig.SrcDb.TrustServerCertificate}"
+ $" /p:ExtractReferencedServerScopedElements=False /p:IgnoreUserLoginMappings=True /p:IgnorePermissions=True";
2024-09-22 05:27:52 +00:00
if (Context.NotNullSyncConfig.SrcDb.SyncTablesData != null)
{
foreach (var t in Context.NotNullSyncConfig.SrcDb.SyncTablesData)
{
arguments += $" /p:TableData={t}";
}
}
ProcessStartInfo startInfo =
new()
{
FileName = LocalSyncServer.SqlPackageAbPath, // The command to execute (can be any command line tool)
2024-09-22 05:27:52 +00:00
Arguments = arguments,
StandardOutputEncoding = System.Text.Encoding.UTF8,
2024-09-22 05:27:52 +00:00
// 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.LocalPipe.SendMsg(CreateMsg("数据库打包成功!")).Wait();
PackAndSwitchNext();
}
else
{
Context.LocalPipe.SendMsg(CreateErrMsg(output)).Wait();
throw new Exception("执行发布错误,错误信息参考上一条消息!");
}
}
else
{
throw new NotSupportedException("只支持windows!");
}
}
}
protected override void HandleLocalMsg(SyncMsg msg) { }
protected override void HandleRemoteMsg(SyncMsg msg)
{
throw new NotImplementedException();
}
}
public class UploadPackedHelper(LocalSyncServer context)
: StateHelpBase(context, SyncProcessStep.UploadAndUnpack)
{
public void UpLoadPackedFile()
{
Context
.LocalPipe.UploadFile(
Context.NotNullSyncConfig.RemoteUrl,
2024-09-24 09:46:52 +00:00
$"{LocalSyncServer.TempRootFile}/{Context.NotNullSyncConfig.Id}.zip",
2024-09-22 05:27:52 +00:00
(double current) =>
{
Context
.LocalPipe.SendMsg(CreateMsg(current.ToString(), SyncMsgType.Process))
.Wait();
return true;
}
)
.Wait();
Context.LocalPipe.SendMsg(CreateMsg("上传完成!")).Wait();
var x = Context.GetStateHelper().Step;
2024-09-22 05:27:52 +00:00
}
protected override void HandleLocalMsg(SyncMsg msg)
{
throw new NotImplementedException();
}
protected override void HandleRemoteMsg(SyncMsg msg)
{
Context.LocalPipe.SendMsg(msg).Wait();
var h = new FinallyPublishHelper(Context);
Context.SetStateHelper(h);
}
2024-07-31 09:14:07 +00:00
}
2024-09-22 05:27:52 +00:00
public class FinallyPublishHelper(LocalSyncServer context)
: StateHelpBase(context, SyncProcessStep.Publish)
{
protected override void HandleLocalMsg(SyncMsg msg)
{
throw new NotImplementedException();
}
/// <summary>
/// 由最初始的客户端断开连接,表示发布完成。
/// </summary>
/// <param name="msg"></param>
protected override void HandleRemoteMsg(SyncMsg msg)
{
Context.LocalPipe.SendMsg(msg).Wait();
}
}
2024-09-05 01:59:57 +00:00
// /// <summary>
// /// 0. 发布源验证密码
// /// </summary>
// /// <param name="context"></param>
// public class LocalAuthorityState(LocalSyncServer context) : StateHelpBase(context)
// {
// public override void HandleRemoteMsg(SyncMsg? msg)
// {
// throw new NotImplementedException("error usage!");
// }
2024-07-31 09:14:07 +00:00
2024-09-05 01:59:57 +00:00
// 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!");
// }
// }
// }
// }
2024-07-31 09:14:07 +00:00
2024-09-05 01:59:57 +00:00
// /// <summary>
// /// 1. 获取配置信息,它包含目标的服务器的配置信息
// /// </summary>
// /// <param name="context"></param>
// public class WaitingConfigInfoState(LocalSyncServer context) : StateHelpBase(context)
// {
// public override void HandleRemoteMsg(SyncMsg? msg) { }
2024-07-31 09:14:07 +00:00
2024-09-05 01:59:57 +00:00
// 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");
// }
// }
// }
// }
2024-07-31 09:14:07 +00:00
2024-09-05 01:59:57 +00:00
// /// <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 的允许列表内!");
// }
// }
// }
2024-07-31 09:14:07 +00:00
2024-09-05 01:59:57 +00:00
// 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) { }
// }