diff --git a/README.md b/README.md index 4c1d4e5..c6cb1d0 100644 --- a/README.md +++ b/README.md @@ -147,7 +147,7 @@ curl --cacert /var/lib/crossdesk/certs/api.crossdesk.cn_root.crt \ } ``` -- `online_device_count`:当前在线设备数,不包含临时 `web-*` 客户端 +- `online_device_count`:当前在线设备数,不包含临时 `web-*` 客户端和 `C-*` 分身客户端 - `online_web_client_count`:当前在线 Web 客户端数,仅统计临时 `web-*` 客户端 - `active_connection_count`:当前处于连接中的会话数,按已加入传输的客户端连接数统计 - 响应已带 `Access-Control-Allow-Origin: *`,可直接被网页端 `fetch` 调用 diff --git a/README_EN.md b/README_EN.md index 47b7f5c..c3c38f3 100644 --- a/README_EN.md +++ b/README_EN.md @@ -146,7 +146,7 @@ The `/api/stats` path is also supported. Example response: } ``` -- `online_device_count`: Number of online devices, excluding temporary `web-*` clients +- `online_device_count`: Number of online devices, excluding temporary `web-*` clients and `C-*` clone clients - `online_web_client_count`: Number of online web clients, counting only temporary `web-*` clients - `active_connection_count`: Number of active in-progress connections, counted by joined guest connections in transmissions - The response includes `Access-Control-Allow-Origin: *`, so it can be called directly from browser `fetch` diff --git a/src/device_db_manager/device_db_manager.cpp b/src/device_db_manager/device_db_manager.cpp index f764a29..ac2ce7d 100644 --- a/src/device_db_manager/device_db_manager.cpp +++ b/src/device_db_manager/device_db_manager.cpp @@ -502,7 +502,9 @@ int DeviceDBManager::GetOnlineDeviceCount() { const char* sql = "SELECT COUNT(*) FROM device_presence " - "WHERE online = 1 AND device_id NOT LIKE 'web-%';"; + "WHERE online = 1 " + "AND device_id NOT LIKE 'web-%' " + "AND device_id NOT LIKE 'C-%';"; sqlite3_stmt* stmt = nullptr; if (sqlite3_prepare_v2(db_, sql, -1, &stmt, nullptr) != SQLITE_OK) { diff --git a/src/presence_manager.cpp b/src/presence_manager.cpp index 3a4ced9..cb8642d 100644 --- a/src/presence_manager.cpp +++ b/src/presence_manager.cpp @@ -10,8 +10,12 @@ bool IsWebClient(const std::string& device_id) { return device_id.rfind("web-", 0) == 0; } +bool IsCloneClient(const std::string& device_id) { + return device_id.rfind("C-", 0) == 0; +} + bool ShouldTrackOnlineDevice(const std::string& device_id) { - return !IsWebClient(device_id); + return !IsWebClient(device_id) && !IsCloneClient(device_id); } } // namespace @@ -23,7 +27,7 @@ void PresenceManager::OnLogin(const std::string& user_id, std::lock_guard lock(online_devices_mutex_); if (ShouldTrackOnlineDevice(device_id)) { online_devices_.insert(device_id); - } else { + } else if (IsWebClient(device_id)) { online_web_clients_.insert(device_id); } } @@ -39,7 +43,7 @@ void PresenceManager::OnLogout(const std::string& device_id) { std::lock_guard lock(online_devices_mutex_); if (ShouldTrackOnlineDevice(device_id)) { online_devices_.erase(device_id); - } else { + } else if (IsWebClient(device_id)) { online_web_clients_.erase(device_id); } } diff --git a/tests/presence_manager_test.cpp b/tests/presence_manager_test.cpp index 0dad16f..aa37252 100644 --- a/tests/presence_manager_test.cpp +++ b/tests/presence_manager_test.cpp @@ -1,30 +1,75 @@ #include "presence_manager.h" +#include +#include +#include +#include + +#include "device_db_manager.h" + int main() { PresenceManager presence; websocketpp::connection_hdl hdl; int failures = 0; - auto expect = [&failures](bool condition) { + auto expect = [&failures](bool condition, const std::string& message) { if (!condition) { + std::cerr << "FAIL: " << message << std::endl; ++failures; } }; - expect(presence.GetOnlineDeviceCount() == 0); - expect(presence.GetOnlineWebClientCount() == 0); + expect(presence.GetOnlineDeviceCount() == 0, + "initial online device count is zero"); + expect(presence.GetOnlineWebClientCount() == 0, + "initial online web client count is zero"); presence.OnLogin("device-1", "device-1", hdl); - expect(presence.GetOnlineDeviceCount() == 1); - expect(presence.GetOnlineWebClientCount() == 0); + expect(presence.GetOnlineDeviceCount() == 1, + "regular device increments online device count"); + expect(presence.GetOnlineWebClientCount() == 0, + "regular device does not increment web client count"); presence.OnLogin("web-1", "web-1", hdl); - expect(presence.GetOnlineDeviceCount() == 1); - expect(presence.GetOnlineWebClientCount() == 1); + expect(presence.GetOnlineDeviceCount() == 1, + "web client does not increment online device count"); + expect(presence.GetOnlineWebClientCount() == 1, + "web client increments web client count"); + + presence.OnLogin("C-000000", "C-000000", hdl); + expect(presence.GetOnlineDeviceCount() == 1, + "clone client does not increment online device count"); + expect(presence.GetOnlineWebClientCount() == 1, + "clone client does not increment web client count"); + + presence.OnLogout("C-000000"); + expect(presence.GetOnlineDeviceCount() == 1, + "clone logout leaves online device count unchanged"); + expect(presence.GetOnlineWebClientCount() == 1, + "clone logout leaves web client count unchanged"); presence.OnLogout("web-1"); - expect(presence.GetOnlineDeviceCount() == 1); - expect(presence.GetOnlineWebClientCount() == 0); + expect(presence.GetOnlineDeviceCount() == 1, + "web logout leaves online device count unchanged"); + expect(presence.GetOnlineWebClientCount() == 0, + "web logout decrements web client count"); + + const auto db_path = + std::filesystem::temp_directory_path() / + ("crossdesk_presence_manager_test_" + + std::to_string(std::chrono::steady_clock::now() + .time_since_epoch() + .count()) + + ".db"); + { + DeviceDBManager db(db_path.string()); + db.SetDeviceOnline("device-1", true); + db.SetDeviceOnline("web-1", true); + db.SetDeviceOnline("C-000000", true); + expect(db.GetOnlineDeviceCount() == 1, + "database online device count excludes web and clone clients"); + } + std::filesystem::remove(db_path); return failures == 0 ? 0 : 1; }