Remove _ suffix to class members
This commit is contained in:
@@ -21,22 +21,22 @@ constexpr const char *EMPTY_SSE_MESSAGE = ":\r\r";
|
|||||||
constexpr idx_t EMPTY_SSE_MESSAGE_LENGTH = 3;
|
constexpr idx_t EMPTY_SSE_MESSAGE_LENGTH = 3;
|
||||||
|
|
||||||
bool EventDispatcher::WaitEvent(httplib::DataSink *sink) {
|
bool EventDispatcher::WaitEvent(httplib::DataSink *sink) {
|
||||||
std::unique_lock<std::mutex> lock(mutex_);
|
std::unique_lock<std::mutex> lock(mutex);
|
||||||
// Don't allow too many simultaneous waits, because each consumes a thread in
|
// Don't allow too many simultaneous waits, because each consumes a thread in
|
||||||
// the httplib thread pool, and also browsers limit the number of server-sent
|
// the httplib thread pool, and also browsers limit the number of server-sent
|
||||||
// event connections.
|
// event connections.
|
||||||
if (closed_ || wait_count_ >= MAX_EVENT_WAIT_COUNT) {
|
if (closed || wait_count >= MAX_EVENT_WAIT_COUNT) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
int target_id = next_id_;
|
int target_id = next_id;
|
||||||
wait_count_++;
|
wait_count++;
|
||||||
cv_.wait_for(lock, std::chrono::seconds(5));
|
cv.wait_for(lock, std::chrono::seconds(5));
|
||||||
wait_count_--;
|
wait_count--;
|
||||||
if (closed_) {
|
if (closed) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (current_id_ == target_id) {
|
if (current_id == target_id) {
|
||||||
sink->write(message_.data(), message_.size());
|
sink->write(message.data(), message.size());
|
||||||
} else {
|
} else {
|
||||||
// Our wait timer expired. Write an empty, no-op message.
|
// Our wait timer expired. Write an empty, no-op message.
|
||||||
// This enables detecting when the client is gone.
|
// This enables detecting when the client is gone.
|
||||||
@@ -45,82 +45,86 @@ bool EventDispatcher::WaitEvent(httplib::DataSink *sink) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void EventDispatcher::SendEvent(const std::string &message) {
|
void EventDispatcher::SendEvent(const std::string &_message) {
|
||||||
std::lock_guard<std::mutex> guard(mutex_);
|
std::lock_guard<std::mutex> guard(mutex);
|
||||||
if (closed_) {
|
if (closed) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
current_id_ = next_id_++;
|
current_id = next_id++;
|
||||||
message_ = message;
|
message = _message;
|
||||||
cv_.notify_all();
|
cv.notify_all();
|
||||||
}
|
}
|
||||||
|
|
||||||
void EventDispatcher::Close() {
|
void EventDispatcher::Close() {
|
||||||
std::lock_guard<std::mutex> guard(mutex_);
|
std::lock_guard<std::mutex> guard(mutex);
|
||||||
if (closed_) {
|
if (closed) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
current_id_ = next_id_++;
|
|
||||||
closed_ = true;
|
current_id = next_id++;
|
||||||
cv_.notify_all();
|
closed = true;
|
||||||
|
cv.notify_all();
|
||||||
}
|
}
|
||||||
|
|
||||||
unique_ptr<HttpServer> HttpServer::instance_;
|
unique_ptr<HttpServer> HttpServer::server_instance;
|
||||||
|
|
||||||
HttpServer *HttpServer::instance() {
|
HttpServer *HttpServer::instance() {
|
||||||
if (!instance_) {
|
if (!server_instance) {
|
||||||
instance_ = make_uniq<HttpServer>();
|
server_instance = make_uniq<HttpServer>();
|
||||||
std::atexit(HttpServer::StopInstance);
|
std::atexit(HttpServer::StopInstance);
|
||||||
}
|
}
|
||||||
return instance_.get();
|
return server_instance.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool HttpServer::Started() { return instance_ && instance_->thread_; }
|
bool HttpServer::Started() {
|
||||||
|
return server_instance && server_instance->main_thread;
|
||||||
|
}
|
||||||
|
|
||||||
void HttpServer::StopInstance() {
|
void HttpServer::StopInstance() {
|
||||||
if (instance_) {
|
if (server_instance) {
|
||||||
instance_->Stop();
|
server_instance->Stop();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool HttpServer::Start(const uint16_t local_port, const std::string &remote_url,
|
bool HttpServer::Start(const uint16_t _local_port,
|
||||||
const shared_ptr<DatabaseInstance> &ddb_instance) {
|
const std::string &_remote_url,
|
||||||
if (thread_) {
|
const shared_ptr<DatabaseInstance> &_ddb_instance) {
|
||||||
|
if (main_thread) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
local_port_ = local_port;
|
local_port = _local_port;
|
||||||
remote_url_ = remote_url;
|
remote_url = _remote_url;
|
||||||
ddb_instance_ = ddb_instance;
|
ddb_instance = _ddb_instance;
|
||||||
#ifndef UI_EXTENSION_GIT_SHA
|
#ifndef UI_EXTENSION_GIT_SHA
|
||||||
#error "UI_EXTENSION_GIT_SHA must be defined"
|
#error "UI_EXTENSION_GIT_SHA must be defined"
|
||||||
#endif
|
#endif
|
||||||
user_agent_ = StringUtil::Format("duckdb-ui/%s(%s)", UI_EXTENSION_GIT_SHA,
|
user_agent = StringUtil::Format("duckdb-ui/%s(%s)", UI_EXTENSION_GIT_SHA,
|
||||||
DuckDB::Platform());
|
DuckDB::Platform());
|
||||||
event_dispatcher_ = make_uniq<EventDispatcher>();
|
event_dispatcher = make_uniq<EventDispatcher>();
|
||||||
thread_ = make_uniq<std::thread>(&HttpServer::Run, this);
|
main_thread = make_uniq<std::thread>(&HttpServer::Run, this);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool HttpServer::Stop() {
|
bool HttpServer::Stop() {
|
||||||
if (!thread_) {
|
if (!main_thread) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
event_dispatcher_->Close();
|
event_dispatcher->Close();
|
||||||
server_.stop();
|
server.stop();
|
||||||
thread_->join();
|
main_thread->join();
|
||||||
thread_.reset();
|
main_thread.reset();
|
||||||
event_dispatcher_.reset();
|
event_dispatcher.reset();
|
||||||
connections_.clear();
|
connections.clear();
|
||||||
ddb_instance_.reset();
|
ddb_instance.reset();
|
||||||
remote_url_ = "";
|
remote_url = "";
|
||||||
local_port_ = 0;
|
local_port = 0;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint16_t HttpServer::LocalPort() { return local_port_; }
|
uint16_t HttpServer::LocalPort() { return local_port; }
|
||||||
|
|
||||||
void HttpServer::SendConnectedEvent(const std::string &token) {
|
void HttpServer::SendConnectedEvent(const std::string &token) {
|
||||||
SendEvent(StringUtil::Format("event: ConnectedEvent\ndata: %s\n\n", token));
|
SendEvent(StringUtil::Format("event: ConnectedEvent\ndata: %s\n\n", token));
|
||||||
@@ -131,45 +135,45 @@ void HttpServer::SendCatalogChangedEvent() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void HttpServer::SendEvent(const std::string &message) {
|
void HttpServer::SendEvent(const std::string &message) {
|
||||||
if (event_dispatcher_) {
|
if (event_dispatcher) {
|
||||||
event_dispatcher_->SendEvent(message);
|
event_dispatcher->SendEvent(message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void HttpServer::Run() {
|
void HttpServer::Run() {
|
||||||
server_.Get("/localEvents",
|
server.Get("/localEvents",
|
||||||
[&](const httplib::Request &req, httplib::Response &res) {
|
[&](const httplib::Request &req, httplib::Response &res) {
|
||||||
HandleGetLocalEvents(req, res);
|
HandleGetLocalEvents(req, res);
|
||||||
});
|
});
|
||||||
server_.Get("/localToken",
|
server.Get("/localToken",
|
||||||
[&](const httplib::Request &req, httplib::Response &res) {
|
[&](const httplib::Request &req, httplib::Response &res) {
|
||||||
HandleGetLocalToken(req, res);
|
HandleGetLocalToken(req, res);
|
||||||
});
|
});
|
||||||
server_.Get("/.*", [&](const httplib::Request &req, httplib::Response &res) {
|
server.Get("/.*", [&](const httplib::Request &req, httplib::Response &res) {
|
||||||
HandleGet(req, res);
|
HandleGet(req, res);
|
||||||
});
|
});
|
||||||
server_.Post("/ddb/interrupt",
|
server.Post("/ddb/interrupt",
|
||||||
[&](const httplib::Request &req, httplib::Response &res) {
|
[&](const httplib::Request &req, httplib::Response &res) {
|
||||||
HandleInterrupt(req, res);
|
HandleInterrupt(req, res);
|
||||||
});
|
});
|
||||||
server_.Post("/ddb/run",
|
server.Post("/ddb/run",
|
||||||
[&](const httplib::Request &req, httplib::Response &res,
|
[&](const httplib::Request &req, httplib::Response &res,
|
||||||
const httplib::ContentReader &content_reader) {
|
const httplib::ContentReader &content_reader) {
|
||||||
HandleRun(req, res, content_reader);
|
HandleRun(req, res, content_reader);
|
||||||
});
|
});
|
||||||
server_.Post("/ddb/tokenize",
|
server.Post("/ddb/tokenize",
|
||||||
[&](const httplib::Request &req, httplib::Response &res,
|
[&](const httplib::Request &req, httplib::Response &res,
|
||||||
const httplib::ContentReader &content_reader) {
|
const httplib::ContentReader &content_reader) {
|
||||||
HandleTokenize(req, res, content_reader);
|
HandleTokenize(req, res, content_reader);
|
||||||
});
|
});
|
||||||
server_.listen("localhost", local_port_);
|
server.listen("localhost", local_port);
|
||||||
}
|
}
|
||||||
|
|
||||||
void HttpServer::HandleGetLocalEvents(const httplib::Request &req,
|
void HttpServer::HandleGetLocalEvents(const httplib::Request &req,
|
||||||
httplib::Response &res) {
|
httplib::Response &res) {
|
||||||
res.set_chunked_content_provider(
|
res.set_chunked_content_provider(
|
||||||
"text/event-stream", [&](size_t /*offset*/, httplib::DataSink &sink) {
|
"text/event-stream", [&](size_t /*offset*/, httplib::DataSink &sink) {
|
||||||
if (event_dispatcher_->WaitEvent(&sink)) {
|
if (event_dispatcher->WaitEvent(&sink)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
sink.done();
|
sink.done();
|
||||||
@@ -179,13 +183,13 @@ void HttpServer::HandleGetLocalEvents(const httplib::Request &req,
|
|||||||
|
|
||||||
void HttpServer::HandleGetLocalToken(const httplib::Request &req,
|
void HttpServer::HandleGetLocalToken(const httplib::Request &req,
|
||||||
httplib::Response &res) {
|
httplib::Response &res) {
|
||||||
if (!ddb_instance_->ExtensionIsLoaded("motherduck")) {
|
if (!ddb_instance->ExtensionIsLoaded("motherduck")) {
|
||||||
res.set_content("", "text/plain"); // UI expects an empty response if the
|
res.set_content("", "text/plain"); // UI expects an empty response if the
|
||||||
// extension is not loaded
|
// extension is not loaded
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Connection connection(*ddb_instance_);
|
Connection connection(*ddb_instance);
|
||||||
auto query_res = connection.Query("CALL get_md_token()");
|
auto query_res = connection.Query("CALL get_md_token()");
|
||||||
if (query_res->HasError()) {
|
if (query_res->HasError()) {
|
||||||
res.status = 500;
|
res.status = 500;
|
||||||
@@ -204,7 +208,7 @@ void HttpServer::HandleGet(const httplib::Request &req,
|
|||||||
httplib::Response &res) {
|
httplib::Response &res) {
|
||||||
// Create HTTP client to remote URL
|
// Create HTTP client to remote URL
|
||||||
// TODO: Can this be created once and shared?
|
// TODO: Can this be created once and shared?
|
||||||
httplib::Client client(remote_url_);
|
httplib::Client client(remote_url);
|
||||||
client.set_keep_alive(true);
|
client.set_keep_alive(true);
|
||||||
|
|
||||||
// Provide a way to turn on or off server certificate verification, at least
|
// Provide a way to turn on or off server certificate verification, at least
|
||||||
@@ -218,7 +222,7 @@ void HttpServer::HandleGet(const httplib::Request &req,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// forward GET to remote URL
|
// forward GET to remote URL
|
||||||
auto result = client.Get(req.path, req.params, {{"User-Agent", user_agent_}});
|
auto result = client.Get(req.path, req.params, {{"User-Agent", user_agent}});
|
||||||
if (!result) {
|
if (!result) {
|
||||||
res.status = 500;
|
res.status = 500;
|
||||||
return;
|
return;
|
||||||
@@ -275,7 +279,7 @@ void HttpServer::DoHandleRun(const httplib::Request &req,
|
|||||||
// Set current database if optional header is provided.
|
// Set current database if optional header is provided.
|
||||||
if (!database_name.empty()) {
|
if (!database_name.empty()) {
|
||||||
connection->context->RunFunctionInTransaction([&] {
|
connection->context->RunFunctionInTransaction([&] {
|
||||||
ddb_instance_->GetDatabaseManager().SetDefaultDatabase(
|
ddb_instance->GetDatabaseManager().SetDefaultDatabase(
|
||||||
*connection->context, database_name);
|
*connection->context, database_name);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -395,10 +399,10 @@ HttpServer::FindConnection(const std::string &connection_name) {
|
|||||||
|
|
||||||
// Need to protect access to the connections map because this can be called
|
// Need to protect access to the connections map because this can be called
|
||||||
// from multiple threads.
|
// from multiple threads.
|
||||||
std::lock_guard<std::mutex> guard(connections_mutex_);
|
std::lock_guard<std::mutex> guard(connections_mutex);
|
||||||
|
|
||||||
auto result = connections_.find(connection_name);
|
auto result = connections.find(connection_name);
|
||||||
if (result != connections_.end()) {
|
if (result != connections.end()) {
|
||||||
return result->second;
|
return result->second;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -410,22 +414,22 @@ HttpServer::FindOrCreateConnection(const std::string &connection_name) {
|
|||||||
if (connection_name.empty()) {
|
if (connection_name.empty()) {
|
||||||
// If no connection name was provided, create and return a new connection
|
// If no connection name was provided, create and return a new connection
|
||||||
// but don't remember it.
|
// but don't remember it.
|
||||||
return make_shared_ptr<Connection>(*ddb_instance_);
|
return make_shared_ptr<Connection>(*ddb_instance);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Need to protect access to the connections map because this can be called
|
// Need to protect access to the connections map because this can be called
|
||||||
// from multiple threads.
|
// from multiple threads.
|
||||||
std::lock_guard<std::mutex> guard(connections_mutex_);
|
std::lock_guard<std::mutex> guard(connections_mutex);
|
||||||
|
|
||||||
// If an existing connection with the provided name was found, return it.
|
// If an existing connection with the provided name was found, return it.
|
||||||
auto result = connections_.find(connection_name);
|
auto result = connections.find(connection_name);
|
||||||
if (result != connections_.end()) {
|
if (result != connections.end()) {
|
||||||
return result->second;
|
return result->second;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Otherwise, create a new one, remember it, and return it.
|
// Otherwise, create a new one, remember it, and return it.
|
||||||
auto connection = make_shared_ptr<Connection>(*ddb_instance_);
|
auto connection = make_shared_ptr<Connection>(*ddb_instance);
|
||||||
connections_[connection_name] = connection;
|
connections[connection_name] = connection;
|
||||||
return connection;
|
return connection;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -25,13 +25,13 @@ public:
|
|||||||
void Close();
|
void Close();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::mutex mutex_;
|
std::mutex mutex;
|
||||||
std::condition_variable cv_;
|
std::condition_variable cv;
|
||||||
std::atomic_int next_id_{0};
|
std::atomic_int next_id{0};
|
||||||
std::atomic_int current_id_{-1};
|
std::atomic_int current_id{-1};
|
||||||
std::atomic_int wait_count_{0};
|
std::atomic_int wait_count{0};
|
||||||
std::string message_;
|
std::string message;
|
||||||
std::atomic_bool closed_{false};
|
std::atomic_bool closed{false};
|
||||||
};
|
};
|
||||||
|
|
||||||
class HttpServer {
|
class HttpServer {
|
||||||
@@ -70,17 +70,17 @@ private:
|
|||||||
void SetResponseEmptyResult(httplib::Response &res);
|
void SetResponseEmptyResult(httplib::Response &res);
|
||||||
void SetResponseErrorResult(httplib::Response &res, const std::string &error);
|
void SetResponseErrorResult(httplib::Response &res, const std::string &error);
|
||||||
|
|
||||||
uint16_t local_port_;
|
uint16_t local_port;
|
||||||
std::string remote_url_;
|
std::string remote_url;
|
||||||
shared_ptr<DatabaseInstance> ddb_instance_;
|
shared_ptr<DatabaseInstance> ddb_instance;
|
||||||
std::string user_agent_;
|
std::string user_agent;
|
||||||
httplib::Server server_;
|
httplib::Server server;
|
||||||
unique_ptr<std::thread> thread_;
|
unique_ptr<std::thread> main_thread;
|
||||||
std::mutex connections_mutex_;
|
std::mutex connections_mutex;
|
||||||
std::unordered_map<std::string, shared_ptr<Connection>> connections_;
|
std::unordered_map<std::string, shared_ptr<Connection>> connections;
|
||||||
unique_ptr<EventDispatcher> event_dispatcher_;
|
unique_ptr<EventDispatcher> event_dispatcher;
|
||||||
|
|
||||||
static unique_ptr<HttpServer> instance_;
|
static unique_ptr<HttpServer> server_instance;
|
||||||
};
|
};
|
||||||
;
|
;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user