// rdrepld.cpp // // The Rivendell Replicator Daemon // // (C) Copyright 2010-2019 Fred Gleason // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License version 2 as // published by the Free Software Foundation. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public // License along with this program; if not, write to the Free Software // Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. // #include #include #include #include #include #include #include #include #include #include #include #include #include #include "citadelxds.h" #include "rdrepld.h" void SigHandler(int signum) { pid_t local_pid; switch(signum) { case SIGINT: case SIGTERM: RDDeletePid(RD_PID_DIR,"rdrepld.pid"); exit(0); break; case SIGCHLD: local_pid=waitpid(-1,NULL,WNOHANG); while(local_pid>0) { local_pid=waitpid(-1,NULL,WNOHANG); } signal(SIGCHLD,SigHandler); return; } } MainObject::MainObject(QObject *parent) :QObject(parent) { QString err_msg; RDApplication::ErrorType err_type=RDApplication::ErrorOk; debug=false; // // Open the Database // rda=new RDApplication("rdrepld","rdrepld",RDREPLD_USAGE,this); if(!rda->open(&err_msg,&err_type,false)) { fprintf(stderr,"rdrepld: %s\n",(const char *)err_msg); exit(1); } // // Read Command Options // for(unsigned i=0;icmdSwitch()->keys();i++) { if(rda->cmdSwitch()->key(i)=="-d") { debug=true; rda->cmdSwitch()->setProcessed(i,true); } if(!rda->cmdSwitch()->processed(i)) { fprintf(stderr,"rdrepld: unknown command option \"%s\"\n", (const char *)rda->cmdSwitch()->key(i)); exit(2); } } // // Calculate Temporary Directory // repl_temp_dir=RDTempDirectory::basePath(); // connect(RDDbStatus(), // SIGNAL(logText(RDConfig::LogPriority,const QString &)), // this,SLOT(log(RDConfig::LogPriority,const QString &))); if(qApp->argc()!=1) { debug=true; } ::signal(SIGINT,SigHandler); ::signal(SIGTERM,SigHandler); ::signal(SIGCHLD,SigHandler); if(!RDWritePid(RD_PID_DIR,"rdrepld.pid")) { fprintf(stderr,"rdrepld: aborting - can't write pid file\n"); exit(1); } // // Start the Main Loop // repl_loop_timer=new QTimer(this); connect(repl_loop_timer,SIGNAL(timeout()),this,SLOT(mainLoop())); repl_loop_timer->start(RD_RDREPL_SCAN_INTERVAL,true); rda->syslog(LOG_INFO,"started"); } void MainObject::mainLoop() { LoadReplicators(); ProcessCarts(); FreeReplicators(); repl_loop_timer->start(RD_RDREPL_SCAN_INTERVAL,true); } void MainObject::ProcessCarts() { QString sql; RDSqlQuery *q; RDSqlQuery *q1; RDSqlQuery *q2; QString repl_name; QString where; bool stale; for(unsigned i=0;iconfig()->name(); sql=QString("select GROUP_NAME from REPLICATOR_MAP where ")+ "REPLICATOR_NAME=\""+RDEscapeString(repl_name)+"\""; q=new RDSqlQuery(sql); while(q->next()) { where+=QString("(GROUP_NAME=\"")+ RDEscapeString(q->value(0).toString())+"\")||"; } delete q; where=where.left(where.length()-2); sql=QString("select ")+ "NUMBER,"+ // 00 "TYPE,"+ // 01 "METADATA_DATETIME "+ // 02 "from CART where "+ where; q=new RDSqlQuery(sql); while(q->next()) { sql=QString("select ")+ "ID,"+ // 00 "ITEM_DATETIME "+ // 01 "from REPL_CART_STATE where "+ "(REPLICATOR_NAME=\""+RDEscapeString(repl_name)+"\")&&"+ QString().sprintf("(CART_NUMBER=%u)",q->value(0).toUInt()); q1=new RDSqlQuery(sql); if(q1->first()) { stale=q->value(2).toDateTime()>q1->value(1).toDateTime(); } else { stale=true; } if(stale) { if(repl_replicators[i]->processCart(q->value(0).toUInt())) { if(q1->isValid()) { sql=QString("update REPL_CART_STATE set ")+ "ITEM_DATETIME=now() where "+ QString().sprintf("ID=%u",q1->value(0).toUInt()); } else { sql=QString("insert into REPL_CART_STATE set ")+ "REPLICATOR_NAME=\""+RDEscapeString(repl_name)+"\","+ QString().sprintf("CART_NUMBER=%u,",q->value(0).toUInt())+ "ITEM_DATETIME=now()"; } q2=new RDSqlQuery(sql); delete q2; } } delete q1; } delete q; } } void MainObject::LoadReplicators() { QString sql; RDSqlQuery *q; ReplConfig *config; sql=QString("select ")+ "NAME,"+ // 00 "TYPE_ID,"+ // 01 "FORMAT,"+ // 02 "CHANNELS,"+ // 03 "SAMPRATE,"+ // 04 "BITRATE,"+ // 05 "QUALITY,"+ // 06 "URL,"+ // 07 "URL_USERNAME,"+ // 08 "URL_PASSWORD,"+ // 09 "ENABLE_METADATA,"+ // 10 "NORMALIZATION_LEVEL "+ // 11 "from REPLICATORS where "+ "STATION_NAME=\""+RDEscapeString(rda->config()->stationName())+"\""; q=new RDSqlQuery(sql); while(q->next()) { config=new ReplConfig(); config->setName(q->value(0).toString()); config->setType((RDReplicator::Type)q->value(1).toUInt()); config->setFormat((RDSettings::Format)q->value(2).toUInt()); config->setChannels(q->value(3).toUInt()); config->setSampleRate(q->value(4).toUInt()); config->setBitRate(q->value(5).toUInt()); config->setQuality(q->value(6).toUInt()); config->setUrl(q->value(7).toString()); config->setUrlUsername(q->value(8).toString()); config->setUrlPassword(q->value(9).toString()); config->setEnableMetadata(RDBool(q->value(10).toString())); config->setNormalizeLevel(q->value(11).toInt()); switch(config->type()) { case RDReplicator::TypeCitadelXds: repl_replicators.push_back(new CitadelXds(config)); break; case RDReplicator::TypeLast: break; } repl_replicators.back()->startProcess(); } delete q; } void MainObject::FreeReplicators() { for(unsigned i=0;i