add:soc接口

master
handefeng 8 months ago
parent 3f5a6140f9
commit 7be3c8edb4
  1. 184
      Model/Services/SOCClientService.cs
  2. 32
      Model/Services/StatusCodes.cs
  3. 7
      Resource/Document/log.txt
  4. 8
      SparkClient.csproj
  5. 2
      SparkClient.sln.DotSettings.user

@ -1,23 +1,62 @@
using Newtonsoft.Json; using Newtonsoft.Json;
using System; using System;
using System.IO;
using System.Net.Http; using System.Net.Http;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Windows;
using HandyControl.Tools.Extension;
namespace SparkClient.Model.Services namespace SparkClient.Model.Services
{ {
/// <summary>
/// SOC 客户端服务类,用于与远程服务器进行交互,包括启动图片收集任务、获取图片、获取采集状态等操作。
/// </summary>
public class SOCClientService public class SOCClientService
{ {
// Log地址
private const string LogFilePath = @"..\..\..\Resource\Document\log.txt";
// Log格式
private const string LogMessageFormat = "[{0:yyyy-MM-dd HH:mm:ss.fff}] 发生异常: {1}{2}";
private static readonly Dictionary<string, string> StatusDescriptions = new Dictionary<string, string>
{
{ "S000", "成功" },
{ "S001", "采图正在进行中" },
{ "S002", "缓存图片被清理(读取不够及时)" },
{ "S003", "无法向单片机发送指令" },
{ "S004", "单片机访问超时" },
{ "S005", "单片机返回错误码" },
{ "P001", "未找到切工仪" },
{ "P002", "算法调用失败" }
};
/// <summary>
/// 基础URL,用于构建完整的API请求地址。
/// </summary>
private readonly string _baseUrl; private readonly string _baseUrl;
/// <summary>
/// 认证令牌,用于HTTP请求的认证。
/// </summary>
private readonly string _authToken; private readonly string _authToken;
/// <summary>
/// 构造函数,初始化基础URL和认证令牌。
/// </summary>
/// <param name="baseUrl">基础URL</param>
/// <param name="authToken">认证令牌</param>
public SOCClientService(string baseUrl, string authToken) public SOCClientService(string baseUrl, string authToken)
{ {
_baseUrl = baseUrl; _baseUrl = baseUrl;
_authToken = authToken; _authToken = authToken;
} }
// 通用GET请求方法 /// <summary>
/// 发送GET请求的通用方法。
/// </summary>
/// <param name="url">请求的完整URL</param>
/// <returns>HTTP响应</returns>
private async Task<HttpResponseMessage> SendGetRequestAsync(string url) private async Task<HttpResponseMessage> SendGetRequestAsync(string url)
{ {
using (var client = new HttpClient()) using (var client = new HttpClient())
@ -27,7 +66,11 @@ namespace SparkClient.Model.Services
} }
} }
// 1. 启动图片收集任务 /// <summary>
/// 启动图片收集任务。
/// </summary>
/// <param name="lightLevel">光照级别</param>
/// <returns>任务状态</returns>
public async Task<string> CollectImagesAsync(int lightLevel) public async Task<string> CollectImagesAsync(int lightLevel)
{ {
string url = $"{_baseUrl}/collect_images?light_level={lightLevel}"; string url = $"{_baseUrl}/collect_images?light_level={lightLevel}";
@ -41,27 +84,55 @@ namespace SparkClient.Model.Services
} }
else else
{ {
return "Error: " + response.StatusCode; return "collect_images_Error: " + (int)response.StatusCode;
} }
} }
// 2. 获取图片 /// <summary>
public async Task<byte[]> RetrieveImageAsync(int index) /// 获取指定索引的图片。
/// </summary>
/// <param name="index">图片索引</param>
/// <returns>图片的字节数组</returns>
public async Task<List<string>> RetrieveImageAsync(string savePath)
{ {
string url = $"{_baseUrl}/retrieve_image/{index}"; List<string> imageNames = new List<string>();
var response = await SendGetRequestAsync(url); // 读取图片接口
int imageIndex = 0;
if (response.IsSuccessStatusCode) while (true)
{
return await response.Content.ReadAsByteArrayAsync();
}
else
{ {
throw new Exception("Error retrieving image: " + response.StatusCode); string url = $"{_baseUrl}/retrieve_image/{imageIndex}";
var response = await SendGetRequestAsync(url);
int status = (int)response.StatusCode;
if (status == 200)
{
byte[] imageBytes = await response.Content.ReadAsByteArrayAsync();
string fileName = Path.Combine(savePath, $"image_{imageIndex}.bmp");
// 图片名称List
imageNames.Add(Path.GetFileName(fileName));
// 保存图片
await File.WriteAllBytesAsync(fileName, imageBytes);
imageIndex++;
}
else if (status == 425)
{
await Task.Delay(1000);
}
else if (status == 410)
{
imageIndex++;
}
else if (status == 404)
{
return imageNames;
}
} }
} }
// 3. 获取采集状态 /// <summary>
/// 获取图片采集状态。
/// </summary>
/// <returns>采集状态</returns>
public async Task<string> CollectStatusAsync() public async Task<string> CollectStatusAsync()
{ {
string url = $"{_baseUrl}/collect_status"; string url = $"{_baseUrl}/collect_status";
@ -75,14 +146,95 @@ namespace SparkClient.Model.Services
} }
else else
{ {
return "Error: " + response.StatusCode; return "collect_status_Error: " + (int)response.StatusCode;
} }
} }
/// <summary>
/// 处理图片收集、保存和状态检查。
/// </summary>
/// <param name="lightLevel">光照级别</param>
/// <param name="savePath">图片保存路径</param>
/// <returns>操作结果</returns>
public async Task<string> ProcessImageCollectionAsync(int lightLevel, string savePath)
{
try
{
// 清理 savePath 文件夹
if (Directory.Exists(savePath))
{
Directory.Delete(savePath, true);
}
Directory.CreateDirectory(savePath);
// 启动任务接口
string startStatus = await CollectImagesAsync(lightLevel);
if (startStatus != "S000")
{
// 启动任务失败
return JsonConvert.SerializeObject(new { status = startStatus, images = new List<string>() });
}
// 读取图片接口
List<string> imageNames = await RetrieveImageAsync(savePath);
if (imageNames.Count != 0)
{
// 采集状态接口
string acquisitionStatus = await CollectStatusAsync();
if (acquisitionStatus != "S000")
{
// 采集状态失败
return JsonConvert.SerializeObject(new { status = acquisitionStatus, images = new List<string>() });
}
}
// 按下载时间排序图片名称
return JsonConvert.SerializeObject(new { status = "S000", images = imageNames });
}
catch (Exception e)
{
// 日志记录
// logger.Error(e, "发生异常");
string logMessage = $"[{DateTime.Now:yyyy-MM-dd HH:mm:ss.fff}] 发生异常: {e.Message}{Environment.NewLine}";
File.AppendAllText(LogFilePath, logMessage);
return JsonConvert.SerializeObject(new { status = "P001", images = new List<string>() });
}
}
/// <summary>
/// 根据状态码获取相应的描述信息。
/// 如果状态码在预定义的状态字典中存在,则返回对应的描述信息;
/// 否则返回“未知状态: [状态码]”。
/// </summary>
/// <param name="status">状态码。</param>
/// <returns>状态描述信息。</returns>
private string GetDescription(string status)
{
if (StatusDescriptions.TryGetValue(status, out string description))
{
return description;
}
return "未知状态: " + status;
}
} }
/// <summary>
/// 响应状态类,用于解析服务器返回的状态信息。
/// </summary>
public class ResponseStatus public class ResponseStatus
{ {
/// <summary>
/// 状态码
/// </summary>
public string Status { get; set; } public string Status { get; set; }
/// <summary>
/// 状态消息
/// </summary>
public string Message { get; set; } public string Message { get; set; }
} }
} }

