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.

273 lines
13 KiB

using System.Data;
using System.IO;
using System.Runtime.InteropServices;
using System.Windows.Forms;
using log4net;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using SparkClient.Model.Entity.ApiEntity;
using SparkClient.Model.Helper;
using System.Configuration;
using SparkClient.Model.Common;
namespace SparkClient.Model.Services
{
public class AlgorithmServer
{
private static readonly ILog Logger = LogManager.GetLogger(typeof(AlgorithmServer));
// 导入 C++ DLL 中的 DetectDiamond 函数
[DllImport("diamond_cut_inspector.dll", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
private static extern IntPtr DetectDiamond(string jsonData);
// 导入 C++ DLL 中的 FreeMemory 函数
[DllImport("diamond_cut_inspector.dll", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
private static extern void FreeString(IntPtr ptr);
// 添加公共方法
public AlgorithmResultEntity 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;
//算法配置参数
string sql = $"SELECT JSON FROM ALGORITHM_CONFIG ORDER BY JSON_ORDER ASC";
DataTable table = DataBaseHelper.ExecuteQuery(sql);
object lightLevelValue = table.Rows[0][0];
string algo_config = lightLevelValue.ToString() ?? throw new InvalidOperationException();
//图片根目录
string? image_file_base_path = ConfigurationManager.AppSettings["ImageFileBasePath"];
// 获取 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();
// 调用 C++ DLL 函数解析 JSON
IntPtr resultPtr = DetectDiamond(jsonDataString);
string resultJson = Marshal.PtrToStringAnsi(resultPtr);
// 释放 DLL 分配的内存
FreeString(resultPtr);
// 检查返回的 JSON 字符串是否为空或无效
if (string.IsNullOrEmpty(resultJson))
{
// 返回一个默认的 AlgorithmResultEntity 对象表示解析失败
return new AlgorithmResultEntity
{
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.Error($"Algorithm failed with status: {result.status}");
// 记录算法失败的错误信息
Logger.Error($"Algorithm failed with errorMsg: {result.error_msg}");
// 处理 C++ DLL 日志文件
//ProcessDllLog();
// 算法调用失败时,保存图片到历史记录文件夹
// 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 = 1000L * 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}");
}
}
/// <summary>
/// 处理 C++ DLL 的日志文件,将其复制到 log4net 日志目录下的 logs 文件夹,并记录其内容到日志中
/// </summary>
private void ProcessDllLog()
{
try
{
// 获取系统临时目录路径(TMP 或 TEMP 环境变量)
string? tempDirectory = Environment.GetEnvironmentVariable("TMP") ?? Environment.GetEnvironmentVariable("TEMP");
if (tempDirectory != null)
{
// 构建搜索模式
string searchPattern = "*diamond_cut_inspector*";
// 获取所有匹配的文件
string[] logFiles = Directory.GetFiles(tempDirectory, searchPattern, SearchOption.TopDirectoryOnly);
if (logFiles.Length > 0)
{
// 找到最新的日志文件
string latestLogFile = logFiles.OrderByDescending(file => new FileInfo(file).LastWriteTime).First();
// 获取 log4net 日志文件所在的目录
string log4netLogDirectory = Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location);
if (log4netLogDirectory != null)
{
// 构建 logs 目录路径
string logsDirectory = Path.Combine(log4netLogDirectory, "logs");
// 确保 logs 目录存在
Directory.CreateDirectory(logsDirectory);
// 构建目标文件路径
string targetFilePath = Path.Combine(logsDirectory, Path.GetFileName(latestLogFile));
// 复制最新日志文件到 logs 目录
File.Copy(latestLogFile, targetFilePath, true);
// 读取复制后的日志文件的内容
string dllLogContent = File.ReadAllText(targetFilePath);
// 记录 C++ DLL 日志文件的内容到日志中
Logger.Error("C++ DLL Log Content:");
Logger.Error(dllLogContent);
}
else
{
Logger.Error("Unable to determine the log4net log directory.");
}
}
else
{
// 如果没有找到匹配的日志文件,记录错误信息
Logger.Error("No C++ DLL log files found matching the pattern '*diamond_cut_inspector*.log'.");
}
}
else
{
// 如果无法获取临时目录路径,记录错误信息
Logger.Error("Unable to determine the temporary directory path.");
}
}
catch (Exception ex)
{
// 记录读取或复制日志文件时的异常
Logger.Error($"Error processing C++ DLL log file: {ex.Message}");
Logger.Error($"Stack Trace: {ex.StackTrace}");
}
}
}
}