From 2b45dad26ee73d9633d7eb2c4834a605f0a26bf8 Mon Sep 17 00:00:00 2001 From: amass <168062547@qq.com> Date: Wed, 31 Jul 2024 22:28:05 +0800 Subject: [PATCH] add extra info for analysis. --- Readme.md | 6 +++ Server/Application.cpp | 13 ++++-- Server/Database/Database.cpp | 86 +++++++++++++++++++----------------- Server/Database/Database.h | 3 +- UnitTest/DatabaseTest.cpp | 13 +++--- 5 files changed, 69 insertions(+), 52 deletions(-) diff --git a/Readme.md b/Readme.md index e5d8c29..0dd641d 100644 --- a/Readme.md +++ b/Readme.md @@ -9,8 +9,14 @@ | id | INTEGER | NOT NULL | | | url | TEXT | NOT NULL | | | visitor_uuid | TEXT | NOT NULL | | +| last_user_agent | TEXT | NOT NULL | | +| last_view_time | INTEGER | NOT NULL | | | page_view_count | INTEGER | NOT NULL | | +插入 url,visitor_uuid,last_user_agent ,last_view_time至表中,如果表中已存在url,visitor_uuid的item,则更新last_user_agent ,last_view_time,并将page_view_count加1,否则创建新的item,并将page_view_count赋值为1 + + + ### 任务清单 diff --git a/Server/Application.cpp b/Server/Application.cpp index a45aedb..57991ee 100644 --- a/Server/Application.cpp +++ b/Server/Application.cpp @@ -119,7 +119,7 @@ Application::Application(const std::string &path) session.reply( ServiceLogic::make_200(request, "notify successed.\n", "text/html")); }); - + // clang-format on m_router->insert("/api/v1/visit_analysis", [this](HttpSession &session, const Request &request, const boost::urls::matches &matches) { using namespace boost::beast; @@ -127,15 +127,21 @@ Application::Application(const std::string &path) auto &root = rootJson.as_object(); std::string url; std::string visitorUuid; + std::string userAgent; if (root.contains("url")) { url = root["url"].as_string(); } if (root.contains("visitor_uuid")) { visitorUuid = root["visitor_uuid"].as_string(); } + if (root.contains("user_agent")) { + userAgent = root["user_agent"].as_string(); + } auto database = Amass::Singleton::instance(); - database->updateVisitCount(url, visitorUuid); + auto now = std::chrono::system_clock::now(); + std::time_t now_time = std::chrono::system_clock::to_time_t(now); + database->updateVisitCount(url, visitorUuid, userAgent, now_time); auto data = database->visitAnalysisData(std::string(url)); auto total = database->siteVisitAnalysisData(); @@ -153,8 +159,7 @@ Application::Application(const std::string &path) s.prepare_payload(); session.reply(std::move(s)); }); - // clang-format on - + m_ioContext = Amass::Singleton::instance(getThreads()); m_timer = std::make_shared(*m_ioContext->ioContext()); diff --git a/Server/Database/Database.cpp b/Server/Database/Database.cpp index b320baf..15cf3c6 100644 --- a/Server/Database/Database.cpp +++ b/Server/Database/Database.cpp @@ -106,48 +106,51 @@ void Database::setTaskFinished(int id, bool finished, uint64_t finishedTime) { } } -void Database::updateVisitCount(const std::string &url, const std::string &visitorUuid) { - sqlite3_stmt *stmt = nullptr; - const char *sql_select = "SELECT page_view_count FROM visit_analysis WHERE url = ? AND visitor_uuid = ?"; - if (sqlite3_prepare_v2(m_sqlite3, sql_select, -1, &stmt, 0) != SQLITE_OK) { +void Database::updateVisitCount(const std::string &url, const std::string &visitorUuid, const std::string &userAgent, + int64_t time) { + sqlite3_stmt *stmt; + const char *query = "SELECT id, page_view_count FROM visit_analysis WHERE url = ? AND visitor_uuid = ?"; + if (sqlite3_prepare_v2(m_sqlite3, query, -1, &stmt, 0) != SQLITE_OK) { LOG(error) << "Failed to prepare statement: " << sqlite3_errmsg(m_sqlite3); - return; } sqlite3_bind_text(stmt, 1, url.c_str(), -1, SQLITE_STATIC); sqlite3_bind_text(stmt, 2, visitorUuid.c_str(), -1, SQLITE_STATIC); - int rc = sqlite3_step(stmt); - if (rc == SQLITE_ROW) { // 记录存在,执行UPDATE语句 - sqlite3_finalize(stmt); // 释放SELECT语句的资源 - const char *sql_update = - "UPDATE visit_analysis SET page_view_count = page_view_count + 1 WHERE url = ? AND visitor_uuid = ?"; - if (sqlite3_prepare_v2(m_sqlite3, sql_update, -1, &stmt, 0) != SQLITE_OK) { - LOG(error) << "Failed to prepare statement: " << sqlite3_errmsg(m_sqlite3); - return; - } - sqlite3_bind_text(stmt, 1, url.c_str(), -1, SQLITE_STATIC); - sqlite3_bind_text(stmt, 2, visitorUuid.c_str(), -1, SQLITE_STATIC); - if (sqlite3_step(stmt) != SQLITE_DONE) { - LOG(error) << "Failed to execute statement: " << sqlite3_errmsg(m_sqlite3); - sqlite3_finalize(stmt); - return; - } - } else { // 记录不存在,执行INSERT语句 - sqlite3_finalize(stmt); // 释放SELECT语句的资源 - const char *sql_insert = "INSERT INTO visit_analysis (url, visitor_uuid, page_view_count) VALUES (?, ?, 1)"; - if (sqlite3_prepare_v2(m_sqlite3, sql_insert, -1, &stmt, 0) != SQLITE_OK) { - LOG(error) << "Failed to prepare statement: " << sqlite3_errmsg(m_sqlite3); - return; - } - sqlite3_bind_text(stmt, 1, url.c_str(), -1, SQLITE_STATIC); - sqlite3_bind_text(stmt, 2, visitorUuid.c_str(), -1, SQLITE_STATIC); - if (sqlite3_step(stmt) != SQLITE_DONE) { // 执行INSERT语句 - LOG(error) << "Failed to execute statement: " << sqlite3_errmsg(m_sqlite3); - sqlite3_finalize(stmt); - return; - } + int id = -1; + int page_view_count = 0; + if (sqlite3_step(stmt) == SQLITE_ROW) { + id = sqlite3_column_int(stmt, 0); + page_view_count = sqlite3_column_int(stmt, 1); } - // 释放语句资源 sqlite3_finalize(stmt); + if (id != -1) { // 更新记录 + const char *updateQuery = + "UPDATE visit_analysis SET last_user_agent = ?, last_view_time = ?, page_view_count = ? WHERE id = ?"; + if (sqlite3_prepare_v2(m_sqlite3, updateQuery, -1, &stmt, 0) != SQLITE_OK) { + LOG(error) << "Failed to prepare update statement: " << sqlite3_errmsg(m_sqlite3); + } + sqlite3_bind_text(stmt, 1, userAgent.c_str(), -1, SQLITE_STATIC); + sqlite3_bind_int64(stmt, 2, time); + sqlite3_bind_int(stmt, 3, page_view_count + 1); + sqlite3_bind_int(stmt, 4, id); + if (sqlite3_step(stmt) != SQLITE_DONE) { + LOG(error) << "Failed to update record: " << sqlite3_errmsg(m_sqlite3); + } + sqlite3_finalize(stmt); + } else { // 插入新记录 + const char *insertQuery = "INSERT INTO visit_analysis (url, visitor_uuid, last_user_agent, last_view_time, " + "page_view_count) VALUES (?, ?, ?, ?, 1)"; + if (sqlite3_prepare_v2(m_sqlite3, insertQuery, -1, &stmt, 0) != SQLITE_OK) { + LOG(error) << "Failed to prepare insert statement: " << sqlite3_errmsg(m_sqlite3); + } + sqlite3_bind_text(stmt, 1, url.c_str(), -1, SQLITE_STATIC); + sqlite3_bind_text(stmt, 2, visitorUuid.c_str(), -1, SQLITE_STATIC); + sqlite3_bind_text(stmt, 3, userAgent.c_str(), -1, SQLITE_STATIC); + sqlite3_bind_int64(stmt, 4, time); + if (sqlite3_step(stmt) != SQLITE_DONE) { + LOG(error) << "Failed to insert record: " << sqlite3_errmsg(m_sqlite3) << std::endl; + } + sqlite3_finalize(stmt); + } } void Database::clearVisitRecord() { @@ -261,16 +264,17 @@ void Database::initialize() { } char *message = nullptr; - const char *sql_create_visit_analysis = R"( + sql = R"( CREATE TABLE IF NOT EXISTS visit_analysis ( - id INTEGER NOT NULL, + id INTEGER PRIMARY KEY AUTOINCREMENT, url TEXT NOT NULL, visitor_uuid TEXT NOT NULL, - page_view_count INTEGER NOT NULL, - PRIMARY KEY (id) + last_user_agent TEXT NOT NULL, + last_view_time INTEGER NOT NULL, + page_view_count INTEGER NOT NULL ); )"; - result = sqlite3_exec(m_sqlite3, sql_create_visit_analysis, 0, 0, &message); + result = sqlite3_exec(m_sqlite3, sql, 0, 0, &message); if (result != SQLITE_OK) { LOG(error) << "Failed to create table: " << message << std::endl; sqlite3_free(message); diff --git a/Server/Database/Database.h b/Server/Database/Database.h index 96d1ae0..e61766f 100644 --- a/Server/Database/Database.h +++ b/Server/Database/Database.h @@ -27,7 +27,8 @@ public: bool removeTask(int id); void setTaskFinished(int id, bool finished, uint64_t finishedTime); - void updateVisitCount(const std::string &url, const std::string &visitorUuid); + void updateVisitCount(const std::string &url, const std::string &visitorUuid, const std::string &userAgent, + int64_t time); void clearVisitRecord(); VisitAnalysis visitAnalysisData(const std::string &url); VisitAnalysis siteVisitAnalysisData(); diff --git a/UnitTest/DatabaseTest.cpp b/UnitTest/DatabaseTest.cpp index 666ecf4..44de5df 100644 --- a/UnitTest/DatabaseTest.cpp +++ b/UnitTest/DatabaseTest.cpp @@ -21,11 +21,12 @@ BOOST_AUTO_TEST_CASE(DatabaseTest) { auto items = database.homeBoxItems(); BOOST_CHECK_EQUAL(items.size(), 1); - auto now = duration_cast(std::chrono::system_clock::now().time_since_epoch()).count(); - database.setTaskFinished(1, true, now); + auto now = std::chrono::system_clock::now(); + std::time_t now_time = std::chrono::system_clock::to_time_t(now); + database.setTaskFinished(1, true, now_time); - database.updateVisitCount("/note", "uuid_123"); - database.updateVisitCount("/note/1", "uuid_1232"); - database.updateVisitCount("/note", "uuid_123"); - database.updateVisitCount("/note", "uuid_1234"); + database.updateVisitCount("/note", "uuid_123", "chrome", now_time); + database.updateVisitCount("/note/1", "uuid_1232", "chrome", now_time); + database.updateVisitCount("/note", "uuid_123", "chrome", now_time); + database.updateVisitCount("/note", "uuid_1234", "chrome", now_time); } \ No newline at end of file