@ -0,0 +1,32 @@
namespace SparkClient.Model.Common
{
/// <summary>
/// 存储状态码及其描述信息的常量类。
/// </summary>
public static class StatusCodes
{
// 成功
public const string S000 = "S000";
// 采图正在进行中
public const string S001 = "S001";
// 缓存图片被清理(读取不够及时)
public const string S002 = "S002";
// 无法向单片机发送指令
public const string S003 = "S003";
// 单片机访问超时
public const string S004 = "S004";
// 单片机返回错误码
public const string S005 = "S005";
// 未找到切工仪
public const string P001 = "P001";
// 算法调用失败
public const string P002 = "P002";
}
}

@ -0,0 +1,7 @@
[2024-12-05 16:21:22.627] 发生异常: 由于目标计算机积极拒绝,无法连接。 (localhost:5000)
[2024-12-05 16:42:38.854] 发生异常: 由于目标计算机积极拒绝,无法连接。 (localhost:5000)
[2024-12-05 16:42:49.827] 发生异常: 由于目标计算机积极拒绝,无法连接。 (localhost:5000)
[2024-12-05 16:50:48.304] 发生异常: 由于目标计算机积极拒绝,无法连接。 (localhost:5000)
[2024-12-05 16:50:56.037] 发生异常: 由于目标计算机积极拒绝,无法连接。 (localhost:5000)
[2024-12-05 16:51:04.013] 发生异常: 由于目标计算机积极拒绝,无法连接。 (localhost:5000)
[2024-12-05 16:58:31.184] 发生异常: 由于目标计算机积极拒绝,无法连接。 (localhost:5000)

@ -30,6 +30,9 @@
<None Update="log4net.config"> <None Update="log4net.config">
<CopyToOutputDirectory>Always</CopyToOutputDirectory> <CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None> </None>
<None Update="SparkDB.db">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Remove="Resource\Images\config_3x.png" /> <None Remove="Resource\Images\config_3x.png" />
<Resource Include="Resource\Images\config_3x.png" /> <Resource Include="Resource\Images\config_3x.png" />
<None Remove="Resource\Images\diam_3x.png" /> <None Remove="Resource\Images\diam_3x.png" />
@ -100,4 +103,9 @@
<Compile Remove="Resource\Images\Temp\**" /> <Compile Remove="Resource\Images\Temp\**" />
</ItemGroup> </ItemGroup>
<ItemGroup>
<Folder Include="Libs\" />
<Folder Include="Resource\SOCImages\" />
</ItemGroup>
</Project> </Project>

