Loading src/cluster.cpp +75 −5 Changes for src/cluster.cpp: 75 added lines, 5 removed lines. Original line number Diff line number Diff line Loading @@ -164,6 +164,22 @@ namespace authdb { return id; } uint64_t sidGroupId(const uuid::uuid &sid) { // SHA-256(0xFF || sid) → take first 8 bytes // 0xFF prefix avoids collision with sessionGroupId(uid||did) std::vector<uint8_t> input(17); input[0] = 0xFF; std::memcpy(input.data() + 1, sid.value, 16); auto hash = netplus::sha256_hash(input); uint64_t id = 0; for (int i = 0; i < 8; i++) { id = (id << 8) | hash[i]; } return id; } // --- Cluster --- Cluster::Cluster() {} Loading Loading @@ -264,19 +280,23 @@ namespace authdb { auto data = SessionBlock::serialize(sess); uuid::uuid uid, did; uuid::uuid sid, uid, did; sess.getSid(sid); sess.getUid(uid); sess.getDid(did); uint64_t sgid = sessionGroupId(uid, did); uint64_t sid_gid = sidGroupId(sid); // Store locally for peers to fetch // Store under both uid+did key and SID key store_->store(sgid, 0, data.data(), data.size()); store_->store(sid_gid, 0, data.data(), data.size()); // Replicate raw data to all peer nodes // Replicate raw data to all peer nodes under both keys try { std::lock_guard<std::mutex> lock(client_mutex_); pclient_->replicate_to_peers(sgid, 0, data.data(), data.size()); pclient_->replicate_to_peers(sid_gid, 0, data.data(), data.size()); } catch (const netplus::NetException &e) { std::cerr << "Cluster push session failed: " << e.what() << std::endl; } catch (const std::exception &e) { Loading Loading @@ -321,10 +341,27 @@ namespace authdb { void Cluster::removeSession(const uuid::uuid &uid, const uuid::uuid &did) { uint64_t sgid = sessionGroupId(uid, did); // Remove from local store // Also remove the SID-keyed entry: fetch data first to get the SID std::vector<uint8_t> data; if (store_->fetch(sgid, 0, data)) { uuid::uuid sid, d_uid, d_did; std::vector<uuid::uuid> members; std::string username; if (SessionBlock::deserialize(data, sid, d_uid, d_did, members, username)) { uint64_t sid_gid = sidGroupId(sid); store_->remove_group(sid_gid); if (pclient_) { try { std::lock_guard<std::mutex> lock(client_mutex_); pclient_->remove(sid_gid); } catch (...) {} } } } // Remove uid+did keyed entry store_->remove_group(sgid); // Remove from all peer nodes if (pclient_) { try { std::lock_guard<std::mutex> lock(client_mutex_); Loading Loading @@ -352,6 +389,39 @@ namespace authdb { return false; } bool Cluster::fetchSessionBySid(const uuid::uuid &session_id, uuid::uuid &sid, uuid::uuid &uid, uuid::uuid &did, std::vector<uuid::uuid> &members, std::string &username) { uint64_t sid_gid = sidGroupId(session_id); // Check local store first std::vector<uint8_t> data; if (store_->fetch(sid_gid, 0, data)) { if (SessionBlock::deserialize(data, sid, uid, did, members, username)) { return true; } } // Try to fetch from peer nodes if (pclient_) { try { std::lock_guard<std::mutex> lock(client_mutex_); if (pclient_->fetch_from_peers(sid_gid, 0, data) && !data.empty()) { if (SessionBlock::deserialize(data, sid, uid, did, members, username)) { // Cache locally store_->store(sid_gid, 0, data.data(), data.size()); return true; } } } catch (...) { return false; } } return false; } // --- DataOpBlock serialization --- std::vector<uint8_t> DataOpBlock::serialize(OpType op, const std::string &domain, Loading src/cluster.h +7 −0 Changes for src/cluster.h: 7 added lines, 0 removed lines. Original line number Diff line number Diff line Loading @@ -74,6 +74,7 @@ namespace authdb { }; uint64_t sessionGroupId(const uuid::uuid &uid, const uuid::uuid &did); uint64_t sidGroupId(const uuid::uuid &sid); // --- Data operation replication --- Loading Loading @@ -137,6 +138,12 @@ namespace authdb { // Check if a session already exists in the cluster for uid+did bool hasSession(const uuid::uuid &uid, const uuid::uuid &did); // Fetch a session from the cluster by session ID (SID) bool fetchSessionBySid(const uuid::uuid &session_id, uuid::uuid &sid, uuid::uuid &uid, uuid::uuid &did, std::vector<uuid::uuid> &members, std::string &username); // Replicate a data operation (create/edit/delete) to peers void replicateOp(OpType op, const std::string &domain, const uuid::uuid &uid, int dataType, Loading src/session.cpp +23 −3 Changes for src/session.cpp: 23 added lines, 3 removed lines. Original line number Diff line number Diff line Loading @@ -363,16 +363,36 @@ const authdb::SessionData *authdb::Session::addSession(AuthBackend &backend,uuid } const authdb::SessionData *authdb::Session::getSession(uuid::uuid sessionid){ { std::lock_guard<std::mutex> guard(_SessionLock); cleanupExpired(); for(SessionData *cur=_firstData; cur; cur=cur->_next){ if(cur->_sid==sessionid) return cur; } } // Not found locally — fetch from cluster peers by SID if (g_Cluster && g_Cluster->isRunning()) { uuid::uuid sid, uid, did; std::vector<uuid::uuid> members; std::string username; if (g_Cluster->fetchSessionBySid(sessionid, sid, uid, did, members, username)) { SessionData *imported = new SessionData(sid, uid, did, members); imported->_username = username; std::lock_guard<std::mutex> guard(_SessionLock); if (!_firstData) { _firstData = imported; _lastData = _firstData; } else { _lastData->_next = imported; _lastData = _lastData->_next; } return imported; } } // Not found locally — check cluster peers // We can't query by session ID directly since cluster stores by uid+did, // so if not found locally, the session must be resolved through login flow return nullptr; } Loading Loading
src/cluster.cpp +75 −5 Changes for src/cluster.cpp: 75 added lines, 5 removed lines. Original line number Diff line number Diff line Loading @@ -164,6 +164,22 @@ namespace authdb { return id; } uint64_t sidGroupId(const uuid::uuid &sid) { // SHA-256(0xFF || sid) → take first 8 bytes // 0xFF prefix avoids collision with sessionGroupId(uid||did) std::vector<uint8_t> input(17); input[0] = 0xFF; std::memcpy(input.data() + 1, sid.value, 16); auto hash = netplus::sha256_hash(input); uint64_t id = 0; for (int i = 0; i < 8; i++) { id = (id << 8) | hash[i]; } return id; } // --- Cluster --- Cluster::Cluster() {} Loading Loading @@ -264,19 +280,23 @@ namespace authdb { auto data = SessionBlock::serialize(sess); uuid::uuid uid, did; uuid::uuid sid, uid, did; sess.getSid(sid); sess.getUid(uid); sess.getDid(did); uint64_t sgid = sessionGroupId(uid, did); uint64_t sid_gid = sidGroupId(sid); // Store locally for peers to fetch // Store under both uid+did key and SID key store_->store(sgid, 0, data.data(), data.size()); store_->store(sid_gid, 0, data.data(), data.size()); // Replicate raw data to all peer nodes // Replicate raw data to all peer nodes under both keys try { std::lock_guard<std::mutex> lock(client_mutex_); pclient_->replicate_to_peers(sgid, 0, data.data(), data.size()); pclient_->replicate_to_peers(sid_gid, 0, data.data(), data.size()); } catch (const netplus::NetException &e) { std::cerr << "Cluster push session failed: " << e.what() << std::endl; } catch (const std::exception &e) { Loading Loading @@ -321,10 +341,27 @@ namespace authdb { void Cluster::removeSession(const uuid::uuid &uid, const uuid::uuid &did) { uint64_t sgid = sessionGroupId(uid, did); // Remove from local store // Also remove the SID-keyed entry: fetch data first to get the SID std::vector<uint8_t> data; if (store_->fetch(sgid, 0, data)) { uuid::uuid sid, d_uid, d_did; std::vector<uuid::uuid> members; std::string username; if (SessionBlock::deserialize(data, sid, d_uid, d_did, members, username)) { uint64_t sid_gid = sidGroupId(sid); store_->remove_group(sid_gid); if (pclient_) { try { std::lock_guard<std::mutex> lock(client_mutex_); pclient_->remove(sid_gid); } catch (...) {} } } } // Remove uid+did keyed entry store_->remove_group(sgid); // Remove from all peer nodes if (pclient_) { try { std::lock_guard<std::mutex> lock(client_mutex_); Loading Loading @@ -352,6 +389,39 @@ namespace authdb { return false; } bool Cluster::fetchSessionBySid(const uuid::uuid &session_id, uuid::uuid &sid, uuid::uuid &uid, uuid::uuid &did, std::vector<uuid::uuid> &members, std::string &username) { uint64_t sid_gid = sidGroupId(session_id); // Check local store first std::vector<uint8_t> data; if (store_->fetch(sid_gid, 0, data)) { if (SessionBlock::deserialize(data, sid, uid, did, members, username)) { return true; } } // Try to fetch from peer nodes if (pclient_) { try { std::lock_guard<std::mutex> lock(client_mutex_); if (pclient_->fetch_from_peers(sid_gid, 0, data) && !data.empty()) { if (SessionBlock::deserialize(data, sid, uid, did, members, username)) { // Cache locally store_->store(sid_gid, 0, data.data(), data.size()); return true; } } } catch (...) { return false; } } return false; } // --- DataOpBlock serialization --- std::vector<uint8_t> DataOpBlock::serialize(OpType op, const std::string &domain, Loading
src/cluster.h +7 −0 Changes for src/cluster.h: 7 added lines, 0 removed lines. Original line number Diff line number Diff line Loading @@ -74,6 +74,7 @@ namespace authdb { }; uint64_t sessionGroupId(const uuid::uuid &uid, const uuid::uuid &did); uint64_t sidGroupId(const uuid::uuid &sid); // --- Data operation replication --- Loading Loading @@ -137,6 +138,12 @@ namespace authdb { // Check if a session already exists in the cluster for uid+did bool hasSession(const uuid::uuid &uid, const uuid::uuid &did); // Fetch a session from the cluster by session ID (SID) bool fetchSessionBySid(const uuid::uuid &session_id, uuid::uuid &sid, uuid::uuid &uid, uuid::uuid &did, std::vector<uuid::uuid> &members, std::string &username); // Replicate a data operation (create/edit/delete) to peers void replicateOp(OpType op, const std::string &domain, const uuid::uuid &uid, int dataType, Loading
src/session.cpp +23 −3 Changes for src/session.cpp: 23 added lines, 3 removed lines. Original line number Diff line number Diff line Loading @@ -363,16 +363,36 @@ const authdb::SessionData *authdb::Session::addSession(AuthBackend &backend,uuid } const authdb::SessionData *authdb::Session::getSession(uuid::uuid sessionid){ { std::lock_guard<std::mutex> guard(_SessionLock); cleanupExpired(); for(SessionData *cur=_firstData; cur; cur=cur->_next){ if(cur->_sid==sessionid) return cur; } } // Not found locally — fetch from cluster peers by SID if (g_Cluster && g_Cluster->isRunning()) { uuid::uuid sid, uid, did; std::vector<uuid::uuid> members; std::string username; if (g_Cluster->fetchSessionBySid(sessionid, sid, uid, did, members, username)) { SessionData *imported = new SessionData(sid, uid, did, members); imported->_username = username; std::lock_guard<std::mutex> guard(_SessionLock); if (!_firstData) { _firstData = imported; _lastData = _firstData; } else { _lastData->_next = imported; _lastData = _lastData->_next; } return imported; } } // Not found locally — check cluster peers // We can't query by session ID directly since cluster stores by uid+did, // so if not found locally, the session must be resolved through login flow return nullptr; } Loading