Loading src/admin.cpp +17 −0 Original line number Diff line number Diff line Loading @@ -57,6 +57,7 @@ #include "plugin.h" #include "service.h" #include "cluster.h" #include "profile_webp.h" namespace authdb { Loading Loading @@ -221,6 +222,7 @@ namespace authdb { uid.generate(); class UserData udat(uid); bool username = false; bool hasAvatar = false; std::string capturedRawPw; std::string capturedUsername; Loading Loading @@ -256,6 +258,7 @@ namespace authdb { strcpy(cudat.fieldname, name.c_str()); if (cudat.storage == BinaryStorage) { if (strcmp(cudat.fieldname, "avatar") == 0) hasAvatar = true; cudat.datasize = curformdat.value.size(); cudat.data = new char[cudat.datasize]; memcpy(cudat.data, curformdat.value.data(), cudat.datasize); Loading Loading @@ -301,6 +304,20 @@ namespace authdb { if (!username) throw AuthBackendError("username not set!"); if (!hasAvatar) { struct AuthData::Record avat; avat.start = 0xFE; std::copy(&uid.value[0], &uid.value[16], &avat.ruid[0]); avat.type = UserData; avat.storage = BinaryStorage; strcpy(avat.fieldname, "avatar"); avat.datasize = sizeof(profile_webp); avat.data = new char[avat.datasize]; memcpy(avat.data, profile_webp, sizeof(profile_webp)); udat.append(avat); delete[] avat.data; } /* * Compute Kerberos long-term key (RFC 3962 string-to-key) from * the raw password so that MIT / Heimdal kinit can authenticate. Loading src/authdb.cpp +70 −35 Original line number Diff line number Diff line Loading @@ -289,12 +289,19 @@ namespace authdb { _AdminInterface.Request(curreq,tid,args); g_Log.access(clientAddr,method,curreq.getRequestURL(),200); }catch(AuthBackendError &e){ g_Log.error(clientAddr,e.what()); // Retry once on lock timeout before returning 500 try{ std::this_thread::yield(); _AdminInterface.Request(curreq,tid,args); g_Log.access(clientAddr,method,curreq.getRequestURL(),200); }catch(AuthBackendError &e2){ g_Log.error(clientAddr,e2.what()); g_Log.access(clientAddr,method,curreq.getRequestURL(),500); libhttppp::HttpResponse rep; rep.setState(HTTP500); rep.setContentType("text/html"); rep.send(curreq,e.what(),strlen(e.what())); rep.send(curreq,e2.what(),strlen(e2.what())); } } }else if(curreq.getRequestURL().compare(0,4,"/api",4)==0){ char domain[255]={0}; Loading Loading @@ -342,10 +349,29 @@ namespace authdb { } if(apidb){ AuthBackend::Guard guard(*apidb); for(int _retry=0; _retry<2; ++_retry){ try{ AuthBackend::Guard guard(*apidb); ApiController(*apidb,did,curreq,tid,args); g_Log.access(clientAddr,method,curreq.getRequestURL(),200); break; }catch(AuthBackendError &e){ if(_retry==0){ std::this_thread::yield(); continue; } g_Log.error(clientAddr,e.what()); g_Log.access(clientAddr,method,curreq.getRequestURL(),500); json_object *jerr = json_object_new_array(); json_object *eobj = json_object_new_object(); json_object_object_add(eobj,"error",json_object_new_string(e.what())); json_object_array_add(jerr,eobj); const char *errstr = json_object_to_json_string(jerr); libhttppp::HttpResponse rep; rep.setState(HTTP500); rep.setContentType("application/json"); rep.send(curreq,errstr,strlen(errstr)); json_object_put(jerr); }catch(std::exception &e){ g_Log.error(clientAddr,e.what()); g_Log.access(clientAddr,method,curreq.getRequestURL(),500); Loading @@ -359,12 +385,15 @@ namespace authdb { rep.setContentType("application/json"); rep.send(curreq,errstr,strlen(errstr)); json_object_put(jerr); break; }catch(...){ g_Log.access(clientAddr,method,curreq.getRequestURL(),500); libhttppp::HttpResponse rep; rep.setState(HTTP500); rep.setContentType("application/json"); rep.send(curreq,"[{\"error\":\"internal error\"}]",28); break; } } }else{ g_Log.access(clientAddr,method,curreq.getRequestURL(),404); Loading @@ -378,12 +407,18 @@ namespace authdb { getAvatar(curreq,tid,args); g_Log.access(clientAddr,method,curreq.getRequestURL(),200); }catch(AuthBackendError &e){ g_Log.error(clientAddr,e.what()); try{ std::this_thread::yield(); getAvatar(curreq,tid,args); g_Log.access(clientAddr,method,curreq.getRequestURL(),200); }catch(AuthBackendError &e2){ g_Log.error(clientAddr,e2.what()); g_Log.access(clientAddr,method,curreq.getRequestURL(),500); libhttppp::HttpResponse rep; rep.setState(HTTP500); rep.setContentType("text/html"); rep.send(curreq,e.what(),strlen(e.what())); rep.send(curreq,e2.what(),strlen(e2.what())); } } }else{ libhttppp::HttpResponse rep; Loading src/cluster.cpp +29 −9 Original line number Diff line number Diff line Loading @@ -499,40 +499,60 @@ namespace authdb { bool first_run = true; while (running_) { if (!first_run) { // Probe faster when degraded/critical (3s) vs normal (10s) auto interval = (degraded_ || critical_) ? std::chrono::seconds(3) : std::chrono::seconds(10); std::unique_lock<std::mutex> lk(monitor_mutex_); monitor_cv_.wait_for(lk, std::chrono::seconds(10), monitor_cv_.wait_for(lk, interval, [this]{ return !running_.load(); }); } first_run = false; if (!running_ || !pclient_) continue; try { std::unique_lock<std::timed_mutex> lock(client_mutex_, std::try_to_lock); if (!lock.owns_lock()) continue; // skip cycle, don't fight session ops std::unique_lock<std::timed_mutex> lock; if (critical_) { // When critical, wait briefly to ensure recovery probes execute lock = std::unique_lock<std::timed_mutex>(client_mutex_, std::chrono::seconds(2)); } else { // Normal: non-blocking, don't fight session ops lock = std::unique_lock<std::timed_mutex>(client_mutex_, std::try_to_lock); } if (!lock.owns_lock()) continue; auto health = pclient_->get_cluster_status(); bool was_degraded = degraded_; bool was_critical = critical_; if (health.nodes_online >= n) { if (degraded_) { std::cerr << "Cluster: recovered — all " << health.nodes_online << "/" << n << " nodes online" << std::endl; degraded_ = false; } degraded_ = false; critical_ = false; } else if (health.nodes_online >= k) { if (!degraded_) { if (was_critical) { std::cerr << "Cluster: recovering — " << health.nodes_online << "/" << n << " nodes online (was CRITICAL)" << std::endl; } else if (!degraded_) { std::cerr << "Cluster: DEGRADED — " << health.nodes_online << "/" << n << " nodes online" << std::endl; } degraded_ = true; critical_ = false; } else { if (!critical_) { std::cerr << "Cluster: CRITICAL — only " << health.nodes_online << "/" << n << " nodes online (need " << k << ")" << std::endl; } degraded_ = true; critical_ = true; } } catch (const std::exception &e) { if (!critical_) { std::cerr << "Cluster: health probe failed: " << e.what() << std::endl; } degraded_ = true; critical_ = true; } Loading src/profile_webp.h 0 → 100644 +808 −0 File added.Preview size limit exceeded, changes collapsed. Show changes Loading
src/admin.cpp +17 −0 Original line number Diff line number Diff line Loading @@ -57,6 +57,7 @@ #include "plugin.h" #include "service.h" #include "cluster.h" #include "profile_webp.h" namespace authdb { Loading Loading @@ -221,6 +222,7 @@ namespace authdb { uid.generate(); class UserData udat(uid); bool username = false; bool hasAvatar = false; std::string capturedRawPw; std::string capturedUsername; Loading Loading @@ -256,6 +258,7 @@ namespace authdb { strcpy(cudat.fieldname, name.c_str()); if (cudat.storage == BinaryStorage) { if (strcmp(cudat.fieldname, "avatar") == 0) hasAvatar = true; cudat.datasize = curformdat.value.size(); cudat.data = new char[cudat.datasize]; memcpy(cudat.data, curformdat.value.data(), cudat.datasize); Loading Loading @@ -301,6 +304,20 @@ namespace authdb { if (!username) throw AuthBackendError("username not set!"); if (!hasAvatar) { struct AuthData::Record avat; avat.start = 0xFE; std::copy(&uid.value[0], &uid.value[16], &avat.ruid[0]); avat.type = UserData; avat.storage = BinaryStorage; strcpy(avat.fieldname, "avatar"); avat.datasize = sizeof(profile_webp); avat.data = new char[avat.datasize]; memcpy(avat.data, profile_webp, sizeof(profile_webp)); udat.append(avat); delete[] avat.data; } /* * Compute Kerberos long-term key (RFC 3962 string-to-key) from * the raw password so that MIT / Heimdal kinit can authenticate. Loading
src/authdb.cpp +70 −35 Original line number Diff line number Diff line Loading @@ -289,12 +289,19 @@ namespace authdb { _AdminInterface.Request(curreq,tid,args); g_Log.access(clientAddr,method,curreq.getRequestURL(),200); }catch(AuthBackendError &e){ g_Log.error(clientAddr,e.what()); // Retry once on lock timeout before returning 500 try{ std::this_thread::yield(); _AdminInterface.Request(curreq,tid,args); g_Log.access(clientAddr,method,curreq.getRequestURL(),200); }catch(AuthBackendError &e2){ g_Log.error(clientAddr,e2.what()); g_Log.access(clientAddr,method,curreq.getRequestURL(),500); libhttppp::HttpResponse rep; rep.setState(HTTP500); rep.setContentType("text/html"); rep.send(curreq,e.what(),strlen(e.what())); rep.send(curreq,e2.what(),strlen(e2.what())); } } }else if(curreq.getRequestURL().compare(0,4,"/api",4)==0){ char domain[255]={0}; Loading Loading @@ -342,10 +349,29 @@ namespace authdb { } if(apidb){ AuthBackend::Guard guard(*apidb); for(int _retry=0; _retry<2; ++_retry){ try{ AuthBackend::Guard guard(*apidb); ApiController(*apidb,did,curreq,tid,args); g_Log.access(clientAddr,method,curreq.getRequestURL(),200); break; }catch(AuthBackendError &e){ if(_retry==0){ std::this_thread::yield(); continue; } g_Log.error(clientAddr,e.what()); g_Log.access(clientAddr,method,curreq.getRequestURL(),500); json_object *jerr = json_object_new_array(); json_object *eobj = json_object_new_object(); json_object_object_add(eobj,"error",json_object_new_string(e.what())); json_object_array_add(jerr,eobj); const char *errstr = json_object_to_json_string(jerr); libhttppp::HttpResponse rep; rep.setState(HTTP500); rep.setContentType("application/json"); rep.send(curreq,errstr,strlen(errstr)); json_object_put(jerr); }catch(std::exception &e){ g_Log.error(clientAddr,e.what()); g_Log.access(clientAddr,method,curreq.getRequestURL(),500); Loading @@ -359,12 +385,15 @@ namespace authdb { rep.setContentType("application/json"); rep.send(curreq,errstr,strlen(errstr)); json_object_put(jerr); break; }catch(...){ g_Log.access(clientAddr,method,curreq.getRequestURL(),500); libhttppp::HttpResponse rep; rep.setState(HTTP500); rep.setContentType("application/json"); rep.send(curreq,"[{\"error\":\"internal error\"}]",28); break; } } }else{ g_Log.access(clientAddr,method,curreq.getRequestURL(),404); Loading @@ -378,12 +407,18 @@ namespace authdb { getAvatar(curreq,tid,args); g_Log.access(clientAddr,method,curreq.getRequestURL(),200); }catch(AuthBackendError &e){ g_Log.error(clientAddr,e.what()); try{ std::this_thread::yield(); getAvatar(curreq,tid,args); g_Log.access(clientAddr,method,curreq.getRequestURL(),200); }catch(AuthBackendError &e2){ g_Log.error(clientAddr,e2.what()); g_Log.access(clientAddr,method,curreq.getRequestURL(),500); libhttppp::HttpResponse rep; rep.setState(HTTP500); rep.setContentType("text/html"); rep.send(curreq,e.what(),strlen(e.what())); rep.send(curreq,e2.what(),strlen(e2.what())); } } }else{ libhttppp::HttpResponse rep; Loading
src/cluster.cpp +29 −9 Original line number Diff line number Diff line Loading @@ -499,40 +499,60 @@ namespace authdb { bool first_run = true; while (running_) { if (!first_run) { // Probe faster when degraded/critical (3s) vs normal (10s) auto interval = (degraded_ || critical_) ? std::chrono::seconds(3) : std::chrono::seconds(10); std::unique_lock<std::mutex> lk(monitor_mutex_); monitor_cv_.wait_for(lk, std::chrono::seconds(10), monitor_cv_.wait_for(lk, interval, [this]{ return !running_.load(); }); } first_run = false; if (!running_ || !pclient_) continue; try { std::unique_lock<std::timed_mutex> lock(client_mutex_, std::try_to_lock); if (!lock.owns_lock()) continue; // skip cycle, don't fight session ops std::unique_lock<std::timed_mutex> lock; if (critical_) { // When critical, wait briefly to ensure recovery probes execute lock = std::unique_lock<std::timed_mutex>(client_mutex_, std::chrono::seconds(2)); } else { // Normal: non-blocking, don't fight session ops lock = std::unique_lock<std::timed_mutex>(client_mutex_, std::try_to_lock); } if (!lock.owns_lock()) continue; auto health = pclient_->get_cluster_status(); bool was_degraded = degraded_; bool was_critical = critical_; if (health.nodes_online >= n) { if (degraded_) { std::cerr << "Cluster: recovered — all " << health.nodes_online << "/" << n << " nodes online" << std::endl; degraded_ = false; } degraded_ = false; critical_ = false; } else if (health.nodes_online >= k) { if (!degraded_) { if (was_critical) { std::cerr << "Cluster: recovering — " << health.nodes_online << "/" << n << " nodes online (was CRITICAL)" << std::endl; } else if (!degraded_) { std::cerr << "Cluster: DEGRADED — " << health.nodes_online << "/" << n << " nodes online" << std::endl; } degraded_ = true; critical_ = false; } else { if (!critical_) { std::cerr << "Cluster: CRITICAL — only " << health.nodes_online << "/" << n << " nodes online (need " << k << ")" << std::endl; } degraded_ = true; critical_ = true; } } catch (const std::exception &e) { if (!critical_) { std::cerr << "Cluster: health probe failed: " << e.what() << std::endl; } degraded_ = true; critical_ = true; } Loading
src/profile_webp.h 0 → 100644 +808 −0 File added.Preview size limit exceeded, changes collapsed. Show changes