Loading src/conf.cpp +64 −63 Original line number Diff line number Diff line Loading @@ -56,28 +56,35 @@ blogi::Config::Config(const std::string &path) : confplus::Config(path), _Config try { _ClientName=getValue(getKey("/BLOGI/AUTHDB/CLIENTNAME"),0); } catch(...) {} try { _ClientSecret=getValue(getKey("/BLOGI/AUTHDB/CLIENTSECRET"),0); } catch(...) {} // Parse multi-domain AUTHDB sources (parallel arrays) // Parse multi-domain AUTHDB sources. // Preferred form is an indexed sequence: /BLOGI/AUTHDB/<i>/URL ... . // A legacy single-mapping form (/BLOGI/AUTHDB/URL) is still supported. try { auto *urlKey = getKey("/BLOGI/AUTHDB/URL"); auto *nameKey = getKey("/BLOGI/AUTHDB/CLIENTNAME"); auto *secretKey = getKey("/BLOGI/AUTHDB/CLIENTSECRET"); size_t count = getElements(urlKey); for (size_t i = 0; i < count; ++i) { bool indexed = false; for (size_t i = 0; ; ++i) { std::string base = "/BLOGI/AUTHDB/" + std::to_string(i); auto *node = getKey(base.c_str()); if (!node) break; indexed = true; AuthSource src; src.url = getValue(urlKey, i); src.clientName = getValue(nameKey, i); src.clientSecret = getValue(secretKey, i); try { auto *domKey = getKey("/BLOGI/AUTHDB/DOMAIN"); src.domain = getValue(domKey, i); } catch (...) { src.domain = ""; try { src.url = getValue(getKey((base + "/URL").c_str()), 0); } catch(...) { continue; } try { src.clientName = getValue(getKey((base + "/CLIENTNAME").c_str()), 0); } catch(...) {} try { src.clientSecret = getValue(getKey((base + "/CLIENTSECRET").c_str()), 0); } catch(...) {} try { src.domain = getValue(getKey((base + "/DOMAIN").c_str()), 0); } catch(...) { src.domain = ""; } _AuthSources.push_back(std::move(src)); } if (!indexed && !_AuthUrl.empty()) { // Legacy single mapping AuthSource src; src.url = _AuthUrl; src.clientName = _ClientName; src.clientSecret = _ClientSecret; try { src.domain = getValue(getKey("/BLOGI/AUTHDB/DOMAIN"), 0); } catch(...) { src.domain = ""; } _AuthSources.push_back(std::move(src)); } } catch (...) { // If multi-domain parsing fails, create a single source from legacy fields if (!_AuthUrl.empty()) { if (_AuthSources.empty() && !_AuthUrl.empty()) { AuthSource src; src.url = _AuthUrl; src.clientName = _ClientName; Loading Loading @@ -134,78 +141,72 @@ blogi::Config::Config(const std::string &path) : confplus::Config(path), _Config _MediaDBUrl="https://127.0.0.1:8442"; } // Parse multi-domain configurations // libconfplus YAML stores sequence-of-mappings as flat keys with positional values. // Parse multi-domain configurations. // The libconfplus YAML loader produces a fully indexed tree: each entry of // the DOMAINS sequence lives under /BLOGI/DOMAINS/<i>/... . // Each domain entry MUST define its own DB_DRIVER, DB_CONNECTION, etc. // NAME is an array: one config entry can serve multiple domain names. // No global fallbacks — unconfigured domains get 404. // NAMES is a proper nested sequence: one config entry can serve multiple // domain names. No global fallbacks — unconfigured domains get 404. try { auto *dbDriverKey = getKey("/BLOGI/DOMAINS/DB_DRIVER"); if (!dbDriverKey) throw std::runtime_error("no domains"); size_t domCount = getElements(dbDriverKey); for (size_t i = 0; i < domCount; ++i) { for (size_t i = 0; ; ++i) { std::string base = "/BLOGI/DOMAINS/" + std::to_string(i); auto *domNode = getKey(base.c_str()); if (!domNode) break; // no more domain entries DomainConfig dc; // NAME is stored as a sub-array per domain entry via DOMAINS/NAME // NAME: single primary name for this entry. try { auto *nameKey = getKey("/BLOGI/DOMAINS/NAME"); auto *nameKey = getKey((base + "/NAME").c_str()); if (nameKey) { // In flat config, multiple names for the same domain entry // are stored as comma-separated or as multiple positional values. // With the current YAML parser, each domain entry gets one NAME value, // but we also support NAMES as a separate multi-value key. std::string n = getValue(nameKey, i); std::string n = getValue(nameKey, 0); if (!n.empty()) dc.names.push_back(n); } } catch(...) {} // Additional names via DOMAINS/NAMES (array per domain) // NAMES: nested sequence of additional names for this entry. try { auto *namesKey = getKey("/BLOGI/DOMAINS/NAMES"); auto *namesKey = getKey((base + "/NAMES").c_str()); if (namesKey) { size_t namesCount = getElements(namesKey); for (size_t j = 0; j < namesCount; ++j) { size_t nameCount = getElements(namesKey); for (size_t j = 0; j < nameCount; ++j) { std::string n = getValue(namesKey, j); // Only add names that belong to this domain index // In flat config with seqMapping, all names at index i belong to domain i if (!n.empty()) { if (n.empty()) continue; bool dup = false; for (const auto &existing : dc.names) if (existing == n) { dup = true; break; } if (!dup) dc.names.push_back(n); } } } } catch(...) {} if (dc.names.empty()) continue; try { dc.dbDriver = getValue(dbDriverKey, i); } catch(...) { continue; } try { dc.dbConnection = getValue(getKey("/BLOGI/DOMAINS/DB_CONNECTION"), i); } catch(...) { continue; } try { auto *repKey = getKey("/BLOGI/DOMAINS/DB_REPLICAS"); if (repKey) { // TODO: per-domain replicas if needed } } catch(...) {} try { dc.dbDriver = getValue(getKey((base + "/DB_DRIVER").c_str()), 0); } catch(...) { continue; } try { dc.dbConnection = getValue(getKey((base + "/DB_CONNECTION").c_str()), 0); } catch(...) { continue; } try { dc.authUrl = getValue(getKey("/BLOGI/DOMAINS/AUTH_URL"), i); } catch(...) {} try { dc.clientName = getValue(getKey("/BLOGI/DOMAINS/AUTH_CLIENTNAME"), i); } catch(...) {} try { dc.clientSecret = getValue(getKey("/BLOGI/DOMAINS/AUTH_CLIENTSECRET"), i); } catch(...) {} try { dc.siteUrl = getValue(getKey("/BLOGI/DOMAINS/URL"), i); } catch(...) {} try { dc.authUrl = getValue(getKey((base + "/AUTH_URL").c_str()), 0); } catch(...) {} try { dc.clientName = getValue(getKey((base + "/AUTH_CLIENTNAME").c_str()), 0); } catch(...) {} try { dc.clientSecret = getValue(getKey((base + "/AUTH_CLIENTSECRET").c_str()), 0); } catch(...) {} try { dc.siteUrl = getValue(getKey((base + "/URL").c_str()), 0); } catch(...) {} dc.siteUrls.clear(); if (!dc.siteUrl.empty()) dc.siteUrls.push_back(dc.siteUrl); try { dc.prefix = getValue(getKey("/BLOGI/DOMAINS/PREFIX"), i); } catch(...) {} try { dc.prefix = getValue(getKey((base + "/PREFIX").c_str()), 0); } catch(...) {} if (dc.prefix == "/") dc.prefix = ""; try { dc.templatePath = getValue(getKey("/BLOGI/DOMAINS/TEMPLATE"), i); } catch(...) {} try { dc.startPage = getValue(getKey("/BLOGI/DOMAINS/STARTPAGE"), i); } catch(...) {} try { dc.mediaDBUrl = getValue(getKey("/BLOGI/DOMAINS/MEDIA_URL"), i); } catch(...) {} try { dc.tmpDir = getValue(getKey("/BLOGI/DOMAINS/TMPDIR"), i); } catch(...) { dc.tmpDir = "/tmp/blogi"; } try { dc.templatePath = getValue(getKey((base + "/TEMPLATE").c_str()), 0); } catch(...) {} try { dc.startPage = getValue(getKey((base + "/STARTPAGE").c_str()), 0); } catch(...) {} try { dc.mediaDBUrl = getValue(getKey((base + "/MEDIA_URL").c_str()), 0); } catch(...) {} try { dc.tmpDir = getValue(getKey((base + "/TMPDIR").c_str()), 0); } catch(...) { dc.tmpDir = "/tmp/blogi"; } try { std::string plgdir = getValue(getKey("/BLOGI/DOMAINS/PLUGINDIR"), i); auto *plgKey = getKey((base + "/PLUGINDIR").c_str()); if (plgKey) { size_t plgCount = getElements(plgKey); for (size_t j = 0; j < plgCount; ++j) { std::string plgdir = getValue(plgKey, j); if (!plgdir.empty()) dc.plgDirs.push_back(plgdir); } } } catch(...) {} // Auth source from domain values Loading Loading
src/conf.cpp +64 −63 Original line number Diff line number Diff line Loading @@ -56,28 +56,35 @@ blogi::Config::Config(const std::string &path) : confplus::Config(path), _Config try { _ClientName=getValue(getKey("/BLOGI/AUTHDB/CLIENTNAME"),0); } catch(...) {} try { _ClientSecret=getValue(getKey("/BLOGI/AUTHDB/CLIENTSECRET"),0); } catch(...) {} // Parse multi-domain AUTHDB sources (parallel arrays) // Parse multi-domain AUTHDB sources. // Preferred form is an indexed sequence: /BLOGI/AUTHDB/<i>/URL ... . // A legacy single-mapping form (/BLOGI/AUTHDB/URL) is still supported. try { auto *urlKey = getKey("/BLOGI/AUTHDB/URL"); auto *nameKey = getKey("/BLOGI/AUTHDB/CLIENTNAME"); auto *secretKey = getKey("/BLOGI/AUTHDB/CLIENTSECRET"); size_t count = getElements(urlKey); for (size_t i = 0; i < count; ++i) { bool indexed = false; for (size_t i = 0; ; ++i) { std::string base = "/BLOGI/AUTHDB/" + std::to_string(i); auto *node = getKey(base.c_str()); if (!node) break; indexed = true; AuthSource src; src.url = getValue(urlKey, i); src.clientName = getValue(nameKey, i); src.clientSecret = getValue(secretKey, i); try { auto *domKey = getKey("/BLOGI/AUTHDB/DOMAIN"); src.domain = getValue(domKey, i); } catch (...) { src.domain = ""; try { src.url = getValue(getKey((base + "/URL").c_str()), 0); } catch(...) { continue; } try { src.clientName = getValue(getKey((base + "/CLIENTNAME").c_str()), 0); } catch(...) {} try { src.clientSecret = getValue(getKey((base + "/CLIENTSECRET").c_str()), 0); } catch(...) {} try { src.domain = getValue(getKey((base + "/DOMAIN").c_str()), 0); } catch(...) { src.domain = ""; } _AuthSources.push_back(std::move(src)); } if (!indexed && !_AuthUrl.empty()) { // Legacy single mapping AuthSource src; src.url = _AuthUrl; src.clientName = _ClientName; src.clientSecret = _ClientSecret; try { src.domain = getValue(getKey("/BLOGI/AUTHDB/DOMAIN"), 0); } catch(...) { src.domain = ""; } _AuthSources.push_back(std::move(src)); } } catch (...) { // If multi-domain parsing fails, create a single source from legacy fields if (!_AuthUrl.empty()) { if (_AuthSources.empty() && !_AuthUrl.empty()) { AuthSource src; src.url = _AuthUrl; src.clientName = _ClientName; Loading Loading @@ -134,78 +141,72 @@ blogi::Config::Config(const std::string &path) : confplus::Config(path), _Config _MediaDBUrl="https://127.0.0.1:8442"; } // Parse multi-domain configurations // libconfplus YAML stores sequence-of-mappings as flat keys with positional values. // Parse multi-domain configurations. // The libconfplus YAML loader produces a fully indexed tree: each entry of // the DOMAINS sequence lives under /BLOGI/DOMAINS/<i>/... . // Each domain entry MUST define its own DB_DRIVER, DB_CONNECTION, etc. // NAME is an array: one config entry can serve multiple domain names. // No global fallbacks — unconfigured domains get 404. // NAMES is a proper nested sequence: one config entry can serve multiple // domain names. No global fallbacks — unconfigured domains get 404. try { auto *dbDriverKey = getKey("/BLOGI/DOMAINS/DB_DRIVER"); if (!dbDriverKey) throw std::runtime_error("no domains"); size_t domCount = getElements(dbDriverKey); for (size_t i = 0; i < domCount; ++i) { for (size_t i = 0; ; ++i) { std::string base = "/BLOGI/DOMAINS/" + std::to_string(i); auto *domNode = getKey(base.c_str()); if (!domNode) break; // no more domain entries DomainConfig dc; // NAME is stored as a sub-array per domain entry via DOMAINS/NAME // NAME: single primary name for this entry. try { auto *nameKey = getKey("/BLOGI/DOMAINS/NAME"); auto *nameKey = getKey((base + "/NAME").c_str()); if (nameKey) { // In flat config, multiple names for the same domain entry // are stored as comma-separated or as multiple positional values. // With the current YAML parser, each domain entry gets one NAME value, // but we also support NAMES as a separate multi-value key. std::string n = getValue(nameKey, i); std::string n = getValue(nameKey, 0); if (!n.empty()) dc.names.push_back(n); } } catch(...) {} // Additional names via DOMAINS/NAMES (array per domain) // NAMES: nested sequence of additional names for this entry. try { auto *namesKey = getKey("/BLOGI/DOMAINS/NAMES"); auto *namesKey = getKey((base + "/NAMES").c_str()); if (namesKey) { size_t namesCount = getElements(namesKey); for (size_t j = 0; j < namesCount; ++j) { size_t nameCount = getElements(namesKey); for (size_t j = 0; j < nameCount; ++j) { std::string n = getValue(namesKey, j); // Only add names that belong to this domain index // In flat config with seqMapping, all names at index i belong to domain i if (!n.empty()) { if (n.empty()) continue; bool dup = false; for (const auto &existing : dc.names) if (existing == n) { dup = true; break; } if (!dup) dc.names.push_back(n); } } } } catch(...) {} if (dc.names.empty()) continue; try { dc.dbDriver = getValue(dbDriverKey, i); } catch(...) { continue; } try { dc.dbConnection = getValue(getKey("/BLOGI/DOMAINS/DB_CONNECTION"), i); } catch(...) { continue; } try { auto *repKey = getKey("/BLOGI/DOMAINS/DB_REPLICAS"); if (repKey) { // TODO: per-domain replicas if needed } } catch(...) {} try { dc.dbDriver = getValue(getKey((base + "/DB_DRIVER").c_str()), 0); } catch(...) { continue; } try { dc.dbConnection = getValue(getKey((base + "/DB_CONNECTION").c_str()), 0); } catch(...) { continue; } try { dc.authUrl = getValue(getKey("/BLOGI/DOMAINS/AUTH_URL"), i); } catch(...) {} try { dc.clientName = getValue(getKey("/BLOGI/DOMAINS/AUTH_CLIENTNAME"), i); } catch(...) {} try { dc.clientSecret = getValue(getKey("/BLOGI/DOMAINS/AUTH_CLIENTSECRET"), i); } catch(...) {} try { dc.siteUrl = getValue(getKey("/BLOGI/DOMAINS/URL"), i); } catch(...) {} try { dc.authUrl = getValue(getKey((base + "/AUTH_URL").c_str()), 0); } catch(...) {} try { dc.clientName = getValue(getKey((base + "/AUTH_CLIENTNAME").c_str()), 0); } catch(...) {} try { dc.clientSecret = getValue(getKey((base + "/AUTH_CLIENTSECRET").c_str()), 0); } catch(...) {} try { dc.siteUrl = getValue(getKey((base + "/URL").c_str()), 0); } catch(...) {} dc.siteUrls.clear(); if (!dc.siteUrl.empty()) dc.siteUrls.push_back(dc.siteUrl); try { dc.prefix = getValue(getKey("/BLOGI/DOMAINS/PREFIX"), i); } catch(...) {} try { dc.prefix = getValue(getKey((base + "/PREFIX").c_str()), 0); } catch(...) {} if (dc.prefix == "/") dc.prefix = ""; try { dc.templatePath = getValue(getKey("/BLOGI/DOMAINS/TEMPLATE"), i); } catch(...) {} try { dc.startPage = getValue(getKey("/BLOGI/DOMAINS/STARTPAGE"), i); } catch(...) {} try { dc.mediaDBUrl = getValue(getKey("/BLOGI/DOMAINS/MEDIA_URL"), i); } catch(...) {} try { dc.tmpDir = getValue(getKey("/BLOGI/DOMAINS/TMPDIR"), i); } catch(...) { dc.tmpDir = "/tmp/blogi"; } try { dc.templatePath = getValue(getKey((base + "/TEMPLATE").c_str()), 0); } catch(...) {} try { dc.startPage = getValue(getKey((base + "/STARTPAGE").c_str()), 0); } catch(...) {} try { dc.mediaDBUrl = getValue(getKey((base + "/MEDIA_URL").c_str()), 0); } catch(...) {} try { dc.tmpDir = getValue(getKey((base + "/TMPDIR").c_str()), 0); } catch(...) { dc.tmpDir = "/tmp/blogi"; } try { std::string plgdir = getValue(getKey("/BLOGI/DOMAINS/PLUGINDIR"), i); auto *plgKey = getKey((base + "/PLUGINDIR").c_str()); if (plgKey) { size_t plgCount = getElements(plgKey); for (size_t j = 0; j < plgCount; ++j) { std::string plgdir = getValue(plgKey, j); if (!plgdir.empty()) dc.plgDirs.push_back(plgdir); } } } catch(...) {} // Auth source from domain values Loading