| 11 | #include "fl/system/delay.h" |
| 12 | |
| 13 | FL_TEST_FILE(FL_FILEPATH) { |
| 14 | |
| 15 | using namespace fl; |
| 16 | |
| 17 | // Use port 0 so the OS assigns a free port — avoids hardcoded port conflicts |
| 18 | // with Windows Hyper-V/NAT reserved ranges and TIME_WAIT races. |
| 19 | static const uint16_t kAnyPort = 0; |
| 20 | |
| 21 | // RAII wrapper for NativeHttpServer. Uses port 0 (OS-assigned). |
| 22 | // NativeHttpServer has no move/copy, so we must heap-allocate. |
| 23 | struct ServerGuard { |
| 24 | fl::unique_ptr<NativeHttpServer> ptr; |
| 25 | uint16_t port = 0; |
| 26 | ServerGuard() = default; |
| 27 | ServerGuard(ServerGuard&& o) : ptr(fl::move(o.ptr)), port(o.port) { o.port = 0; } |
| 28 | ServerGuard& operator=(ServerGuard&& o) { ptr = fl::move(o.ptr); port = o.port; o.port = 0; return *this; } |
| 29 | ~ServerGuard() { if (ptr) { ptr->stop(); } } |
| 30 | NativeHttpServer* operator->() { return ptr.get(); } |
| 31 | NativeHttpServer& operator*() { return *ptr; } |
| 32 | explicit operator bool() const { return ptr != nullptr; } |
| 33 | }; |
| 34 | |
| 35 | static ServerGuard makeServer(const ConnectionConfig& config = ConnectionConfig()) { |
| 36 | ServerGuard g; |
| 37 | g.ptr = fl::make_unique<NativeHttpServer>(kAnyPort, config); |
| 38 | if (g.ptr->start()) { |
| 39 | g.port = g.ptr->port(); |
| 40 | return g; |
| 41 | } |
| 42 | g.ptr.reset(); |
| 43 | return g; |
| 44 | } |
| 45 | |
| 46 | // Server thread: runs accept + update in background, posts results via atomics/mutex. |
| 47 | // This is the standard net-thread-to-main pattern: a dedicated networking thread |
| 48 | // handles blocking/polling work and the main thread reads results. |
| 49 | struct NetThread { |
| 50 | NativeHttpServer& server; |
| 51 | fl::atomic<bool> running{true}; |
| 52 | fl::mutex mtx; |
| 53 | // Accumulated recv data per client (simplified: single client) |
| 54 | fl::vector<uint8_t> recvBuf; |
| 55 | fl::atomic<int> recvReady{0}; |
| 56 | fl::thread thread; |
| 57 | |
| 58 | explicit NetThread(NativeHttpServer& s) : server(s) { |
| 59 | thread = fl::thread([this]() { run(); }); |
| 60 | } |
| 61 | |
| 62 | ~NetThread() { |
| 63 | running.store(false); |
| 64 | if (thread.joinable()) thread.join(); |
| 65 | } |
| 66 | |
| 67 | void run() { |
| 68 | while (running.load()) { |
| 69 | server.acceptClients(); |
| 70 | fl::this_thread::sleep_for(fl::chrono::milliseconds(1)); // ok sleep for |
nothing calls this directly
no test coverage detected