From f726d015ae026aaf712548bf66084e2601c64dc7 Mon Sep 17 00:00:00 2001 From: GuanYuankai Date: Fri, 17 Oct 2025 10:01:15 +0800 Subject: [PATCH] =?UTF-8?q?=E6=95=B0=E6=8D=AE=E5=BA=93=E5=AD=98=E5=82=A8?= =?UTF-8?q?=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/dataStorage/data_storage.cc | 151 ++++++++++++++++++++++++++++++++ src/dataStorage/data_storage.h | 46 ++++++++++ 2 files changed, 197 insertions(+) create mode 100644 src/dataStorage/data_storage.cc create mode 100644 src/dataStorage/data_storage.h diff --git a/src/dataStorage/data_storage.cc b/src/dataStorage/data_storage.cc new file mode 100644 index 0000000..18e395f --- /dev/null +++ b/src/dataStorage/data_storage.cc @@ -0,0 +1,151 @@ +#include "data_storage.h" +#include +#include +#include +#include +// 使用 Pimpl Idiom 来隐藏 SQLite 细节 +// struct DataStorage::SQLiteDB { +// sqlite3* db_handle = nullptr; +// // 用于自动执行 finalize 的语句句柄 +// std::unique_ptr stmt_guard{nullptr, sqlite3_finalize}; +// }; + +// 获取单例实例 +DataStorage& DataStorage::getInstance() { + static DataStorage instance; + return instance; +} + +DataStorage::~DataStorage() { + if (db_ && db_->db_handle) { + sqlite3_close(db_->db_handle); + std::cout << "Database connection closed." << std::endl; + } +} + +bool DataStorage::initialize(const std::string& db_path) { + std::lock_guard lock(mutex_); + if (db_ && db_->db_handle) { + return true; // 已经初始化过 + } + + db_ = std::make_unique(); + + int rc = sqlite3_open(db_path.c_str(), &db_->db_handle); + if (rc != SQLITE_OK) { + std::cerr << "Cannot open database: " << sqlite3_errmsg(db_->db_handle) << std::endl; + return false; + } + + // 创建表 + if (!createTables()) { + sqlite3_close(db_->db_handle); + db_->db_handle = nullptr; + return false; + } + + std::cout << "Database initialized successfully at: " << db_path << std::endl; + return true; +} + +bool DataStorage::createTables() { + const char* create_raw_table_sql = + "CREATE TABLE IF NOT EXISTS raw_data (" + "id INTEGER PRIMARY KEY AUTOINCREMENT, " + "device_id TEXT NOT NULL, " + "received_at_ms INTEGER NOT NULL, " + "raw_data BLOB NOT NULL, " + "protocol_type TEXT);"; + + const char* create_processed_table_sql = + "CREATE TABLE IF NOT EXISTS processed_data (" + "id INTEGER PRIMARY KEY AUTOINCREMENT, " + "device_id TEXT NOT NULL, " + "timestamp_ms INTEGER NOT NULL, " + "data_json TEXT NOT NULL, " + "created_at_ms INTEGER DEFAULT (strftime('%s', 'now') * 1000));"; + + char* errMsg = nullptr; + int rc; + + rc = sqlite3_exec(db_->db_handle, create_raw_table_sql, nullptr, nullptr, &errMsg); + if (rc != SQLITE_OK) { + std::cerr << "SQL error creating raw_data table: " << errMsg << std::endl; + sqlite3_free(errMsg); + return false; + } + + rc = sqlite3_exec(db_->db_handle, create_processed_table_sql, nullptr, nullptr, &errMsg); + if (rc != SQLITE_OK) { + std::cerr << "SQL error creating processed_data table: " << errMsg << std::endl; + sqlite3_free(errMsg); + return false; + } + + // 为 device_id 和 timestamp_ms 创建索引,加速查询 + const char* create_processed_index_sql = "CREATE INDEX IF NOT EXISTS idx_device_timestamp ON processed_data(device_id, timestamp_ms);"; + rc = sqlite3_exec(db_->db_handle, create_processed_index_sql, nullptr, nullptr, &errMsg); + if (rc != SQLITE_OK) { + std::cerr << "SQL error creating index: " << errMsg << std::endl; + sqlite3_free(errMsg); + return false; // 即使索引创建失败,表也成功创建了,可以酌情处理 + } + + return true; +} + +bool DataStorage::storeRawData(const std::string& device_id, const std::string& raw_data, const std::string& protocol_type) { + std::lock_guard lock(mutex_); + if (!db_ || !db_->db_handle) { + std::cerr << "Database not initialized." << std::endl; + return false; + } + const char* sql = "INSERT INTO raw_data (device_id, received_at_ms, raw_data, protocol_type) VALUES (?, ?, ?, ?);"; + sqlite3_stmt* stmt; + int rc = sqlite3_prepare_v2(db_->db_handle, sql, -1, &stmt, nullptr); + if (rc != SQLITE_OK) { + std::cerr << "Failed to prepare statement for raw_data: " << sqlite3_errmsg(db_->db_handle) << std::endl; + return false; + } + + // **重要**:这里的 stmt_guard 也需要修正 + // 你之前的代码里是 std::unique_ptr,这也是错误的 + // 应该是 sqlite3_stmt* + std::unique_ptr stmt_guard(stmt, sqlite3_finalize); + sqlite3_bind_text(stmt, 1, device_id.c_str(), -1, SQLITE_STATIC); + sqlite3_bind_int64(stmt, 2, std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count()); + sqlite3_bind_blob(stmt, 3, raw_data.c_str(), raw_data.size(), SQLITE_STATIC); + sqlite3_bind_text(stmt, 4, protocol_type.c_str(), -1, SQLITE_STATIC); + rc = sqlite3_step(stmt); + if (rc != SQLITE_DONE) { + std::cerr << "Failed to execute statement for raw_data: " << sqlite3_errmsg(db_->db_handle) << std::endl; + return false; + } + return true; +} + +bool DataStorage::storeProcessedData(const UnifiedData& data) { + std::lock_guard lock(mutex_); + if (!db_ || !db_->db_handle) { + std::cerr << "Database not initialized." << std::endl; + return false; + } + const char* sql = "INSERT INTO processed_data (device_id, timestamp_ms, data_json) VALUES (?, ?, ?);"; + sqlite3_stmt* stmt; + int rc = sqlite3_prepare_v2(db_->db_handle, sql, -1, &stmt, nullptr); + if (rc != SQLITE_OK) { + std::cerr << "Failed to prepare statement for processed_data: " << sqlite3_errmsg(db_->db_handle) << std::endl; + return false; + } + // **重要**:这里的 stmt_guard 也需要修正 + std::unique_ptr stmt_guard(stmt, sqlite3_finalize); + sqlite3_bind_text(stmt, 1, data.device_id.c_str(), -1, SQLITE_STATIC); + sqlite3_bind_int64(stmt, 2, data.timestamp_ms); + sqlite3_bind_text(stmt, 3, data.data_json.c_str(), -1, SQLITE_STATIC); + rc = sqlite3_step(stmt); + if (rc != SQLITE_DONE) { + std::cerr << "Failed to execute statement for processed_data: " << sqlite3_errmsg(db_->db_handle) << std::endl; + return false; + } + return true; +} \ No newline at end of file diff --git a/src/dataStorage/data_storage.h b/src/dataStorage/data_storage.h new file mode 100644 index 0000000..4f9585d --- /dev/null +++ b/src/dataStorage/data_storage.h @@ -0,0 +1,46 @@ +// /app/src/dataStorage/data_storage.h +#ifndef DATA_STORAGE_H +#define DATA_STORAGE_H + +#include +#include +#include +#include +#include // SQLite 的头文件 + +// 包含 UnifiedData 的定义,并解决重定义问题 +// 如果 unified_data.h 在 /app/src/protocol/ 目录下 +#include "protocol/iprotocol_adapter.h" +// 如果 unified_data.h 在 /app/src/ 目录下 +// #include "../unified_data.h" + + +class DataStorage { +public: + static DataStorage& getInstance(); + DataStorage(const DataStorage&) = delete; + DataStorage& operator=(const DataStorage&) = delete; + + bool initialize(const std::string& db_path); + bool storeRawData(const std::string& device_id, const std::string& raw_data, const std::string& protocol_type = ""); + bool storeProcessedData(const UnifiedData& data); + +private: + DataStorage() = default; + ~DataStorage(); + + // SQLite 的实现细节,对外隐藏 + struct SQLiteDB { + sqlite3* db_handle = nullptr; + // 正确的 unique_ptr 定义:管理 sqlite3_stmt*,删除器是 sqlite3_finalize + std::unique_ptr stmt_guard{nullptr, sqlite3_finalize}; + }; + + // 使用 Pimpl 指针 + std::unique_ptr db_; + std::mutex mutex_; + + bool createTables(); +}; + +#endif // DATA_STORAGE_H