From 4757f8e644090ee3d2cb5d1462ea62c2206bd94d Mon Sep 17 00:00:00 2001 From: amass <168062547@qq.com> Date: Mon, 5 Aug 2024 23:01:19 +0800 Subject: [PATCH] add artical rankings. --- Server/Application.cpp | 35 +++++++++++++++++++++++++- Server/Database/Database.cpp | 49 +++++++++++++++++++++++++++++++++--- Server/Database/Database.h | 1 + 3 files changed, 81 insertions(+), 4 deletions(-) diff --git a/Server/Application.cpp b/Server/Application.cpp index 57991ee..9785613 100644 --- a/Server/Application.cpp +++ b/Server/Application.cpp @@ -160,6 +160,40 @@ Application::Application(const std::string &path) session.reply(std::move(s)); }); + m_router->insert("/api/v1/most_viewed_urls", [this](HttpSession &session, const Request &request, + const boost::urls::matches &matches) { + using namespace boost::beast; + int size = 5; + std::error_code error; + if (!request.body().empty()) { + auto rootJson = boost::json::parse(request.body(), error); + if (error) { + LOG(info) << "<" << request.body() << "> parse json error: " << error.message(); + } else { + auto &root = rootJson.as_object(); + if (root.contains("size")) { + size = root.at("size").as_int64(); + } + } + } + + auto data = Amass::Singleton::instance()->mostViewedUrls(size); + boost::json::array reply; + for (auto &d : data) { + boost::json::object object; + object["url"] = d.url; + object["count"] = d.pageViewCount; + reply.push_back(std::move(object)); + } + http::response s{boost::beast::http::status::ok, request.version()}; + s.set(http::field::server, BOOST_BEAST_VERSION_STRING); + s.set(http::field::content_type, "application/json;charset=UTF-8"); + s.keep_alive(request.keep_alive()); + s.body() = boost::json::serialize(reply); + s.prepare_payload(); + session.reply(std::move(s)); + }); + m_ioContext = Amass::Singleton::instance(getThreads()); m_timer = std::make_shared(*m_ioContext->ioContext()); @@ -177,7 +211,6 @@ const Application::RequestHandler *Application::find(boost::urls::segments_encod boost::urls::matches_base &matches) const noexcept { const Application::RequestHandler *ret = nullptr; try { - LOG(info) << path << "cgdfc"; ret = m_router->find(path, matches); } catch (const std::exception &e) { boost::stacktrace::stacktrace trace = boost::stacktrace::stacktrace::from_current_exception(); diff --git a/Server/Database/Database.cpp b/Server/Database/Database.cpp index 15cf3c6..a9adaa3 100644 --- a/Server/Database/Database.cpp +++ b/Server/Database/Database.cpp @@ -109,11 +109,15 @@ void Database::setTaskFinished(int id, bool finished, uint64_t finishedTime) { void Database::updateVisitCount(const std::string &url, const std::string &visitorUuid, const std::string &userAgent, int64_t time) { sqlite3_stmt *stmt; + auto strippedUrl = url; + if (strippedUrl.size() > 1 && strippedUrl.back() == '/') { + strippedUrl.pop_back(); + } 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); } - sqlite3_bind_text(stmt, 1, url.c_str(), -1, SQLITE_STATIC); + sqlite3_bind_text(stmt, 1, strippedUrl.c_str(), -1, SQLITE_STATIC); sqlite3_bind_text(stmt, 2, visitorUuid.c_str(), -1, SQLITE_STATIC); int id = -1; int page_view_count = 0; @@ -142,7 +146,7 @@ void Database::updateVisitCount(const std::string &url, const std::string &visit 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, 1, strippedUrl.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); @@ -165,7 +169,7 @@ void Database::clearVisitRecord() { VisitAnalysis Database::siteVisitAnalysisData() { VisitAnalysis ret; - sqlite3_stmt *stmt; + sqlite3_stmt *stmt = nullptr; const char *sql = "SELECT COUNT(DISTINCT visitor_uuid) as unique_visitors, SUM(page_view_count) as " "total_page_views FROM visit_analysis"; if (sqlite3_prepare_v2(m_sqlite3, sql, -1, &stmt, nullptr) != SQLITE_OK) { @@ -182,6 +186,45 @@ VisitAnalysis Database::siteVisitAnalysisData() { return ret; } +std::list Database::mostViewedUrls(int size) { + std::vector filter = { + "/", + "/LoginPage", + "/我的笔记", + "/我的博客", + }; + const char *sql = "SELECT url, SUM(page_view_count) AS total_page_view_count " + "FROM visit_analysis " + "GROUP BY url " + "ORDER BY total_page_view_count DESC " + "LIMIT ?"; + sqlite3_stmt *stmt = nullptr; + std::list ret; + auto rc = sqlite3_prepare_v2(m_sqlite3, sql, -1, &stmt, nullptr); + if (rc != SQLITE_OK) { + LOG(error) << "Failed to prepare statement: " << sqlite3_errmsg(m_sqlite3); + return ret; + } + + sqlite3_bind_int(stmt, 1, size + filter.size()); + + // Execute the SQL statement and fetch the results + while ((rc = sqlite3_step(stmt)) == SQLITE_ROW) { + VisitAnalysis pv; + pv.url = reinterpret_cast(sqlite3_column_text(stmt, 0)); + if (std::find(filter.cbegin(), filter.cend(), pv.url) != filter.cend()) continue; + pv.pageViewCount = sqlite3_column_int(stmt, 1); + ret.push_back(pv); + } + + if (rc != SQLITE_DONE) { + LOG(error) << "Failed to execute statement: " << sqlite3_errmsg(m_sqlite3); + } + sqlite3_finalize(stmt); + + return ret; +} + VisitAnalysis Database::visitAnalysisData(const std::string &url) { VisitAnalysis ret; sqlite3_stmt *stmt; diff --git a/Server/Database/Database.h b/Server/Database/Database.h index e61766f..b8e9f72 100644 --- a/Server/Database/Database.h +++ b/Server/Database/Database.h @@ -32,6 +32,7 @@ public: void clearVisitRecord(); VisitAnalysis visitAnalysisData(const std::string &url); VisitAnalysis siteVisitAnalysisData(); + std::list mostViewedUrls(int size); HomeBox::Items homeBoxItems(); bool addHomeBoxItem(const std::string &name, const std::string &location, int cost);