Files
project-vesper/vesper/src/ClientManager/ClientManager.cpp
bonamin fe6b1d871a feat: Add per-subsystem log tags to all firmware modules
Refactored logging system to require a TAG as first argument on all
LOG_* macros, enabling per-subsystem log filtering and cleaner output.
Each subsystem now defines its own TAG (e.g. "BellEngine", "Player").
Also overhauled Logging.hpp/cpp with improved level control and output.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-26 17:31:28 +02:00

170 lines
5.6 KiB
C++

#include "ClientManager.hpp"
#define TAG "ClientManager"
#include "../Logging/Logging.hpp"
ClientManager::ClientManager() {
LOG_INFO(TAG, "Client Manager initialized !");
}
ClientManager::~ClientManager() {
_clients.clear();
LOG_INFO(TAG, "Client Manager destroyed");
}
void ClientManager::addClient(AsyncWebSocketClient* client, DeviceType deviceType) {
if (!isValidClient(client)) {
LOG_WARNING(TAG, "Client Manager - Cannot add invalid client");
return;
}
uint32_t clientId = client->id();
_clients[clientId] = ClientInfo(client, deviceType);
LOG_INFO(TAG, "Client Manager - Client #%u added as %s device", clientId, deviceTypeToString(deviceType));
}
void ClientManager::removeClient(uint32_t clientId) {
auto it = _clients.find(clientId);
if (it != _clients.end()) {
LOG_INFO(TAG, "Client Manager - Client #%u removed (%s device)", clientId,
deviceTypeToString(it->second.deviceType));
_clients.erase(it);
}
}
void ClientManager::updateClientType(uint32_t clientId, DeviceType deviceType) {
auto it = _clients.find(clientId);
if (it != _clients.end()) {
DeviceType oldType = it->second.deviceType;
it->second.deviceType = deviceType;
LOG_INFO(TAG, "Client Manager - Client #%u type updated from %s to %s", clientId,
deviceTypeToString(oldType), deviceTypeToString(deviceType));
}
}
void ClientManager::updateClientLastSeen(uint32_t clientId) {
auto it = _clients.find(clientId);
if (it != _clients.end()) {
it->second.lastSeen = millis();
}
}
bool ClientManager::isClientConnected(uint32_t clientId) const {
auto it = _clients.find(clientId);
if (it != _clients.end()) {
return it->second.isConnected &&
isValidClient(it->second.client);
}
return false;
}
ClientManager::DeviceType ClientManager::getClientType(uint32_t clientId) const {
auto it = _clients.find(clientId);
return (it != _clients.end()) ? it->second.deviceType : DeviceType::UNKNOWN;
}
ClientManager::ClientInfo* ClientManager::getClientInfo(uint32_t clientId) {
auto it = _clients.find(clientId);
return (it != _clients.end()) ? &it->second : nullptr;
}
bool ClientManager::sendToClient(uint32_t clientId, const String& message) {
auto it = _clients.find(clientId);
if (it != _clients.end() && isValidClient(it->second.client)) {
it->second.client->text(message);
updateClientLastSeen(clientId);
LOG_DEBUG(TAG, "Client Manager - Message sent to client #%u: %s", clientId, message.c_str());
return true;
}
LOG_WARNING(TAG, "Client Manager - Failed to send message to client #%u - client not found or invalid", clientId);
return false;
}
void ClientManager::sendToMasterClients(const String& message) {
int count = 0;
for (auto& pair : _clients) {
if (pair.second.deviceType == DeviceType::MASTER &&
isValidClient(pair.second.client)) {
pair.second.client->text(message);
updateClientLastSeen(pair.first);
count++;
}
}
LOG_DEBUG(TAG, "Client Manager - Message sent to %d master client(s): %s", count, message.c_str());
}
void ClientManager::sendToSecondaryClients(const String& message) {
int count = 0;
for (auto& pair : _clients) {
if (pair.second.deviceType == DeviceType::SECONDARY &&
isValidClient(pair.second.client)) {
pair.second.client->text(message);
updateClientLastSeen(pair.first);
count++;
}
}
LOG_DEBUG(TAG, "Client Manager - Message sent to %d secondary client(s): %s", count, message.c_str());
}
void ClientManager::broadcastToAll(const String& message) {
int count = 0;
for (auto& pair : _clients) {
if (isValidClient(pair.second.client)) {
pair.second.client->text(message);
updateClientLastSeen(pair.first);
count++;
}
}
LOG_DEBUG(TAG, "Client Manager - Message broadcasted to %d client(s): %s", count, message.c_str());
}
void ClientManager::cleanupDisconnectedClients() {
auto it = _clients.begin();
while (it != _clients.end()) {
if (!isValidClient(it->second.client)) {
LOG_DEBUG(TAG, "Client Manager - Cleaning up disconnected client #%u", it->first);
it->second.isConnected = false;
it = _clients.erase(it);
} else {
++it;
}
}
}
String ClientManager::getClientListJson() const {
StaticJsonDocument<512> doc;
JsonArray clients = doc.createNestedArray("clients");
for (const auto& pair : _clients) {
JsonObject client = clients.createNestedObject();
client["id"] = pair.first;
client["type"] = deviceTypeToString(pair.second.deviceType);
client["connected"] = isValidClient(pair.second.client);
client["last_seen"] = pair.second.lastSeen;
}
String result;
serializeJson(doc, result);
return result;
}
const char* ClientManager::deviceTypeToString(DeviceType type) const {
switch (type) {
case DeviceType::MASTER: return "master";
case DeviceType::SECONDARY: return "secondary";
default: return "unknown";
}
}
ClientManager::DeviceType ClientManager::stringToDeviceType(const String& typeStr) const {
if (typeStr == "master") return DeviceType::MASTER;
if (typeStr == "secondary") return DeviceType::SECONDARY;
return DeviceType::UNKNOWN;
}
bool ClientManager::isValidClient(AsyncWebSocketClient* client) const {
return client != nullptr && client->status() == WS_CONNECTED;
}