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,
|
void HttpController::getStatus(const drogon::HttpRequestPtr &req,
|
||||||
std::function<void(const drogon::HttpResponsePtr &)> &&callback) {
|
std::function<void(const drogon::HttpResponsePtr &)> &&callback) {
|
||||||
auto resp = drogon::HttpResponse::newHttpResponse();
|
auto resp = drogon::HttpResponse::newHttpResponse();
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ public:
|
|||||||
ADD_METHOD_TO(HttpController::updateObject, "/update", {drogon::Put});
|
ADD_METHOD_TO(HttpController::updateObject, "/update", {drogon::Put});
|
||||||
ADD_METHOD_TO(HttpController::getMetadata, "/meta/{1}", {drogon::Get});
|
ADD_METHOD_TO(HttpController::getMetadata, "/meta/{1}", {drogon::Get});
|
||||||
ADD_METHOD_TO(HttpController::deleteObject, "/deleteobject", {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::getStatus, "/status", {drogon::Get});
|
||||||
ADD_METHOD_TO(HttpController::getObject, "/object/{1}", {drogon::Get});
|
ADD_METHOD_TO(HttpController::getObject, "/object/{1}", {drogon::Get});
|
||||||
ADD_METHOD_TO(HttpController::getRoot, "/", {drogon::Get});
|
ADD_METHOD_TO(HttpController::getRoot, "/", {drogon::Get});
|
||||||
@@ -54,6 +55,9 @@ public:
|
|||||||
void deleteObject(const drogon::HttpRequestPtr &req,
|
void deleteObject(const drogon::HttpRequestPtr &req,
|
||||||
std::function<void(const drogon::HttpResponsePtr &)> &&callback);
|
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,
|
void getStatus(const drogon::HttpRequestPtr &req,
|
||||||
std::function<void(const drogon::HttpResponsePtr &)> &&callback);
|
std::function<void(const drogon::HttpResponsePtr &)> &&callback);
|
||||||
|
|
||||||
|
|||||||
@@ -259,6 +259,34 @@ bool Database::list(std::vector<dbEntry>& entries) {
|
|||||||
return true;
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
sqlite3_finalize(stmt);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
bool Database::merge_existing_entry(const dbEntry& existing, const dbEntry& new_entry, dbEntry& merged) {
|
bool Database::merge_existing_entry(const dbEntry& existing, const dbEntry& new_entry, dbEntry& merged) {
|
||||||
// Merge label:tag pairs
|
// Merge label:tag pairs
|
||||||
std::set<std::string> merged_labeltags(existing.labeltags.begin(), existing.labeltags.end());
|
std::set<std::string> merged_labeltags(existing.labeltags.begin(), existing.labeltags.end());
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ class Database {
|
|||||||
bool remove_by_hash(const std::string& hash);
|
bool remove_by_hash(const std::string& hash);
|
||||||
bool get(const std::string& hash_or_labeltag, dbEntry& entry);
|
bool get(const std::string& hash_or_labeltag, dbEntry& entry);
|
||||||
bool list(std::vector<dbEntry>& entries);
|
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);
|
bool update_or_insert(const dbEntry& entry);
|
||||||
private:
|
private:
|
||||||
std::filesystem::path path_;
|
std::filesystem::path path_;
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
#include <chrono> // For seeding random number generator
|
#include <chrono> // For seeding random number generator
|
||||||
#include <vector> // For getAllKeys
|
#include <vector> // For getAllKeys
|
||||||
#include <string_view> // For litecask values
|
#include <string_view> // For litecask values
|
||||||
|
#include <set> // For handle_delete_old_objects
|
||||||
#include <stdexcept> // For std::runtime_error
|
#include <stdexcept> // For std::runtime_error
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
|
||||||
@@ -476,6 +477,94 @@ void Server::handle_delete_object(const drogon::HttpRequestPtr& req, std::functi
|
|||||||
callback(resp);
|
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) {
|
void Server::handle_exists(const drogon::HttpRequestPtr& req, std::function<void(const drogon::HttpResponsePtr &)>&& callback, const std::string& key) {
|
||||||
nlohmann::json response;
|
nlohmann::json response;
|
||||||
dbEntry entry;
|
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_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_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_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_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 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);
|
void add_cors_headers(const drogon::HttpRequestPtr& req, const drogon::HttpResponsePtr& res);
|
||||||
|
|||||||
Reference in New Issue
Block a user