#pragma once #include "NativeSockets.h" #include #include #include #include #include #include #include #include #include class JsonValue; class ControlServer { public: struct Callbacks { std::function getStateJson; std::function addLayer; std::function removeLayer; std::function moveLayer; std::function moveLayerToIndex; std::function setLayerBypass; std::function setLayerShader; std::function updateLayerParameter; std::function resetLayerParameters; std::function saveStackPreset; std::function loadStackPreset; std::function reloadShader; }; ControlServer(); ~ControlServer(); bool Start(const std::filesystem::path& uiRoot, unsigned short preferredPort, const Callbacks& callbacks, std::string& error); void Stop(); void BroadcastState(); unsigned short GetPort() const { return mPort; } private: struct ClientConnection { UniqueSocket socket; bool websocket = false; }; struct HttpRequest { std::string method; std::string path; std::map headers; std::string body; }; struct HttpResponse { std::string status; std::string contentType; std::string body; bool broadcastState = false; }; void ServerLoop(); bool HandleHttpClient(UniqueSocket clientSocket); bool TryAcceptClient(); bool SendHttpResponse(SOCKET clientSocket, const HttpResponse& response); bool SendHttpResponse(SOCKET clientSocket, const std::string& status, const std::string& contentType, const std::string& body); bool HandleHttpRequest(UniqueSocket clientSocket, const std::string& request); bool HandleWebSocketUpgrade(UniqueSocket clientSocket, const HttpRequest& request); HttpResponse RouteHttpRequest(const HttpRequest& request); HttpResponse ServeGetRequest(const HttpRequest& request) const; HttpResponse ServeUiAsset(const std::string& relativePath) const; HttpResponse HandleApiPost(const HttpRequest& request); bool InvokePostRoute(const std::string& path, const JsonValue& root, std::string& actionError); bool SendWebSocketText(SOCKET clientSocket, const std::string& payload); void BroadcastStateLocked(); std::string LoadUiAsset(const std::string& relativePath, std::string& contentType) const; std::string BuildJsonResponse(bool success, const std::string& error = std::string()) const; static std::string Base64Encode(const unsigned char* data, DWORD dataLength); static std::string ComputeWebSocketAcceptKey(const std::string& clientKey); static std::string GetHeaderValue(const HttpRequest& request, const std::string& headerName); static bool ParseHttpRequest(const std::string& rawRequest, HttpRequest& request); private: std::filesystem::path mUiRoot; Callbacks mCallbacks; UniqueSocket mListenSocket; unsigned short mPort; std::thread mThread; std::atomic mRunning; mutable std::mutex mMutex; std::vector mClients; };