#pragma once #include "duckdb.hpp" #define CPPHTTPLIB_OPENSSL_SUPPORT #include "httplib.hpp" #include #include #include #include #include namespace httplib = duckdb_httplib_openssl; namespace duckdb { class MemoryStream; namespace ui { struct CatalogState { std::map db_to_catalog_version; }; class EventDispatcher { public: bool WaitEvent(httplib::DataSink *sink); void SendEvent(const std::string &message); void Close(); private: std::mutex mutex; std::condition_variable cv; std::atomic_int next_id{0}; std::atomic_int current_id{-1}; std::atomic_int wait_count{0}; std::string message; std::atomic_bool closed{false}; }; class HttpServer { public: HttpServer(shared_ptr _ddb_instance) : ddb_instance(_ddb_instance) {} static HttpServer *GetInstance(ClientContext &); static void UpdateDatabaseInstanceIfRunning(shared_ptr); static bool Started(); static void StopInstance(); static const HttpServer &Start(ClientContext &, bool *was_started = nullptr); static bool Stop(); std::string LocalUrl() const; private: // Lifecycle void DoStart(const uint16_t local_port, const std::string &remote_url); void DoStop(); void Run(); void UpdateDatabaseInstance(shared_ptr context_db); // Watcher void Watch(); void StartWatcher(); void StopWatcher(); // Http handlers void HandleGetLocalEvents(const httplib::Request &req, httplib::Response &res); void HandleGetLocalToken(const httplib::Request &req, httplib::Response &res); void HandleGet(const httplib::Request &req, httplib::Response &res); void HandleInterrupt(const httplib::Request &req, httplib::Response &res); void DoHandleRun(const httplib::Request &req, httplib::Response &res, const httplib::ContentReader &content_reader); void HandleRun(const httplib::Request &req, httplib::Response &res, const httplib::ContentReader &content_reader); void HandleTokenize(const httplib::Request &req, httplib::Response &res, const httplib::ContentReader &content_reader); std::string ReadContent(const httplib::ContentReader &content_reader); // Http responses void SetResponseContent(httplib::Response &res, const MemoryStream &content); void SetResponseEmptyResult(httplib::Response &res); void SetResponseErrorResult(httplib::Response &res, const std::string &error); // Events void SendEvent(const std::string &message); void SendConnectedEvent(const std::string &token); void SendCatalogChangedEvent(); uint16_t local_port; std::string remote_url; weak_ptr ddb_instance; std::string user_agent; httplib::Server server; unique_ptr main_thread; unique_ptr watcher_thread; std::mutex watcher_mutex; std::condition_variable watcher_cv; std::atomic watcher_should_run; unique_ptr event_dispatcher; static unique_ptr server_instance; }; ; } // namespace ui } // namespace duckdb