@ -7,6 +7,8 @@
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ADependencyObject_002Ecs_002Fl_003AC_0021_003FUsers_003Ftongg_003FAppData_003FRoaming_003FJetBrains_003FRider2024_002E3_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F60b63c019ead4a238340b47a1c0010d5226910_003Fca_003F09e9dbc0_003FDependencyObject_002Ecs/@EntryIndexedValue">ForceIncluded</s:String> <s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ADependencyObject_002Ecs_002Fl_003AC_0021_003FUsers_003Ftongg_003FAppData_003FRoaming_003FJetBrains_003FRider2024_002E3_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F60b63c019ead4a238340b47a1c0010d5226910_003Fca_003F09e9dbc0_003FDependencyObject_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AEventToCommand_002Ecs_002Fl_003AC_0021_003FUsers_003Ftongg_003FAppData_003FRoaming_003FJetBrains_003FRider2024_002E3_003Fresharper_002Dhost_003FSourcesCache_003F436b6c3e323d68842c9e251322f5d42b47569f7c925e63aa245dc65465d2843_003FEventToCommand_002Ecs/@EntryIndexedValue">ForceIncluded</s:String> <s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AEventToCommand_002Ecs_002Fl_003AC_0021_003FUsers_003Ftongg_003FAppData_003FRoaming_003FJetBrains_003FRider2024_002E3_003Fresharper_002Dhost_003FSourcesCache_003F436b6c3e323d68842c9e251322f5d42b47569f7c925e63aa245dc65465d2843_003FEventToCommand_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AEventTriggerBase_002Ecs_002Fl_003AC_0021_003FUsers_003Ftongg_003FAppData_003FRoaming_003FJetBrains_003FRider2024_002E3_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003Ffdc001c928464b80ad45ffa09b838a3a15e200_003Faf_003F9abbeb44_003FEventTriggerBase_002Ecs/@EntryIndexedValue">ForceIncluded</s:String> <s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AEventTriggerBase_002Ecs_002Fl_003AC_0021_003FUsers_003Ftongg_003FAppData_003FRoaming_003FJetBrains_003FRider2024_002E3_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003Ffdc001c928464b80ad45ffa09b838a3a15e200_003Faf_003F9abbeb44_003FEventTriggerBase_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AExecutionContext_002Ecs_002Fl_003AC_0021_003FUsers_003FAdministrator_003FAppData_003FRoaming_003FJetBrains_003FRider2024_002E3_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F211e6f3b24fa438a92f1815153647ce2c8f908_003F35_003F053c62c1_003FExecutionContext_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AFile_002Ecs_002Fl_003AC_0021_003FUsers_003FAdministrator_003FAppData_003FRoaming_003FJetBrains_003FRider2024_002E3_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F211e6f3b24fa438a92f1815153647ce2c8f908_003F00_003Fb0994fb0_003FFile_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AFrameworkElement_002Ecs_002Fl_003AC_0021_003FUsers_003Ftongg_003FAppData_003FRoaming_003FJetBrains_003FRider2024_002E3_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F6412d4331611499aab4eb63809a2a83bf60910_003F07_003Fdab5922a_003FFrameworkElement_002Ecs/@EntryIndexedValue">ForceIncluded</s:String> <s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AFrameworkElement_002Ecs_002Fl_003AC_0021_003FUsers_003Ftongg_003FAppData_003FRoaming_003FJetBrains_003FRider2024_002E3_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F6412d4331611499aab4eb63809a2a83bf60910_003F07_003Fdab5922a_003FFrameworkElement_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AGuid_002Ecs_002Fl_003AC_0021_003FUsers_003Ftongg_003FAppData_003FRoaming_003FJetBrains_003FRider2024_002E3_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F211e6f3b24fa438a92f1815153647ce2c8f908_003Faa_003Fa49e75b9_003FGuid_002Ecs/@EntryIndexedValue">ForceIncluded</s:String> <s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AGuid_002Ecs_002Fl_003AC_0021_003FUsers_003Ftongg_003FAppData_003FRoaming_003FJetBrains_003FRider2024_002E3_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F211e6f3b24fa438a92f1815153647ce2c8f908_003Faa_003Fa49e75b9_003FGuid_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AILog_002Ecs_002Fl_003AC_0021_003FUsers_003Ftongg_003FAppData_003FRoaming_003FJetBrains_003FRider2024_002E3_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F6f4e00a876324444bc5ae4e52ed22ade46200_003F49_003Fe673ccfc_003FILog_002Ecs/@EntryIndexedValue">ForceIncluded</s:String> <s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AILog_002Ecs_002Fl_003AC_0021_003FUsers_003Ftongg_003FAppData_003FRoaming_003FJetBrains_003FRider2024_002E3_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F6f4e00a876324444bc5ae4e52ed22ade46200_003F49_003Fe673ccfc_003FILog_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>

Loading…
Cancel
Save