using System.Net.Http; using System.Text.Json; namespace Recordingtest.EngineBridge.Client; public sealed class HmEgHttpSnapshot : IEngineSnapshot, IDisposable { public const string DefaultBaseUrl = "http://localhost:38080"; private readonly HttpClient _http; private readonly bool _ownsClient; private readonly string _baseUrl; public HmEgHttpSnapshot(string baseUrl = DefaultBaseUrl, HttpClient? httpClient = null, TimeSpan? timeout = null) { _baseUrl = baseUrl.TrimEnd('/'); if (httpClient is null) { _http = new HttpClient { Timeout = timeout ?? TimeSpan.FromSeconds(2) }; _ownsClient = true; } else { _http = httpClient; if (timeout.HasValue) _http.Timeout = timeout.Value; _ownsClient = false; } } public IReadOnlyList SelectedObjectIds { get { using var doc = Get("/selection"); var arr = doc.RootElement.GetProperty("selected_ids"); var list = new List(arr.GetArrayLength()); foreach (var e in arr.EnumerateArray()) list.Add(e.GetString() ?? string.Empty); return list; } } public CameraState Camera { get { using var doc = Get("/camera"); var r = doc.RootElement; return new CameraState( ToArray(r.GetProperty("eye")), ToArray(r.GetProperty("target")), ToArray(r.GetProperty("up")), r.GetProperty("fov").GetDouble()); } } public SceneSummary Scene { get { using var doc = Get("/scene"); var r = doc.RootElement; string? path = r.TryGetProperty("document_path", out var dp) && dp.ValueKind == JsonValueKind.String ? dp.GetString() : null; return new SceneSummary(r.GetProperty("object_count").GetInt32(), path); } } public bool IsRenderComplete { get { using var doc = Get("/render"); return doc.RootElement.GetProperty("complete").GetBoolean(); } } public bool IsHealthy { get { try { using var doc = Get("/health"); return doc.RootElement.TryGetProperty("status", out var s) && s.GetString() == "ok"; } catch (EngineBridgeException) { return false; } } } private JsonDocument Get(string endpoint) { try { using var resp = _http.GetAsync(_baseUrl + endpoint).GetAwaiter().GetResult(); if (!resp.IsSuccessStatusCode) throw new EngineBridgeException(endpoint, $"HTTP {(int)resp.StatusCode}"); var body = resp.Content.ReadAsStringAsync().GetAwaiter().GetResult(); return JsonDocument.Parse(body); } catch (EngineBridgeException) { throw; } catch (TaskCanceledException ex) { throw new EngineBridgeException(endpoint, "timeout", ex); } catch (Exception ex) { throw new EngineBridgeException(endpoint, ex.Message, ex); } } private static double[] ToArray(JsonElement e) { var arr = new double[e.GetArrayLength()]; int i = 0; foreach (var item in e.EnumerateArray()) arr[i++] = item.GetDouble(); return arr; } public void Dispose() { if (_ownsClient) _http.Dispose(); } }