Complete Rebuild, with Subsystems for each component. RTOS Tasks. (help by Claude)

This commit is contained in:
2025-10-01 12:42:00 +03:00
parent 104c1d04d4
commit f696984cd1
57 changed files with 11757 additions and 2290 deletions

View File

@@ -0,0 +1,167 @@
#include "ClientManager.hpp"
#include "../Logging/Logging.hpp"
ClientManager::ClientManager() {
LOG_INFO("Client Manager Component - Initialized");
}
ClientManager::~ClientManager() {
_clients.clear();
LOG_INFO("Client Manager Component - Destroyed");
}
void ClientManager::addClient(AsyncWebSocketClient* client, DeviceType deviceType) {
if (!isValidClient(client)) {
LOG_ERROR("Cannot add invalid client");
return;
}
uint32_t clientId = client->id();
_clients[clientId] = ClientInfo(client, deviceType);
LOG_INFO("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("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("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("Message sent to client #%u: %s", clientId, message.c_str());
return true;
}
LOG_WARNING("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("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("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("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("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;
}