cleanup method
This commit is contained in:
@@ -159,6 +159,23 @@ void HttpController::deleteObject(const drogon::HttpRequestPtr &req,
|
||||
}
|
||||
}
|
||||
|
||||
void HttpController::deleteOldObjects(const drogon::HttpRequestPtr &req,
|
||||
std::function<void(const drogon::HttpResponsePtr &)> &&callback) {
|
||||
auto server = Server::getInstance();
|
||||
if (server) {
|
||||
server->handle_delete_old_objects(req, std::move(callback));
|
||||
} else {
|
||||
auto resp = drogon::HttpResponse::newHttpResponse();
|
||||
resp->setStatusCode(drogon::k500InternalServerError);
|
||||
// Try to add security headers if server instance is available
|
||||
auto srv = Server::getInstance();
|
||||
if (srv) {
|
||||
srv->add_security_headers(resp);
|
||||
}
|
||||
callback(resp);
|
||||
}
|
||||
}
|
||||
|
||||
void HttpController::getStatus(const drogon::HttpRequestPtr &req,
|
||||
std::function<void(const drogon::HttpResponsePtr &)> &&callback) {
|
||||
auto resp = drogon::HttpResponse::newHttpResponse();
|
||||
|
||||
@@ -17,6 +17,7 @@ public:
|
||||
ADD_METHOD_TO(HttpController::updateObject, "/update", {drogon::Put});
|
||||
ADD_METHOD_TO(HttpController::getMetadata, "/meta/{1}", {drogon::Get});
|
||||
ADD_METHOD_TO(HttpController::deleteObject, "/deleteobject", {drogon::Get});
|
||||
ADD_METHOD_TO(HttpController::deleteOldObjects, "/deleteoldobjects", {drogon::Get});
|
||||
ADD_METHOD_TO(HttpController::getStatus, "/status", {drogon::Get});
|
||||
ADD_METHOD_TO(HttpController::getObject, "/object/{1}", {drogon::Get});
|
||||
ADD_METHOD_TO(HttpController::getRoot, "/", {drogon::Get});
|
||||
@@ -53,7 +54,10 @@ public:
|
||||
|
||||
void deleteObject(const drogon::HttpRequestPtr &req,
|
||||
std::function<void(const drogon::HttpResponsePtr &)> &&callback);
|
||||
|
||||
|
||||
void deleteOldObjects(const drogon::HttpRequestPtr &req,
|
||||
std::function<void(const drogon::HttpResponsePtr &)> &&callback);
|
||||
|
||||
void getStatus(const drogon::HttpRequestPtr &req,
|
||||
std::function<void(const drogon::HttpResponsePtr &)> &&callback);
|
||||
|
||||
|
||||
@@ -238,7 +238,7 @@ bool Database::get(const std::string& hash_or_labeltag, dbEntry& entry) {
|
||||
bool Database::list(std::vector<dbEntry>& entries) {
|
||||
std::string sql = "SELECT hash, labeltags, metadata FROM objects;";
|
||||
sqlite3_stmt* stmt;
|
||||
|
||||
|
||||
if (sqlite3_prepare_v2(db_, sql.c_str(), -1, &stmt, nullptr) != SQLITE_OK) {
|
||||
return false;
|
||||
}
|
||||
@@ -249,7 +249,35 @@ bool Database::list(std::vector<dbEntry>& entries) {
|
||||
entry.hash = reinterpret_cast<const char*>(sqlite3_column_text(stmt, 0));
|
||||
std::string labeltags_str = reinterpret_cast<const char*>(sqlite3_column_text(stmt, 1));
|
||||
std::string metadata_str = reinterpret_cast<const char*>(sqlite3_column_text(stmt, 2));
|
||||
|
||||
|
||||
entry.labeltags = nlohmann::json::parse(labeltags_str).get<std::vector<std::string>>();
|
||||
entry.metadata = nlohmann::json::parse(metadata_str);
|
||||
entries.push_back(entry);
|
||||
}
|
||||
|
||||
sqlite3_finalize(stmt);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Database::list_by_label(const std::string& label, std::vector<dbEntry>& entries) {
|
||||
// Find all entries that have at least one labeltag starting with "label:"
|
||||
std::string sql = "SELECT hash, labeltags, metadata FROM objects WHERE labeltags LIKE ?;";
|
||||
sqlite3_stmt* stmt;
|
||||
|
||||
if (sqlite3_prepare_v2(db_, sql.c_str(), -1, &stmt, nullptr) != SQLITE_OK) {
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string pattern = "%\"" + label + ":%";
|
||||
sqlite3_bind_text(stmt, 1, pattern.c_str(), -1, SQLITE_STATIC);
|
||||
|
||||
entries.clear();
|
||||
while (sqlite3_step(stmt) == SQLITE_ROW) {
|
||||
dbEntry entry;
|
||||
entry.hash = reinterpret_cast<const char*>(sqlite3_column_text(stmt, 0));
|
||||
std::string labeltags_str = reinterpret_cast<const char*>(sqlite3_column_text(stmt, 1));
|
||||
std::string metadata_str = reinterpret_cast<const char*>(sqlite3_column_text(stmt, 2));
|
||||
|
||||
entry.labeltags = nlohmann::json::parse(labeltags_str).get<std::vector<std::string>>();
|
||||
entry.metadata = nlohmann::json::parse(metadata_str);
|
||||
entries.push_back(entry);
|
||||
|
||||
@@ -25,6 +25,7 @@ class Database {
|
||||
bool remove_by_hash(const std::string& hash);
|
||||
bool get(const std::string& hash_or_labeltag, dbEntry& entry);
|
||||
bool list(std::vector<dbEntry>& entries);
|
||||
bool list_by_label(const std::string& label, std::vector<dbEntry>& entries);
|
||||
bool update_or_insert(const dbEntry& entry);
|
||||
private:
|
||||
std::filesystem::path path_;
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#include <chrono> // For seeding random number generator
|
||||
#include <vector> // For getAllKeys
|
||||
#include <string_view> // For litecask values
|
||||
#include <set> // For handle_delete_old_objects
|
||||
#include <stdexcept> // For std::runtime_error
|
||||
#include <sstream>
|
||||
|
||||
@@ -476,6 +477,94 @@ void Server::handle_delete_object(const drogon::HttpRequestPtr& req, std::functi
|
||||
callback(resp);
|
||||
}
|
||||
|
||||
void Server::handle_delete_old_objects(const drogon::HttpRequestPtr& req, std::function<void(const drogon::HttpResponsePtr &)>&& callback) {
|
||||
auto resp = drogon::HttpResponse::newHttpResponse();
|
||||
|
||||
std::map<std::string, std::string> params;
|
||||
if (!validate_write_request(req, resp, {"label"}, params)) {
|
||||
add_security_headers(resp);
|
||||
callback(resp);
|
||||
return;
|
||||
}
|
||||
|
||||
std::string label = params["label"];
|
||||
|
||||
// Get all entries for this label
|
||||
std::vector<dbEntry> entries;
|
||||
if (!db_->list_by_label(label, entries)) {
|
||||
resp->setStatusCode(drogon::k500InternalServerError);
|
||||
nlohmann::json response = {{"result", "error"}, {"error", "Failed to list objects for label: " + label}};
|
||||
resp->setBody(response.dump());
|
||||
resp->setContentTypeCode(drogon::CT_APPLICATION_JSON);
|
||||
add_security_headers(resp);
|
||||
callback(resp);
|
||||
return;
|
||||
}
|
||||
|
||||
if (entries.empty()) {
|
||||
nlohmann::json response = {{"result", "success"}, {"deleted", 0}, {"message", "No objects found for label: " + label}};
|
||||
resp->setBody(response.dump());
|
||||
resp->setContentTypeCode(drogon::CT_APPLICATION_JSON);
|
||||
add_security_headers(resp);
|
||||
callback(resp);
|
||||
return;
|
||||
}
|
||||
|
||||
// Find hashes that have at least one tag containing 'latest' for this label
|
||||
std::set<std::string> hashes_to_keep;
|
||||
for (const auto& entry : entries) {
|
||||
for (const auto& labeltag : entry.labeltags) {
|
||||
// Check if this labeltag belongs to our label and contains 'latest'
|
||||
if (labeltag.rfind(label + ":", 0) == 0) {
|
||||
std::string tag = labeltag.substr(label.length() + 1);
|
||||
if (tag.find("latest") != std::string::npos) {
|
||||
hashes_to_keep.insert(entry.hash);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Delete entries that don't have a 'latest' tag
|
||||
int deleted_count = 0;
|
||||
std::vector<std::string> errors;
|
||||
|
||||
for (const auto& entry : entries) {
|
||||
if (hashes_to_keep.find(entry.hash) != hashes_to_keep.end()) {
|
||||
continue; // Skip entries with 'latest' tags
|
||||
}
|
||||
|
||||
// Remove from database
|
||||
if (!db_->remove_by_hash(entry.hash)) {
|
||||
errors.push_back("Failed to remove database entry for hash: " + entry.hash);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Remove the file
|
||||
std::filesystem::path file_path = config_.object_store_path / entry.hash;
|
||||
if (std::filesystem::exists(file_path) && std::filesystem::is_regular_file(file_path)) {
|
||||
try {
|
||||
std::filesystem::remove(file_path);
|
||||
} catch (const std::filesystem::filesystem_error& e) {
|
||||
errors.push_back("Failed to delete file for hash " + entry.hash + ": " + e.what());
|
||||
}
|
||||
}
|
||||
|
||||
deleted_count++;
|
||||
}
|
||||
|
||||
nlohmann::json response;
|
||||
if (errors.empty()) {
|
||||
response = {{"result", "success"}, {"deleted", deleted_count}};
|
||||
} else {
|
||||
response = {{"result", "partial"}, {"deleted", deleted_count}, {"errors", errors}};
|
||||
}
|
||||
resp->setBody(response.dump());
|
||||
resp->setContentTypeCode(drogon::CT_APPLICATION_JSON);
|
||||
add_security_headers(resp);
|
||||
callback(resp);
|
||||
}
|
||||
|
||||
void Server::handle_exists(const drogon::HttpRequestPtr& req, std::function<void(const drogon::HttpResponsePtr &)>&& callback, const std::string& key) {
|
||||
nlohmann::json response;
|
||||
dbEntry entry;
|
||||
|
||||
@@ -47,6 +47,7 @@ public:
|
||||
void handle_get_directory(const drogon::HttpRequestPtr& req, std::function<void(const drogon::HttpResponsePtr &)>&& callback);
|
||||
void handle_get_metadata(const drogon::HttpRequestPtr& req, std::function<void(const drogon::HttpResponsePtr &)>&& callback, const std::string& key);
|
||||
void handle_delete_object(const drogon::HttpRequestPtr& req, std::function<void(const drogon::HttpResponsePtr &)>&& callback);
|
||||
void handle_delete_old_objects(const drogon::HttpRequestPtr& req, std::function<void(const drogon::HttpResponsePtr &)>&& callback);
|
||||
void handle_exists(const drogon::HttpRequestPtr& req, std::function<void(const drogon::HttpResponsePtr &)>&& callback, const std::string& key);
|
||||
void handle_cors_preflight(const drogon::HttpRequestPtr& req, std::function<void(const drogon::HttpResponsePtr &)>&& callback);
|
||||
void add_cors_headers(const drogon::HttpRequestPtr& req, const drogon::HttpResponsePtr& res);
|
||||
|
||||
Reference in New Issue
Block a user