You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
304 lines
13 KiB
304 lines
13 KiB
using System.Data; |
|
using System.IO; |
|
using log4net; |
|
using Newtonsoft.Json; |
|
using Newtonsoft.Json.Linq; |
|
using BrilliantSightClient.Model.Entity.ApiEntity; |
|
using BrilliantSightClient.Model.Helper; |
|
using System.Configuration; |
|
using System.Diagnostics; |
|
using System.Text; |
|
using BrilliantSightClient.ViewModel.Configuration; |
|
using SparkDotNetCore.DiamondScanner.Entity; |
|
using SparkDotNetCore.DiamondScanner.Entity.Child; |
|
|
|
namespace BrilliantSightClient.Model.Services |
|
{ |
|
public class AlgorithmServer |
|
{ |
|
private readonly AlgorithmConfigVM _algorithmConfigVM; |
|
|
|
public AlgorithmServer() |
|
{ |
|
_algorithmConfigVM = new AlgorithmConfigVM(); |
|
} |
|
private static readonly ILog Logger = LogManager.GetLogger(typeof(AlgorithmServer)); |
|
|
|
// 添加公共方法 |
|
public DiaResult CallParseJsonAndReturnActions(string shape, string shape_mode, string image_files) |
|
{ |
|
try |
|
{ |
|
//半圆 |
|
string circleSql = $"SELECT VALUE FROM CUTTER_CONFIG WHERE KEY = 'half_circle'"; |
|
DataTable circleTable = DataBaseHelper.ExecuteQuery(circleSql); |
|
object halfCircleValue = circleTable.Rows[0][0]; |
|
bool.TryParse(halfCircleValue.ToString(), out bool boolResult); |
|
bool half_circle = boolResult; |
|
|
|
//算法配置参数,初始化算法配置数据并获取 AlgorithmConfigJson |
|
|
|
_algorithmConfigVM.InitAlgorithmData(null); |
|
string algo_config = _algorithmConfigVM.AlgorithmConfigJson; |
|
|
|
|
|
//图片根目录 |
|
string? image_file_base_path = ConfigurationManager.AppSettings["ImageFileBasePath"]; |
|
if (string.IsNullOrEmpty(image_file_base_path)) |
|
{ |
|
throw new InvalidOperationException("ImageFileBasePath is not configured in AppSettings."); |
|
} |
|
|
|
// 获取 log4net 日志文件所在的目录 |
|
string? log4NetLogDirectory = |
|
Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location); |
|
// 构建C++ DLL 日志文件路径 |
|
string algorithm_log_path = Path.Combine(log4NetLogDirectory, "logs"); |
|
|
|
// 将所有变量拼接成一个 JSON 对象 |
|
JObject jsonData = new JObject( |
|
new JProperty("shape", shape), |
|
new JProperty("shape_mode", shape_mode), |
|
new JProperty("image_file_base_path", image_file_base_path), |
|
new JProperty("image_files", JToken.Parse(image_files)), |
|
new JProperty("half_circle", half_circle), |
|
new JProperty("algorithm_log_path", algorithm_log_path), |
|
new JProperty("algo_config", JObject.Parse(algo_config)) |
|
); |
|
|
|
string jsonDataString = jsonData.ToString().Replace("\"", "\\\""); |
|
//string jsonDataString = jsonData.ToString(); |
|
// // 调用 C++ DLL 函数解析 JSON |
|
// IntPtr resultPtr = DetectDiamond(jsonDataString); |
|
// string resultJson = Marshal.PtrToStringAnsi(resultPtr); |
|
// // 释放 DLL 分配的内存 |
|
// FreeString(resultPtr); |
|
// // 检查返回的 JSON 字符串是否为空或无效 |
|
// if (string.IsNullOrEmpty(resultJson)) |
|
// { |
|
// Logger.Error("Algorithm failed or no result returned."); |
|
// // 返回一个默认的 AlgorithmResultEntity 对象表示解析失败 |
|
// return new AlgorithmResultEntity |
|
// { |
|
// facets = new List<Facet>(), |
|
// measurements = new Measurements() |
|
// }; |
|
// } |
|
|
|
// 启动隔离的控制台应用程序 |
|
var startInfo = new ProcessStartInfo |
|
{ |
|
FileName = "AlgorithmDllIsolationConsoleApp.exe", // 控制台应用程序路径 |
|
Arguments = $"\"{jsonDataString}\"", // 将 JSON 数据作为参数传递给控制台应用程序 |
|
RedirectStandardOutput = true, // 获取控制台应用程序的输出 |
|
RedirectStandardError = true, |
|
UseShellExecute = false, |
|
CreateNoWindow = true |
|
}; |
|
|
|
using (var process = Process.Start(startInfo)) |
|
{ |
|
// 使用 StringBuilder 来捕获标准输出和标准错误 |
|
var outputBuilder = new StringBuilder(); |
|
var errorBuilder = new StringBuilder(); |
|
|
|
// 订阅标准输出事件 |
|
process.OutputDataReceived += (sender, e) => |
|
{ |
|
if (e.Data == null) |
|
{ |
|
// 当 e.Data 为 null 时,表示读取完成 |
|
outputBuilder.AppendLine(e.Data); |
|
Console.WriteLine($"Output: {e.Data}"); |
|
return; |
|
} |
|
// 将输出数据追加到 outputBuilder |
|
outputBuilder.AppendLine(e.Data); |
|
// 打印输出数据到控制台 |
|
Console.WriteLine($"Output: {e.Data}"); |
|
}; |
|
|
|
// 订阅标准错误事件 |
|
process.ErrorDataReceived += (sender, e) => |
|
{ |
|
if (e.Data == null) |
|
{ |
|
// 当 e.Data 为 null 时,表示读取完成 |
|
errorBuilder.AppendLine(e.Data); |
|
Logger.Error($"Error Output: {e.Data}"); |
|
return; |
|
} |
|
// 将错误数据追加到 errorBuilder |
|
errorBuilder.AppendLine(e.Data); |
|
// 记录错误数据到日志 |
|
Logger.Error($"Error Output: {e.Data}"); |
|
}; |
|
|
|
// 开始异步读取 |
|
process.BeginOutputReadLine(); |
|
process.BeginErrorReadLine(); |
|
|
|
// 等待控制台应用程序结束 |
|
process.WaitForExit(); |
|
|
|
// 等待异步读取完成 |
|
//Task.WaitAll(outputTcs.Task, errorTcs.Task); |
|
|
|
// 获取结果 |
|
string resultJson = outputBuilder.ToString(); |
|
string errorOutput = errorBuilder.ToString(); |
|
|
|
|
|
// 如果控制台应用程序有错误输出 |
|
if (!string.IsNullOrEmpty(errorOutput)) |
|
{ |
|
Logger.Error($"Console App Error: {errorOutput}"); |
|
} |
|
|
|
// 如果没有结果或失败 |
|
if (string.IsNullOrEmpty(resultJson)) |
|
{ |
|
Logger.Error("Algorithm failed or no result returned."); |
|
return new DiaResult() |
|
{ |
|
Facets = new List<Facet>(), |
|
Measurements = new Measurements() |
|
}; |
|
} |
|
|
|
// 反序列化 JSON 字符串为 AlgorithmResultEntity 对象 |
|
var result = JsonConvert.DeserializeObject<AlgorithmResultEntity>(resultJson); |
|
|
|
// 检查反序列化结果是否为 null |
|
if (result == null) |
|
{ |
|
// 返回一个默认的 AlgorithmResultEntity 对象表示解析失败 |
|
return new AlgorithmResultEntity |
|
{ |
|
Facets = new List<Facet>(), |
|
Measurements = new Measurements() |
|
}; |
|
} |
|
|
|
// 记录算法失败的状态 |
|
Logger.Info($"Algorithm failed with status: {result.Status}"); |
|
// 记录算法失败的错误信息 |
|
Logger.Info($"Algorithm failed with errorMsg: {result.ErrorMsg}"); |
|
// 处理 C++ DLL 日志文件 |
|
// 算法调用失败时,保存图片到历史记录文件夹 |
|
// if (result.status == StatusCodes.AlgorithmFailed) |
|
// { |
|
// HandleAlgorithmFailure(image_files); |
|
// } |
|
return result; |
|
} |
|
} |
|
catch (Exception ex) |
|
{ |
|
// 记录日志或处理异常 |
|
Logger.Error($"Error in CallParseJsonAndReturnActions: {ex.Message}"); |
|
Logger.Error($"Stack Trace: {ex.StackTrace}"); |
|
// 如果有 InnerException,打印出来 |
|
if (ex.InnerException != null) |
|
{ |
|
Logger.Error($"Inner Exception: {ex.InnerException.Message}"); |
|
Logger.Error($"Inner Stack Trace: {ex.InnerException.StackTrace}"); |
|
} |
|
|
|
// 返回一个默认的 AlgorithmResultEntity 对象表示解析失败 |
|
return new AlgorithmResultEntity |
|
{ |
|
Facets = new List<Facet>(), |
|
Measurements = new Measurements() |
|
}; |
|
} |
|
} |
|
|
|
/// <summary> |
|
/// 处理算法调用失败时的逻辑,包括保存图片到历史记录文件夹 |
|
/// </summary> |
|
/// <param name="image_files">图片文件路径的 JSON 字符串</param> |
|
private void HandleAlgorithmFailure(string image_files) |
|
{ |
|
|
|
// 从配置文件中读取 imageHistoryPath |
|
// 定义历史记录文件夹路径 |
|
string? imageHistoryPath = ConfigurationManager.AppSettings["ImageHistoryPath"]; |
|
if (string.IsNullOrEmpty(imageHistoryPath)) |
|
{ |
|
Logger.Error("ImageHistoryPath is not configured in AppSettings."); |
|
return; |
|
} |
|
|
|
// 生成时间戳,格式为 yyyyMMddHHmmss |
|
string timestamp = DateTime.Now.ToString("yyyy-MM-dd-HH-mm-ss"); |
|
// 组合新的文件夹路径 |
|
string newFolderPath = Path.Combine(imageHistoryPath, $"image-{timestamp}"); |
|
|
|
// 检查 D 盘内存空间 |
|
DriveInfo dDrive = new DriveInfo("D"); |
|
long requiredSpace = 10L * 1024 * 1024 * 1024; // 10GB |
|
if (dDrive.TotalFreeSpace < requiredSpace) |
|
{ |
|
// 如果 D 盘空间不足 10GB,删除最早创建的10个文件夹 |
|
DirectoryInfo historyDir = new DirectoryInfo(imageHistoryPath); // 获取历史记录文件夹的信息 |
|
DirectoryInfo[] subDirs = historyDir.GetDirectories(); // 获取历史记录文件夹中的所有子文件夹 |
|
if (subDirs.Length > 0) |
|
{ |
|
// 按创建时间排序子文件夹 |
|
var orderedSubDirs = subDirs.OrderBy(d => d.CreationTime).ToList(); |
|
int foldersToDelete = Math.Min(10, orderedSubDirs.Count); |
|
|
|
// 删除最早的 10 个文件夹,如果不够 10 个则全删掉 |
|
for (int i = 0; i < foldersToDelete; i++) |
|
{ |
|
orderedSubDirs[i].Delete(true); |
|
} |
|
} |
|
} |
|
|
|
// 创建新文件夹 |
|
Directory.CreateDirectory(newFolderPath); |
|
|
|
// 保存图片到新文件夹 |
|
try |
|
{ |
|
// 解析 image_files JSON 数组 |
|
JArray imageFilesArray = JArray.Parse(image_files); |
|
string[] imageFiles = imageFilesArray.Select(token => token.ToString()).ToArray(); |
|
|
|
string? imageBasePath = ConfigurationManager.AppSettings["ImageFileBasePath"]; // 图片根目录 |
|
if (string.IsNullOrEmpty(imageBasePath)) |
|
{ |
|
Logger.Error("ImageFileBasePath is not configured in AppSettings."); |
|
return; |
|
} |
|
|
|
foreach (string imageFile in imageFiles) |
|
{ |
|
// 获取文件名 |
|
string fileName = Path.GetFileName(imageFile); |
|
// 构建完整的源文件路径 |
|
string sourcePath = Path.Combine(imageBasePath, imageFile); |
|
// 组合目标路径 |
|
string destinationPath = Path.Combine(newFolderPath, fileName); |
|
// 复制文件到目标路径,如果目标文件已存在则覆盖 |
|
File.Copy(sourcePath, destinationPath, true); |
|
} |
|
} |
|
catch (JsonException ex) |
|
{ |
|
// 记录日志或处理异常 |
|
Logger.Error($"Error parsing image_files JSON: {ex.Message}"); |
|
Logger.Error($"Stack Trace: {ex.StackTrace}"); |
|
} |
|
catch (Exception ex) |
|
{ |
|
// 记录其他异常 |
|
Logger.Error($"Error saving images: {ex.Message}"); |
|
Logger.Error($"Stack Trace: {ex.StackTrace}"); |
|
} |
|
} |
|
} |
|
|
|
}
|
|
|