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
};
}
}
}