CalibrationClient.cs 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Net.Http;
  5. using System.Text;
  6. using System.Threading.Tasks;
  7. using Newtonsoft.Json;
  8. namespace ivf_tl_Operate.Debug
  9. {
  10. /// <summary>
  11. /// operate 端"16 孔标定协作"客户端:封装 control 的 /debug/calibrate/* 四端点(start/progress/recalibrate/stop)
  12. /// + 轮询进度。复用 operate 已借到的 sessionId(由 DebugSessionClient.Acquire 取得),全程同一会话。
  13. /// 纯逻辑可单测:HttpClient 可注入(测试用 FakeHandler);http=null 则自建并自 Dispose(对齐 DebugSessionClient)。
  14. /// start/recalibrate/stop 返回 AcquireResult(对齐 control DebugCommandResult:Ok/Result/Error/Code);
  15. /// progress 返回 CalibProgressDto(从 DebugCommandResult.result 内嵌对象反序列化)。
  16. /// 实时画面复用 MjpegStreamClient(不在本类)。
  17. /// </summary>
  18. public sealed class CalibrationClient : IDisposable
  19. {
  20. private readonly string _baseUrl;
  21. private readonly string _sessionId;
  22. private readonly HttpClient _http;
  23. private readonly bool _ownsHttp;
  24. public CalibrationClient(string baseUrl, string sessionId, HttpClient http = null)
  25. {
  26. _baseUrl = baseUrl.TrimEnd('/');
  27. _sessionId = sessionId;
  28. _ownsHttp = http == null; // 自建的由本类 Dispose;注入的归调用方
  29. _http = http ?? new HttpClient();
  30. }
  31. // /progress 的 result 内嵌 CalibProgress,用 envelope 把外层 ok/code 与内层 result 一并取出。
  32. private sealed class ProgressEnvelope
  33. {
  34. [JsonProperty("ok")] public bool Ok { get; set; }
  35. [JsonProperty("code")] public string Code { get; set; }
  36. [JsonProperty("error")] public string Error { get; set; }
  37. [JsonProperty("result")] public CalibProgressDto Result { get; set; }
  38. }
  39. private async Task<AcquireResult> PostAsync(string path, object body)
  40. {
  41. var content = new StringContent(body == null ? "{}" : JsonConvert.SerializeObject(body), Encoding.UTF8, "application/json");
  42. var resp = await _http.PostAsync($"{_baseUrl}{path}", content);
  43. string s = await resp.Content.ReadAsStringAsync();
  44. return JsonConvert.DeserializeObject<AcquireResult>(s) ?? new AcquireResult { Ok = false, Error = "空响应" };
  45. }
  46. /// <summary>起一次 16 孔标定。wells 为空则 control 端默认 1..16。</summary>
  47. public Task<AcquireResult> StartAsync(IEnumerable<int> wells = null)
  48. => PostAsync("/debug/calibrate/start", new { sessionId = _sessionId, wells = wells?.ToArray() });
  49. /// <summary>轮询进度:返回 CalibProgressDto(无进度/会话失效则返回 null)。</summary>
  50. public async Task<CalibProgressDto> PollProgressAsync()
  51. {
  52. var content = new StringContent(JsonConvert.SerializeObject(new { sessionId = _sessionId }), Encoding.UTF8, "application/json");
  53. var resp = await _http.PostAsync($"{_baseUrl}/debug/calibrate/progress", content);
  54. string s = await resp.Content.ReadAsStringAsync();
  55. var env = JsonConvert.DeserializeObject<ProgressEnvelope>(s);
  56. return env?.Result; // ok=false(SESSION_EXPIRED 等)时 result 缺省 → null
  57. }
  58. /// <summary>单孔重标。</summary>
  59. public Task<AcquireResult> RecalibrateAsync(int wellSn)
  60. => PostAsync("/debug/calibrate/recalibrate", new { sessionId = _sessionId, wellSn });
  61. /// <summary>中止标定。</summary>
  62. public Task<AcquireResult> StopAsync()
  63. => PostAsync("/debug/calibrate/stop", new { sessionId = _sessionId });
  64. public void Dispose()
  65. {
  66. if (_ownsHttp) { try { _http?.Dispose(); } catch { } } // 只释放自建的;注入的归调用方
  67. }
  68. }
  69. }