using System.Net; using System.Net.Sockets; using System.Text; namespace Recordingtest.EngineBridge.IntegrationTests; public sealed class FakeBridgeServer : IDisposable { public Dictionary Responses { get; } = new(); public TimeSpan ResponseDelay { get; set; } = TimeSpan.Zero; private readonly HttpListener _listener; private readonly Thread _thread; private volatile bool _stop; public int Port { get; } public string BaseUrl => $"http://localhost:{Port}"; public FakeBridgeServer() { Port = FindFreePort(); _listener = new HttpListener(); _listener.Prefixes.Add($"http://localhost:{Port}/"); _listener.Start(); _thread = new Thread(Loop) { IsBackground = true }; _thread.Start(); } private static int FindFreePort() { var l = new TcpListener(IPAddress.Loopback, 0); l.Start(); var p = ((IPEndPoint)l.LocalEndpoint).Port; l.Stop(); return p; } private void Loop() { while (!_stop && _listener.IsListening) { HttpListenerContext ctx; try { ctx = _listener.GetContext(); } catch { return; } try { if (ResponseDelay > TimeSpan.Zero) Thread.Sleep(ResponseDelay); var path = ctx.Request.Url?.AbsolutePath ?? "/"; if (Responses.TryGetValue(path, out var body)) { var bytes = Encoding.UTF8.GetBytes(body); ctx.Response.StatusCode = 200; ctx.Response.ContentType = "application/json"; ctx.Response.OutputStream.Write(bytes, 0, bytes.Length); } else { ctx.Response.StatusCode = 404; } ctx.Response.OutputStream.Close(); } catch { try { ctx.Response.Abort(); } catch { } } } } public void Dispose() { _stop = true; try { _listener.Stop(); } catch { } try { _listener.Close(); } catch { } } }