using System; using System.Collections.Generic; using System.Linq; using System.Net.Http; using System.Text; using System.Threading.Tasks; using Newtonsoft.Json; namespace ivf_tl_Operate.Debug { /// /// operate 端"16 孔标定协作"客户端:封装 control 的 /debug/calibrate/* 四端点(start/progress/recalibrate/stop) /// + 轮询进度。复用 operate 已借到的 sessionId(由 DebugSessionClient.Acquire 取得),全程同一会话。 /// 纯逻辑可单测:HttpClient 可注入(测试用 FakeHandler);http=null 则自建并自 Dispose(对齐 DebugSessionClient)。 /// start/recalibrate/stop 返回 AcquireResult(对齐 control DebugCommandResult:Ok/Result/Error/Code); /// progress 返回 CalibProgressDto(从 DebugCommandResult.result 内嵌对象反序列化)。 /// 实时画面复用 MjpegStreamClient(不在本类)。 /// public sealed class CalibrationClient : IDisposable { private readonly string _baseUrl; private readonly string _sessionId; private readonly HttpClient _http; private readonly bool _ownsHttp; public CalibrationClient(string baseUrl, string sessionId, HttpClient http = null) { _baseUrl = baseUrl.TrimEnd('/'); _sessionId = sessionId; _ownsHttp = http == null; // 自建的由本类 Dispose;注入的归调用方 _http = http ?? new HttpClient(); } // /progress 的 result 内嵌 CalibProgress,用 envelope 把外层 ok/code 与内层 result 一并取出。 private sealed class ProgressEnvelope { [JsonProperty("ok")] public bool Ok { get; set; } [JsonProperty("code")] public string Code { get; set; } [JsonProperty("error")] public string Error { get; set; } [JsonProperty("result")] public CalibProgressDto Result { get; set; } } private async Task PostAsync(string path, object body) { var content = new StringContent(body == null ? "{}" : JsonConvert.SerializeObject(body), Encoding.UTF8, "application/json"); var resp = await _http.PostAsync($"{_baseUrl}{path}", content); string s = await resp.Content.ReadAsStringAsync(); return JsonConvert.DeserializeObject(s) ?? new AcquireResult { Ok = false, Error = "空响应" }; } /// 起一次 16 孔标定。wells 为空则 control 端默认 1..16。 public Task StartAsync(IEnumerable wells = null) => PostAsync("/debug/calibrate/start", new { sessionId = _sessionId, wells = wells?.ToArray() }); /// 轮询进度:返回 CalibProgressDto(无进度/会话失效则返回 null)。 public async Task PollProgressAsync() { var content = new StringContent(JsonConvert.SerializeObject(new { sessionId = _sessionId }), Encoding.UTF8, "application/json"); var resp = await _http.PostAsync($"{_baseUrl}/debug/calibrate/progress", content); string s = await resp.Content.ReadAsStringAsync(); var env = JsonConvert.DeserializeObject(s); return env?.Result; // ok=false(SESSION_EXPIRED 等)时 result 缺省 → null } /// 单孔重标。 public Task RecalibrateAsync(int wellSn) => PostAsync("/debug/calibrate/recalibrate", new { sessionId = _sessionId, wellSn }); /// 中止标定。 public Task StopAsync() => PostAsync("/debug/calibrate/stop", new { sessionId = _sessionId }); public void Dispose() { if (_ownsHttp) { try { _http?.Dispose(); } catch { } } // 只释放自建的;注入的归调用方 } } }