using Newtonsoft.Json; using System; using System.Configuration; using System.Data; using System.IO; using System.Net.Http; using System.Text; using log4net; using BrilliantSightClient.Model; using BrilliantSightClient.Model.Entity.ApiEntity; using BrilliantSightClient.Model.Extension; using BrilliantSightClient.Model.Helper; namespace BrilliantSightClient.Model.Services { /// /// SOC 客户端服务类,用于与远程服务器进行交互,包括启动图片收集任务、获取图片、获取采集状态等操作。 /// public class SOCClientService { // Log地址 private static readonly ILog Logger = LogManager.GetLogger(typeof(SOCClientService)); /// /// 基础URL,用于构建完整的API请求地址。 /// private readonly string? _baseUrl; /// /// 认证令牌,用于HTTP请求的认证。 /// private readonly string _authToken; private static SOCClientService _service; public static SOCClientService Service { get { if (_service == null) _service = new SOCClientService(); return _service; } } private bool GenImage; /// /// 构造函数,初始化基础URL和认证令牌。 /// private SOCClientService() { _baseUrl = ConfigurationManager.AppSettings["BaseUrl"]; _authToken = "your_basic_auth_token"; } /// /// 发送GET请求的通用方法。 /// /// 请求的完整URL /// HTTP响应 private async Task> SendGetRequestAsync(string url, string sendCode = "", JsonSerializerSettings settings = null)where T : ResponseStatus { if (sendCode.IsNullOrEmpty()) { sendCode = url.GenerateSign(); } using (var client = new HttpClient()) { Logger.Info($"[SendCode={sendCode}]Request sent to URL: {url}"); client.DefaultRequestHeaders.Add("Authorization", "Basic " + _authToken); client.Timeout = new TimeSpan(0, 0, 30); HttpResponseMessage result = await client.GetAsync(url); // 提前读取内容并存储 string responseBody = await result.Content.ReadAsStringAsync(); int statusCode = (int)result.StatusCode; // 记录日志 Logger.Info($"[SendCode={sendCode}]Response: Status={statusCode}, Body={responseBody}"); var tempEntity = JsonConvert.DeserializeObject(responseBody, settings); if (StatusCodes.PreviousTaskIncomplete.Equals(tempEntity.Status)) { Logger.Info($"S009 请求重试"); await Task.Delay(500); return await SendGetRequestAsync(url, sendCode); } return new HttpSendResult() { StatusCode = statusCode, Content = tempEntity, }; } } private async Task SendGetRequestImageAsync(string url, string sendCode = "") { if (sendCode.IsNullOrEmpty()) { sendCode = url.GenerateSign(); } using (var client = new HttpClient()) { Logger.Info($"[SendCode={sendCode}]Request Image Download URL: {url}"); client.DefaultRequestHeaders.Add("Authorization", "Basic " + _authToken); var data = await client.GetAsync(url); Logger.Info($"[SendCode={sendCode}]Request Image Downloaded {data.StatusCode}"); return data; } } /// /// 启动图片收集任务。 /// /// 任务状态 public async Task CollectImagesAsync() { try { GenImage = true; // 光照度和半圆 int lightLevel = 0; string halfCircle = string.Empty; // 查询光照度和半圆配置 string sql = $"SELECT KEY, VALUE FROM CUTTER_CONFIG "; DataTable table = DataBaseHelper.ExecuteQuery(sql); if (table == null || table.Rows.Count == 0) { throw new Exception("No data found for the specified keys."); } StringBuilder sbParams = new StringBuilder(); foreach (DataRow row in table.Rows) { string key = row["Key"].ToString() ?? string.Empty; string value = row["Value"].ToString() ?? string.Empty; // if (key == "light_level" && int.TryParse(value, out int parsedLightLevel)) // { // lightLevel = parsedLightLevel; // 光照度 // } // else if (key == "half_circle") // { // halfCircle = value; // 半圆 // } sbParams.Append($"{key}={value}&"); } // string url = $"{_baseUrl}/collect_images?light_level={lightLevel}&half_circle={halfCircle}"; string url = $"{_baseUrl}/collect_images?{sbParams.ToString().Substring(0, sbParams.ToString().Length - 1)}"; var response = await SendGetRequestAsync(url); if (response.StatusCode != 200) { return new SocResultEntity { Status = StatusCodes.DeviceNotFound, Images = new List() }; } var result = response.Content; if (result == null) { return new SocResultEntity { Status = StatusCodes.DeviceNotFound, Images = new List() }; } return new SocResultEntity { Status = result.Status, Images = new List(), DeviceId = result.device_id }; } catch (Exception ex) { // 记录日志或进行其他处理 Console.WriteLine($"Error in DoSoc: {ex.Message}"); Logger.Warn($"Error in DoSoc: {ex.Message}"); // 或者使用日志框架记录日志 // logger.LogError(ex, "Error in DoSoc method."); return new SocResultEntity { Status = StatusCodes.DeviceNotFound, Images = new List(), DeviceId = "" }; } finally { GenImage = false; } } /// /// 启动图片收集任务。 /// /// 任务状态 public Task> CollectImagesAsyncNotAwait() { try { GenImage = true; // 光照度和半圆 int lightLevel = 0; string halfCircle = string.Empty; // 查询光照度和半圆配置 string sql = $"SELECT KEY, VALUE FROM CUTTER_CONFIG "; DataTable table = DataBaseHelper.ExecuteQuery(sql); if (table == null || table.Rows.Count == 0) { throw new Exception("No data found for the specified keys."); } StringBuilder sbParams = new StringBuilder(); foreach (DataRow row in table.Rows) { string key = row["Key"].ToString() ?? string.Empty; string value = row["Value"].ToString() ?? string.Empty; // if (key == "light_level" && int.TryParse(value, out int parsedLightLevel)) // { // lightLevel = parsedLightLevel; // 光照度 // } // else if (key == "half_circle") // { // halfCircle = value; // 半圆 // } sbParams.Append($"{key}={value}&"); } // string url = $"{_baseUrl}/collect_images?light_level={lightLevel}&half_circle={halfCircle}"; string url = $"{_baseUrl}/collect_images?{sbParams.ToString().Substring(0, sbParams.ToString().Length - 1)}"; var result = SendGetRequestAsync(url); return result; } catch (Exception ex) { // 记录日志或进行其他处理 Console.WriteLine($"Error in DoSoc: {ex.Message}"); Logger.Warn($"Error in DoSoc: {ex.Message}"); // 或者使用日志框架记录日志 // logger.LogError(ex, "Error in DoSoc method."); return null; } finally { GenImage = false; } } /// /// 获取指定索引的图片。 /// /// 保存图片路径 /// 图片的字节数组 public async Task> RetrieveImageAsync(string? savePath, CancellationToken token = default) { List imageNames = new List(); // 读取图片接口 int imageIndex = 0; int imageTotal = ConfigurationHelper.ReadConfigValueToInteger("DetectImageTotal", 100); while (true) { if (imageIndex >= imageTotal) { return imageNames; } string url = $"{_baseUrl}/retrieve_image/{imageIndex}"; string sendCode = url.GenerateSign(); try { var response = await SendGetRequestImageAsync(url, sendCode); int status = (int)response.StatusCode; token.ThrowIfCancellationRequested(); switch (status) { case 200: byte[] imageBytes = await response.Content.ReadAsByteArrayAsync(); // 获取 Content-Type 头以确定图片格式 string contentType = response.Content.Headers.ContentType.MediaType; string fileExtension = GetFileExtension(contentType); string fileName = Path.Combine(savePath, $"image_{imageIndex}{fileExtension}"); // 图片名称List imageNames.Add(Path.GetFileName(fileName)); // 保存图片 await File.WriteAllBytesAsync(fileName, imageBytes); imageIndex++; break; case 425: // 请求被锁定,等待一段时间后重试 await Task.Delay(500); break; case 410: // 资源已被永久删除,跳过当前索引 imageIndex++; break; case 404: // 资源未找到,结束循环 Logger.Info($"[SendCode={sendCode}] Image Not Found."); break; //return imageNames; default: // 其他状态码,记录警告并继续 Logger.Warn($"[SendCode={sendCode}]Unexpected status code: {status} for URL: {url}"); imageIndex++; break; } } catch (HttpRequestException ex) { // 捕获HTTP请求异常并记录错误信息 Logger.Error($"[SendCode={sendCode}]HTTP request failed for URL: {url}, Exception: {ex.Message}"); return imageNames; } catch (Exception ex) { // 捕获其他异常并记录错误信息,结束循环 Logger.Error( $"[SendCode={sendCode}]An unexpected error occurred for URL: {url}, Exception: {ex.Message}"); return imageNames; } } } /// /// 获取图片采集状态。 /// /// 采集状态 public async Task CollectStatusAsync() { string url = $"{_baseUrl}/collect_status"; try { var response = await SendGetRequestAsync(url); Logger.Debug($" CollectStatusAsync url :{ url} "); if (response.StatusCode == 200) { ResponseStatus result = response.Content; Logger.Debug($" CollectStatusAsync result :{ result.ToSafeAbundantString()} "); return result.Status; } return StatusCodes.DeviceNotFound; } catch (HttpRequestException ex) { return StatusCodes.DeviceNotFound; } catch (JsonException ex) { return StatusCodes.DeviceNotFound; } catch (Exception ex) { return StatusCodes.DeviceNotFound; } } /// /// 处理图片收集、保存和状态检查。 /// /// 操作结果 public async Task ProcessImageCollectionAsync() { try { await OpenPump(true); // SOC接口 string? savePath = ConfigurationManager.AppSettings["ImageFileBasePath"]; // 清理 savePath 文件夹 if (Directory.Exists(savePath)) { Directory.Delete(savePath, true); } Directory.CreateDirectory(savePath); // 启动任务接口 SocResultEntity entity = await CollectImagesAsync(); // 成功 Logger.Debug($"entity :{entity.Status} {entity.ToString()} "); if (entity.Status != StatusCodes.Success) { // 启动任务失败 return new SocResultEntity { Status = entity.Status, Images = new List() }; } // 读取图片接口 List imageNames = await RetrieveImageAsync(savePath); if (imageNames.Count == 0) { Logger.Debug("imageNames.Count == 0"); // 图片文件读取失败 return new SocResultEntity { Status = StatusCodes.ImageFileReadFailure, Images = new List() }; } return new SocResultEntity { Status = "S000", Images = imageNames, DeviceId = entity.DeviceId}; } catch (Exception e) { // 日志记录 // logger.Error(e, "发生异常"); string logMessage = $"[{DateTime.Now:yyyy-MM-dd HH:mm:ss.fff}] 发生异常: {e.Message}{Environment.NewLine}"; Logger.Error(logMessage); return new SocResultEntity { Status = StatusCodes.DeviceNotFound, Images = new List() }; } finally { await OpenPump(false); } } /// /// 根据给定的 MIME 类型获取对应的文件扩展名。 /// /// HTTP 响应中的 Content-Type 头字段,表示内容的 MIME 类型。 /// 与 MIME 类型对应的文件扩展名。 /// 当传入的 MIME 类型不受支持时抛出此异常。 private string GetFileExtension(string contentType) { switch (contentType.ToLower()) { case "image/bmp": return ".bmp"; case "image/jpg": return ".jpg"; case "image/png": return ".png"; default: throw new InvalidOperationException($"Unsupported content type: {contentType}"); } } public async Task CutRevolve(double angle) { // await OpenPump(true); int param = (int)angle * 100; string url = $"{_baseUrl}/rotate_to?angle={param}"; // if(GenImage) return StatusCodes.DeviceNotFound; GenImage = true; try { var response = await SendGetRequestAsync(url); Logger.Debug(url); if (response.StatusCode == 200) { var result = response.Content; Logger.Debug($"Rotate Angle : {result.ToSafeAbundantString()} "); return result.Status; } return StatusCodes.DeviceNotFound; } catch (Exception e) { string logMessage = $"[{DateTime.Now:yyyy-MM-dd HH:mm:ss.fff}] 发生异常: {e.Message}{Environment.NewLine}"; Logger.Error(logMessage); return StatusCodes.DeviceNotFound; } finally { GenImage = false; // await OpenPump(true); } } public async Task OpenPump(bool isOpen) { string runModel = ConfigurationHelper.ReadConfigValue("RunModel") ?? "10"; if ("1" == runModel || "0" == runModel) { return StatusCodes.Success; } // if(GenImage) return StatusCodes.DeviceNotFound; Logger.Info($"气泵开关请求发起{isOpen}"); int param = isOpen ? 1 : 0 ; string url = $"{_baseUrl}/set_pump?on={param}"; Logger.Debug(url); try { var response = await SendGetRequestAsync(url); if (response.StatusCode == 200) { if (response.Content.Status != StatusCodes.Success) { return await OpenPump(isOpen); } var result = response.Content; Logger.Debug($"Set Pump : {result.ToSafeAbundantString()} "); return result.Status; } Logger.Info($"气泵开关请求发起完毕"); return StatusCodes.DeviceNotFound; } catch (Exception e) { string logMessage = $"[{DateTime.Now:yyyy-MM-dd HH:mm:ss.fff}] 发生异常: {e.Message}{Environment.NewLine}"; Logger.Error(logMessage); return StatusCodes.DeviceNotFound; } } public async Task GetGpioStatus() { string runModel = ConfigurationHelper.ReadConfigValue("RunModel") ?? "10"; if ("1" == runModel || "0" == runModel) { return GpioStatus.IsClose(); } string url = $"{_baseUrl}/gpio_check"; Logger.Info($"舱门状态检查开始:{url}"); try { var response = await SendGetRequestAsync(url); if (response.StatusCode == 200) { var result = response.Content; Logger.Info($"Set Pump : {result.ToSafeAbundantString()} "); return result; } Logger.Info($"舱门状态检查完毕,接口status非200视为关闭"); return GpioStatus.Default(); } catch (Exception e) { string logMessage = $"[{DateTime.Now:yyyy-MM-dd HH:mm:ss.fff}] 发生异常: {e.Message}{Environment.NewLine}"; Logger.Error(logMessage); return GpioStatus.Default(); } } } /// /// 响应状态类,用于解析服务器返回的状态信息。 /// public class ResponseStatus { /// /// 状态码 /// public string Status { get; set; } /// /// 状态消息 /// public string Message { get; set; } /// /// 机器号 /// public string device_id { get; set; } } public class GpioStatus : ResponseStatus { public int Value1 { get; set; } public int Value2 { get; set; } public bool LensGpioIsOpen() { return Value1 == 48; } public bool DiamondGpioIsOpen() { return Value2 == 48; } public bool LensGpioIsClose() { return Value1 == 49; } public bool DiamondGpioIsClose() { return Value2 == 49; } public static GpioStatus Default() { return new GpioStatus { Status = "S000", Value1 = 48, Value2 = 48 }; } public static GpioStatus IsClose() { return new GpioStatus { Status = "S000", Value1 = 49, Value2 = 49 }; } } }