Files
serein-flow/Workbench/Services/WorkbenchEventService.cs

331 lines
10 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using Microsoft.Win32;
using Newtonsoft.Json.Linq;
using Serein.Library;
using Serein.Library.Api;
using Serein.Workbench.Api;
using Serein.Workbench.ViewModels;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Input;
namespace Serein.Workbench.Services
{
#region
public delegate void PreviewlMethodInfoHandler(PreviewlMethodInfoEventArgs eventArgs);
#endregion
#region
public class PreviewlMethodInfoEventArgs(MethodDetailsInfo mdInfo) : EventArgs
{
/// <summary>
/// 方法信息
/// </summary>
public MethodDetailsInfo MethodDetailsInfo { get; } = mdInfo;
}
#endregion
/// <summary>
/// 工作台事件管理
/// </summary>
internal interface IWorkbenchEventService
{
/// <summary>
/// 预览了某个方法信息(待创建)
/// </summary>
event PreviewlMethodInfoHandler OnPreviewlMethodInfo;
/// <summary>
/// 预览依赖方法信息
/// </summary>
void PreviewLibraryMethodInfo(MethodDetailsInfo mdInfo);
}
/// <summary>
/// 工作台事件的实现类
/// </summary>
internal class WorkbenchEventService : IWorkbenchEventService
{
private readonly IFlowEnvironment flowEnvironment;
private readonly IFlowEEForwardingService flowEEForwardingService;
private readonly IKeyEventService keyEventService;
private readonly FlowNodeService flowNodeService;
/// <summary>
/// 管理工作台的事件
/// </summary>
/// <param name="flowEnvironment"></param>
/// <param name="flowEEForwardingService"></param>
/// <param name="keyEventService"></param>
/// <param name="flowNodeService"></param>
public WorkbenchEventService(IFlowEnvironment flowEnvironment,
IFlowEEForwardingService flowEEForwardingService,
IKeyEventService keyEventService,
FlowNodeService flowNodeService)
{
this.flowEnvironment = flowEnvironment;
this.flowEEForwardingService = flowEEForwardingService;
this.keyEventService = keyEventService;
this.flowNodeService = flowNodeService;
InitEvents();
}
private void InitEvents()
{
flowEEForwardingService.OnProjectLoaded += FlowEEForwardingService_OnProjectLoaded;
flowEEForwardingService.OnProjectSaving += SaveProjectToLocalFile;
flowEEForwardingService.OnEnvOut += FlowEEForwardingService_OnEnvOut;
keyEventService.OnKeyDown += KeyEventService_OnKeyDown; ;
}
private void FlowEEForwardingService_OnProjectLoaded(ProjectLoadedEventArgs eventArgs)
{
var edit = App.GetService<Locator>().FlowEditViewModel;
App.UIContextOperation.Invoke(async () => {
foreach (var item in flowNodeService.FlowCanvass)
{
await Task.Delay(50);
flowNodeService.CurrentSelectCanvas = item;
var tab = edit.CanvasTabs.First(tab => tab.Content == item);
edit.SelectedTab = tab;
}
});
}
private void KeyEventService_OnKeyDown(System.Windows.Input.Key key)
{
}
private void FlowEEForwardingService_OnEnvOut(InfoType type, string value)
{
LogWindow.Instance.AppendText($"{DateTime.Now} [{type}] : {value}{Environment.NewLine}");
}
/// <summary>
/// 预览了某个方法信息(待创建)
/// </summary>
public event PreviewlMethodInfoHandler? OnPreviewlMethodInfo;
/// <summary>
/// 预览依赖方法信息
/// </summary>
public void PreviewLibraryMethodInfo(MethodDetailsInfo mdInfo)
{
OnPreviewlMethodInfo?.Invoke(new PreviewlMethodInfoEventArgs(mdInfo));
}
/// <summary>
/// 需要放置节点控件
/// </summary>
public void PlateNodeControl()
{
}
/// <summary>
/// 保存项目数据到本地文件
/// </summary>
/// <param name="e"></param>
private void SaveProjectToLocalFile(ProjectSavingEventArgs e)
{
var project = e.ProjectData;
#region
// 创建一个新的保存文件对话框
SaveFileDialog saveFileDialog = new()
{
Filter = "DynamicNodeFlow Files (*.dnf)|*.dnf",
DefaultExt = "dnf",
FileName = "project.dnf"
// FileName = System.IO.Path.GetFileName(App.FileDataPath)
};
// 显示保存文件对话框
bool? result = saveFileDialog.ShowDialog();
// 如果用户选择了文件并点击了保存按钮
if (result == false)
{
SereinEnv.WriteLine(InfoType.ERROR, "取消保存文件");
return;
}
var savePath = saveFileDialog.FileName;
string? librarySavePath = System.IO.Path.GetDirectoryName(savePath);
if (string.IsNullOrEmpty(librarySavePath))
{
SereinEnv.WriteLine(InfoType.ERROR, "保存项目DLL时返回了意外的文件保存路径");
return;
}
#endregion
#region Dll输出到指定路径
Uri saveProjectFileUri = new Uri(savePath);
SereinEnv.WriteLine(InfoType.INFO, "项目文件保存路径:" + savePath);
for (int index = 0; index < project.Librarys.Length; index++)
{
NodeLibraryInfo? library = project.Librarys[index];
string sourceFilePath = new Uri(library.FilePath).LocalPath; // 源文件夹
string targetDir = System.IO.Path.Combine(librarySavePath, library.AssemblyName); // 目标文件夹
if (!Path.Exists(targetDir))
{
Directory.CreateDirectory(targetDir);
}
string targetFilePath = System.IO.Path.Combine(targetDir, library.FileName); // 目标文件夹
try
{
if (File.Exists(sourceFilePath))
{
if (!File.Exists(targetFilePath))
{
SereinEnv.WriteLine(InfoType.INFO, $"源文件路径 : {sourceFilePath}");
SereinEnv.WriteLine(InfoType.INFO, $"目标路径 : {targetFilePath}");
File.Copy(sourceFilePath, targetFilePath, true);
}
else
{
SereinEnv.WriteLine(InfoType.WARN, $"目标路径已有类库文件: {targetFilePath}");
}
}
else
{
SereinEnv.WriteLine(InfoType.WARN, $"源文件不存在 : {targetFilePath}");
}
}
catch (IOException ex)
{
SereinEnv.WriteLine(InfoType.ERROR, ex.Message);
}
var dirName = System.IO.Path.GetDirectoryName(targetFilePath);
if (!string.IsNullOrEmpty(dirName))
{
var tmpUri2 = new Uri(targetFilePath);
var relativePath = saveProjectFileUri.MakeRelativeUri(tmpUri2).ToString(); // 转为类库的相对文件路径
//string relativePath = System.IO.Path.GetRelativePath(savePath, targetPath);
project.Librarys[index].FilePath = relativePath;
}
}
#endregion
#region
JObject projectJsonData = JObject.FromObject(project);
File.WriteAllText(savePath, projectJsonData.ToString());
#endregion
}
}
}
#region net运行时
/*
1. 扫描目录并计算哈希
string[] directories = new[] { "path1", "path2" };
var fileHashMap = new Dictionary<string, List<string>>(); // hash -> List<full paths>
foreach (var dir in directories)
{
foreach (var file in Directory.EnumerateFiles(dir, "*.*", SearchOption.AllDirectories))
{
using var stream = File.OpenRead(file);
using var sha = SHA256.Create();
var hash = Convert.ToHexString(sha.ComputeHash(stream));
if (!fileHashMap.ContainsKey(hash))
fileHashMap[hash] = new List<string>();
fileHashMap[hash].Add(file);
}
}
2. 将重复文件压缩并保存
string archiveDir = "compressed_output";
Directory.CreateDirectory(archiveDir);
var manifest = new List<FileRecord>();
foreach (var kvp in fileHashMap.Where(kvp => kvp.Value.Count > 1))
{
var hash = kvp.Key;
var originalFile = kvp.Value[0];
var archivePath = Path.Combine(archiveDir, $"{hash}.gz");
using (var input = File.OpenRead(originalFile))
using (var output = File.Create(archivePath))
using (var gzip = new GZipStream(output, CompressionLevel.Optimal))
{
input.CopyTo(gzip);
}
manifest.Add(new FileRecord
{
Hash = hash,
ArchiveFile = $"{hash}.gz",
OriginalPaths = kvp.Value
});
}
3. 生成清单文件JSON
public class FileRecord
{
public string Hash { get; set; }
public string ArchiveFile { get; set; }
public List<string> OriginalPaths { get; set; }
}
File.WriteAllText("manifest.json", JsonSerializer.Serialize(manifest, new JsonSerializerOptions { WriteIndented = true }));
4. 根据清单还原原始文件结构
var manifestJson = File.ReadAllText("manifest.json");
var manifest = JsonSerializer.Deserialize<List<FileRecord>>(manifestJson);
foreach (var record in manifest)
{
var archivePath = Path.Combine("compressed_output", record.ArchiveFile);
foreach (var path in record.OriginalPaths)
{
Directory.CreateDirectory(Path.GetDirectoryName(path)!);
using var input = File.OpenRead(archivePath);
using var gzip = new GZipStream(input, CompressionMode.Decompress);
using var output = File.Create(path);
gzip.CopyTo(output);
}
}
*/
#endregion