477bcd00f0
- CMakeLists.txt - agent_protocol.cpp - agent_protocol.h - app.md - appicon.ico - hosts_db.cpp - hosts_db.h - http_client.cpp - http_client.h - main.cpp - ... Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
103 lines
3.6 KiB
C++
103 lines
3.6 KiB
C++
#include "hosts_db.h"
|
|
#include <sqlite3.h>
|
|
#include <cstring>
|
|
|
|
namespace pex {
|
|
|
|
static const char* k_schema = R"SQL(
|
|
CREATE TABLE IF NOT EXISTS hosts (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
name TEXT NOT NULL UNIQUE,
|
|
url TEXT NOT NULL,
|
|
token TEXT NOT NULL DEFAULT '',
|
|
os TEXT NOT NULL DEFAULT '',
|
|
last_seen_unix INTEGER NOT NULL DEFAULT 0,
|
|
is_local INTEGER NOT NULL DEFAULT 0
|
|
);
|
|
)SQL";
|
|
|
|
HostsDb::HostsDb() = default;
|
|
HostsDb::~HostsDb() { close(); }
|
|
|
|
bool HostsDb::open(const std::string& path) {
|
|
if (sqlite3_open(path.c_str(), &db_) != SQLITE_OK) {
|
|
db_ = nullptr;
|
|
return false;
|
|
}
|
|
char* err = nullptr;
|
|
if (sqlite3_exec(db_, k_schema, nullptr, nullptr, &err) != SQLITE_OK) {
|
|
sqlite3_free(err);
|
|
close();
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
void HostsDb::close() {
|
|
if (db_) { sqlite3_close(db_); db_ = nullptr; }
|
|
}
|
|
|
|
std::vector<Host> HostsDb::list() {
|
|
std::vector<Host> out;
|
|
if (!db_) return out;
|
|
const char* sql = "SELECT id, name, url, token, os, last_seen_unix, is_local FROM hosts ORDER BY name";
|
|
sqlite3_stmt* st = nullptr;
|
|
if (sqlite3_prepare_v2(db_, sql, -1, &st, nullptr) != SQLITE_OK) return out;
|
|
while (sqlite3_step(st) == SQLITE_ROW) {
|
|
Host h;
|
|
h.id = sqlite3_column_int64(st, 0);
|
|
h.name = reinterpret_cast<const char*>(sqlite3_column_text(st, 1));
|
|
h.url = reinterpret_cast<const char*>(sqlite3_column_text(st, 2));
|
|
h.token = reinterpret_cast<const char*>(sqlite3_column_text(st, 3));
|
|
h.os = reinterpret_cast<const char*>(sqlite3_column_text(st, 4));
|
|
h.last_seen_unix = sqlite3_column_int64(st, 5);
|
|
h.is_local = sqlite3_column_int(st, 6) != 0;
|
|
out.push_back(std::move(h));
|
|
}
|
|
sqlite3_finalize(st);
|
|
return out;
|
|
}
|
|
|
|
int64_t HostsDb::upsert(const Host& h) {
|
|
if (!db_) return -1;
|
|
const char* sql =
|
|
"INSERT INTO hosts(name,url,token,os,last_seen_unix,is_local) VALUES(?,?,?,?,?,?) "
|
|
"ON CONFLICT(name) DO UPDATE SET url=excluded.url, token=excluded.token, "
|
|
"os=excluded.os, last_seen_unix=excluded.last_seen_unix, is_local=excluded.is_local";
|
|
sqlite3_stmt* st = nullptr;
|
|
if (sqlite3_prepare_v2(db_, sql, -1, &st, nullptr) != SQLITE_OK) return -1;
|
|
sqlite3_bind_text(st, 1, h.name.c_str(), -1, SQLITE_TRANSIENT);
|
|
sqlite3_bind_text(st, 2, h.url.c_str(), -1, SQLITE_TRANSIENT);
|
|
sqlite3_bind_text(st, 3, h.token.c_str(), -1, SQLITE_TRANSIENT);
|
|
sqlite3_bind_text(st, 4, h.os.c_str(), -1, SQLITE_TRANSIENT);
|
|
sqlite3_bind_int64(st, 5, h.last_seen_unix);
|
|
sqlite3_bind_int(st, 6, h.is_local ? 1 : 0);
|
|
int rc = sqlite3_step(st);
|
|
sqlite3_finalize(st);
|
|
if (rc != SQLITE_DONE) return -1;
|
|
return sqlite3_last_insert_rowid(db_);
|
|
}
|
|
|
|
bool HostsDb::remove(int64_t id) {
|
|
if (!db_) return false;
|
|
sqlite3_stmt* st = nullptr;
|
|
if (sqlite3_prepare_v2(db_, "DELETE FROM hosts WHERE id=?", -1, &st, nullptr) != SQLITE_OK) return false;
|
|
sqlite3_bind_int64(st, 1, id);
|
|
bool ok = sqlite3_step(st) == SQLITE_DONE;
|
|
sqlite3_finalize(st);
|
|
return ok;
|
|
}
|
|
|
|
bool HostsDb::touch_last_seen(int64_t id, int64_t unix_ts) {
|
|
if (!db_) return false;
|
|
sqlite3_stmt* st = nullptr;
|
|
if (sqlite3_prepare_v2(db_, "UPDATE hosts SET last_seen_unix=? WHERE id=?", -1, &st, nullptr) != SQLITE_OK) return false;
|
|
sqlite3_bind_int64(st, 1, unix_ts);
|
|
sqlite3_bind_int64(st, 2, id);
|
|
bool ok = sqlite3_step(st) == SQLITE_DONE;
|
|
sqlite3_finalize(st);
|
|
return ok;
|
|
}
|
|
|
|
} // namespace pex
|