Commit d01e7d0c authored by jan.koester's avatar jan.koester
Browse files

replica config

parent d29560a2
Loading
Loading
Loading
Loading
+9 −0
Original line number Diff line number Diff line
@@ -15,6 +15,12 @@ BLOGI:
  DATABASE:
    DRIVER: "sqlite"
    CONNECTION: "/var/lib/blogi/blog.db"
    # Replication: writes are sent to primary AND all replicas
    # REPLICAS:
    #   - DRIVER: "pqxx"
    #     CONNECTION: "host=replica1.example.com dbname=blogi user=blogi"
    #   - DRIVER: "sqlite"
    #     CONNECTION: "/var/lib/blogi/blog-backup.db"
  AUTHDB:
    - URL: "https://auth.example.com"
      CLIENTNAME: "blogiclient"
@@ -52,6 +58,9 @@ BLOGI:
      DATABASE:
        DRIVER: "sqlite"
        CONNECTION: "/var/lib/blogi/blog-example.db"
        # REPLICAS:
        #   - DRIVER: "pqxx"
        #     CONNECTION: "host=replica.example.com dbname=blogi user=blogi"
      TEMPLATE: "/usr/local/share/blogi/themes/default"
      STARTPAGE: "/blog/content/index"
      HTTP:
+21 −3
Original line number Diff line number Diff line
@@ -101,6 +101,7 @@ blogi::Blogi::Blogi(std::vector<netplus::socket*> serversocket,bool debug) : Htt

    // Helper to initialize a DomainContext
    auto initCtx = [&](DomainContext &ctx, const std::string &dbDriver, const std::string &dbOpts,
                       const std::vector<ReplicaConfig> &replicas,
                       const std::string &authUrl, const std::string &clientName, const std::string &clientSecret,
                       const std::vector<AuthSource> &authSources,
                       const std::string &templatePath, const std::vector<std::string> &plgDirs,
@@ -116,9 +117,16 @@ blogi::Blogi::Blogi(std::vector<netplus::socket*> serversocket,bool debug) : Htt

        try {
            for (int i = 0; i < threads; i++) {
                ctx.plgArgs->database.emplace_back(
                    std::make_unique<dbpp::ReplicatedDatabase>(dbDriver, dbOpts)
                );
                auto db = std::make_unique<dbpp::ReplicatedDatabase>(dbDriver, dbOpts);
                for (const auto &rep : replicas) {
                    try {
                        db->addReplica(rep.driver, rep.connection);
                        std::cerr << "  Added replica: " << rep.driver << " on " << rep.connection << std::endl;
                    } catch (const std::exception &e) {
                        std::cerr << "  Failed to add replica (" << rep.connection << "): " << e.what() << std::endl;
                    }
                }
                ctx.plgArgs->database.emplace_back(std::move(db));
            }
        } catch(std::runtime_error &e) {
            std::cerr << "can't connect db for domain '" << domainName << "' reason: " << e.what() << std::endl;
@@ -126,6 +134,9 @@ blogi::Blogi::Blogi(std::vector<netplus::socket*> serversocket,bool debug) : Htt
        }

        std::unique_ptr<dbpp::ReplicatedDatabase> initdb = std::make_unique<dbpp::ReplicatedDatabase>(dbDriver, dbOpts);
        for (const auto &rep : replicas) {
            try { initdb->addReplica(rep.driver, rep.connection); } catch (...) {}
        }

        Session sess(*initdb);
        sess._initSession();
@@ -199,6 +210,7 @@ blogi::Blogi::Blogi(std::vector<netplus::socket*> serversocket,bool debug) : Htt
            const DomainConfig &dcfg = Blogi::Cfg->getDomainConfig(d);
            auto ctx = std::make_unique<DomainContext>();
            initCtx(*ctx, dcfg.dbDriver, dcfg.dbConnection,
                    dcfg.dbReplicas,
                    dcfg.authUrl, dcfg.clientName, dcfg.clientSecret,
                    dcfg.authSources,
                    dcfg.templatePath, dcfg.plgDirs,
@@ -214,6 +226,12 @@ blogi::Blogi::Blogi(std::vector<netplus::socket*> serversocket,bool debug) : Htt
    {
        _defaultCtx = std::make_unique<DomainContext>();
        initCtx(*_defaultCtx, Blogi::Cfg->getdbdriver(), Blogi::Cfg->getdbopts(),
                [&]() -> std::vector<ReplicaConfig> {
                    std::vector<ReplicaConfig> reps;
                    for (size_t i = 0; i < Blogi::Cfg->getReplicaCount(); ++i)
                        reps.push_back(Blogi::Cfg->getReplica(i));
                    return reps;
                }(),
                Blogi::Cfg->getAuthUrl(), Blogi::Cfg->getClientName(), Blogi::Cfg->getClientSecret(),
                std::vector<AuthSource>(),
                Blogi::Cfg->gettemplate(),
+38 −0
Original line number Diff line number Diff line
@@ -36,6 +36,20 @@ blogi::Config::Config(const std::string &path) : confplus::Config(path){

    _DBDriver=getValue(getKey("/BLOGI/DATABASE/DRIVER"),0);
    _DBConnection=getValue(getKey("/BLOGI/DATABASE/CONNECTION"),0);

    // Parse global database replicas
    try {
        auto *repKey = getKey("/BLOGI/DATABASE/REPLICAS");
        size_t repCount = getElements(repKey);
        for (size_t i = 0; i < repCount; ++i) {
            ReplicaConfig rc;
            std::string repBase = "/BLOGI/DATABASE/REPLICAS/" + std::to_string(i);
            try { rc.driver = getValue(getKey((repBase + "/DRIVER").c_str()), 0); } catch(...) { rc.driver = _DBDriver; }
            try { rc.connection = getValue(getKey((repBase + "/CONNECTION").c_str()), 0); } catch(...) { continue; }
            _DBReplicas.push_back(std::move(rc));
        }
    } catch(...) {}

    _AuthUrl=getValue(getKey("/BLOGI/AUTHDB/URL"),0);
    _ClientName=getValue(getKey("/BLOGI/AUTHDB/CLIENTNAME"),0);
    _ClientSecret=getValue(getKey("/BLOGI/AUTHDB/CLIENTSECRET"),0);
@@ -128,6 +142,22 @@ blogi::Config::Config(const std::string &path) : confplus::Config(path){
            try { dc.name = getValue(getKey((basePath + "/NAME").c_str()), 0); } catch(...) { continue; }
            try { dc.dbDriver = getValue(getKey((basePath + "/DATABASE/DRIVER").c_str()), 0); } catch(...) { dc.dbDriver = _DBDriver; }
            try { dc.dbConnection = getValue(getKey((basePath + "/DATABASE/CONNECTION").c_str()), 0); } catch(...) { dc.dbConnection = _DBConnection; }

            // Parse per-domain database replicas
            try {
                auto *repKey = getKey((basePath + "/DATABASE/REPLICAS").c_str());
                size_t repCount = getElements(repKey);
                for (size_t r = 0; r < repCount; ++r) {
                    ReplicaConfig rc;
                    std::string repBase = basePath + "/DATABASE/REPLICAS/" + std::to_string(r);
                    try { rc.driver = getValue(getKey((repBase + "/DRIVER").c_str()), 0); } catch(...) { rc.driver = dc.dbDriver; }
                    try { rc.connection = getValue(getKey((repBase + "/CONNECTION").c_str()), 0); } catch(...) { continue; }
                    dc.dbReplicas.push_back(std::move(rc));
                }
            } catch(...) {
                dc.dbReplicas = _DBReplicas;
            }

            try { dc.authUrl = getValue(getKey((basePath + "/AUTHDB/URL").c_str()), 0); } catch(...) { dc.authUrl = _AuthUrl; }
            try { dc.clientName = getValue(getKey((basePath + "/AUTHDB/CLIENTNAME").c_str()), 0); } catch(...) { dc.clientName = _ClientName; }
            try { dc.clientSecret = getValue(getKey((basePath + "/AUTHDB/CLIENTSECRET").c_str()), 0); } catch(...) { dc.clientSecret = _ClientSecret; }
@@ -216,6 +246,14 @@ const std::string & blogi::Config::getdbopts() const {
    return _DBConnection;
}

size_t blogi::Config::getReplicaCount() const {
    return _DBReplicas.size();
}

const blogi::ReplicaConfig &blogi::Config::getReplica(size_t idx) const {
    return _DBReplicas[idx];
}

const std::string & blogi::Config::getAuthUrl() const {
    return _AuthUrl;
}
+9 −0
Original line number Diff line number Diff line
@@ -46,10 +46,16 @@ namespace blogi {
        std::string domain;
    };

    struct ReplicaConfig {
        std::string driver;
        std::string connection;
    };

    struct DomainConfig {
        std::string               name;
        std::string               dbDriver;
        std::string               dbConnection;
        std::vector<ReplicaConfig> dbReplicas;
        std::string               authUrl;
        std::string               clientName;
        std::string               clientSecret;
@@ -87,6 +93,8 @@ namespace blogi {

        const std::string &getdbdriver() const;
        const std::string &getdbopts() const;
        size_t getReplicaCount() const;
        const ReplicaConfig &getReplica(size_t idx) const;

        const std::string &getAuthUrl() const;
        const std::string &getClientName() const;
@@ -119,6 +127,7 @@ namespace blogi {
        std::vector<std::string>  _PlgDir;
        std::string               _DBDriver;
        std::string               _DBConnection;
        std::vector<ReplicaConfig> _DBReplicas;
        std::string               _AuthUrl;
        std::string               _ClientName;
        std::string               _ClientSecret;