X-Git-Url: https://git.pterodactylus.net/?a=blobdiff_plain;f=src%2Ffmsapp.cpp;h=2daf6c817304d252eed8064e4ecb5a9d3c8fc5c1;hb=59a5414ec47a2932a7802fcd1d98c4d80166564f;hp=810bd5f3e9c07dc7c67fe7c091047c2400d150ce;hpb=dec33c63afafabf83c3039e916725cac6faef9b3;p=fms.git diff --git a/src/fmsapp.cpp b/src/fmsapp.cpp index 810bd5f..2daf6c8 100644 --- a/src/fmsapp.cpp +++ b/src/fmsapp.cpp @@ -9,12 +9,16 @@ #include "../include/dbmaintenancethread.h" #include "../include/freenet/freenetmasterthread.h" #include "../include/threadwrapper/threadedexecutor.h" +#include "../include/db/sqlite3db.h" #include #include +#include #include #include #include +#include +#include #ifdef _WIN32 #include @@ -22,30 +26,17 @@ #include #endif -//debug -#include -#include -#include -#include -#include "../include/threadwrapper/cancelablerunnable.h" -#include "../include/threadwrapper/cancelablethread.h" - -Poco::FastMutex m1; -class TestRunner:public CancelableRunnable +FMSApp::FMSApp():m_displayhelp(false),m_showoptions(false),m_setoption(false),m_logtype("file"),m_workingdirectory("") { -public: - void run() + // get current working dir so we can go to it later + char wd[1024]; + char *wdptr=NULL; + memset(wd,0,1024); + wdptr=getcwd(wd,1023); + if(wdptr) { - do - { - - }while(!IsCancelled()); + m_workingdirectory=wdptr; } -}; - -FMSApp::FMSApp():m_displayhelp(false) -{ - } void FMSApp::defineOptions(Poco::Util::OptionSet &options) @@ -53,7 +44,10 @@ void FMSApp::defineOptions(Poco::Util::OptionSet &options) ServerApplication::defineOptions(options); // add command line options here - options.addOption(Poco::Util::Option("help","?","display help for command line arguments",false).repeatable(false).callback(Poco::Util::OptionCallback(this,&FMSApp::handleHelp))); + options.addOption(Poco::Util::Option("help","?","Display help for command line arguments.",false).repeatable(false).callback(Poco::Util::OptionCallback(this,&FMSApp::handleHelp))); + options.addOption(Poco::Util::Option("log","l","Select type of log output (file|stdout|stderr).",false,"type",true).repeatable(false).callback(Poco::Util::OptionCallback(this,&FMSApp::handleLogOption))); + options.addOption(Poco::Util::Option("showoptions","","Show all options that can be set and their current values.",false).repeatable(false).callback(Poco::Util::OptionCallback(this,&FMSApp::handleShowOptions))); + options.addOption(Poco::Util::Option("setoption","","Set an option. Values are not validated, so be sure to set them correctly.",false,"option=value",true).repeatable(true).callback(Poco::Util::OptionCallback(this,&FMSApp::handleSetOption))); } void FMSApp::displayHelp() @@ -72,15 +66,65 @@ void FMSApp::handleHelp(const std::string &name, const std::string &value) stopOptionsProcessing(); } +void FMSApp::handleLogOption(const std::string &name, const std::string &value) +{ + if(value=="file" || value=="stdout" || value=="stderr") + { + m_logtype=value; + } +} + +void FMSApp::handleSetOption(const std::string &name, const std::string &value) +{ + std::vector valueparts; + StringFunctions::Split(value,"=",valueparts); + + if(valueparts.size()==2) + { + m_setoptions[valueparts[0]]=valueparts[1]; + } + else + { + std::cout << "Expected option=value but found " << value << std::endl; + } + + m_setoption=true; +} + +void FMSApp::handleShowOptions(const std::string &name, const std::string &value) +{ + m_showoptions=true; +} + void FMSApp::initialize(Poco::Util::Application &self) { ServerApplication::initialize(self); - // set working directory to program directory - int rval=chdir(config().getString("application.dir").c_str()); + // set working directory - fall back on application.dir if working directory isn't set + // if we are runing as a service, then working directory needs to be set to the application directory + if(m_workingdirectory=="" || config().getBool("application.runAsService",false)==true) + { + m_workingdirectory=config().getString("application.dir"); + } + int rval=chdir(m_workingdirectory.c_str()); + +#ifdef QUERY_LOG + { + Poco::AutoPtr formatter=new Poco::FormattingChannel(new Poco::PatternFormatter("%Y-%m-%d %H:%M:%S | %t")); + Poco::AutoPtr fc=new Poco::FileChannel("query.log"); + fc->setProperty("rotation","daily"); + fc->setProperty("times","utc"); + fc->setProperty("archive","timestamp"); + fc->setProperty("purgeCount","5"); + fc->setProperty("compress","true"); + formatter->setChannel(fc); + Poco::Logger::create("querylog",formatter,Poco::Message::PRIO_INFORMATION); + } +#endif - SetupDB(); - SetupDefaultOptions(); + LoadDatabase(); + SetupDB(m_db); + SetupDefaultOptions(m_db); initializeLogger(); config().setString("application.logger","logfile"); } @@ -90,35 +134,99 @@ void FMSApp::initializeLogger() int initiallevel=Poco::Message::PRIO_TRACE; std::string tempval=""; - if(Option::Instance()->Get("LogLevel",tempval)) + Option option(m_db); + + if(option.Get("LogLevel",tempval)) { StringFunctions::Convert(tempval,initiallevel); } Poco::AutoPtr formatter=new Poco::FormattingChannel(new Poco::PatternFormatter("%Y-%m-%d %H:%M:%S | %p | %t")); - Poco::AutoPtr fc=new Poco::FileChannel("fms.log"); - fc->setProperty("rotation","daily"); // rotate log file daily - fc->setProperty("times","utc"); // utc date/times for log entries - fc->setProperty("archive","timestamp"); // add timestamp to old logs - fc->setProperty("purgeCount","30"); // purge old logs after 30 logs have accumulated - fc->setProperty("compress","true"); // gz compress old log files - formatter->setChannel(fc); - setLogger(Poco::Logger::create("logfile",formatter,initiallevel)); + if(m_logtype=="file") + { + Poco::AutoPtr fc=new Poco::FileChannel("fms.log"); + fc->setProperty("rotation","daily"); // rotate log file daily + fc->setProperty("times","utc"); // utc date/times for log entries + fc->setProperty("archive","timestamp"); // add timestamp to old logs + fc->setProperty("purgeCount","30"); // purge old logs after 30 logs have accumulated + fc->setProperty("compress","true"); // gz compress old log files + formatter->setChannel(fc); + } + else + { + if(m_logtype=="stdout") + { + Poco::AutoPtr cc=new Poco::ConsoleChannel(std::cout); + formatter->setChannel(cc); + } + else + { + Poco::AutoPtr cc=new Poco::ConsoleChannel(std::cerr); + formatter->setChannel(cc); + } + } + + setLogger(Poco::Logger::create("logfile",formatter,Poco::Message::PRIO_INFORMATION)); + Poco::Logger::get("logfile").information("LogLevel set to "+tempval); + Poco::Logger::get("logfile").setLevel(initiallevel); + } int FMSApp::main(const std::vector &args) { - if(m_displayhelp==false) + // running as a daemon would reset the working directory to / before calling main + // so we need to set the working directory again + int rval=chdir(m_workingdirectory.c_str()); + + if(VerifyDB(m_db)==false) + { + std::cout << "The FMS database failed verification. It is most likely corrupt!" << std::endl; + logger().fatal("The FMS database failed verification. It is most likely corrupt!"); + } + else if(m_displayhelp) + { + } + else if(m_showoptions) + { + showOptions(); + } + else if(m_setoption) + { + setOptions(); + } + else { logger().information("FMS startup v"FMS_VERSION); + logger().information("Using SQLite "SQLITE_VERSION); + + std::string tempval(""); + Option option(m_db); + option.Get("VacuumOnStartup",tempval); + if(tempval=="true") + { + logger().information("VACUUMing database"); + m_db->Execute("VACUUM;"); + } StartThreads(); + if(isInteractive()==true) + { + std::cout << "FMS has been started." << std::endl << std::endl; + } + waitForTerminationRequest(); + if(isInteractive()==true) + { + std::cout << "Please wait while FMS shuts down." << std::endl << std::endl; + } + + logger().trace("FMSApp::main cancelling threads"); m_threads.Cancel(); + logger().trace("FMSApp::main joining threads"); m_threads.Join(); logger().information("FMS shutdown"); @@ -127,31 +235,95 @@ int FMSApp::main(const std::vector &args) return FMSApp::EXIT_OK; } +void FMSApp::setOptions() +{ + for(std::map::iterator i=m_setoptions.begin(); i!=m_setoptions.end(); i++) + { + std::string tempval(""); + Option option(m_db); + if(option.Get((*i).first,tempval)) + { + option.Set((*i).first,(*i).second); + std::cout << "Option " << (*i).first << " set to " << (*i).second << std::endl; + } + else + { + std::cout << "Unknown option " << (*i).first << std::endl; + } + } +} + +void FMSApp::showOptions() +{ + SQLite3DB::Statement st=m_db->Prepare("SELECT Option, OptionValue FROM tblOption;"); + st.Step(); + while(st.RowReturned()) + { + std::string option=""; + std::string optionvalue=""; + st.ResultText(0,option); + st.ResultText(1,optionvalue); + + std::cout << option << " = " << optionvalue << std::endl; + + st.Step(); + } +} + void FMSApp::StartThreads() { - std::string tempval=""; + std::string tempval(""); + Option option(m_db); // always start the DB maintenance thread + logger().trace("FMSApp::StartThreads starting DBMaintenanceThread"); m_threads.Start(new DBMaintenanceThread()); - Option::Instance()->Get("StartHTTP",tempval); + option.Get("StartHTTP",tempval); if(tempval=="true") { + logger().trace("FMSApp::StartThreads starting HTTPThread"); m_threads.Start(new HTTPThread()); + if(isInteractive()) + { + std::cout << "Started HTTP Thread" << std::endl; + } + } + else + { + logger().trace("FMSApp::StartThreads not starting HTTPThread"); } tempval=""; - Option::Instance()->Get("StartNNTP",tempval); + option.Get("StartNNTP",tempval); if(tempval=="true") { + logger().trace("FMSApp::StartThreads starting NNTPListener"); m_threads.Start(new NNTPListener()); + if(isInteractive()) + { + std::cout << "Started NNTP Thread" << std::endl; + } + } + else + { + logger().trace("FMSApp::StartThreads not starting NNTPListener"); } tempval=""; - Option::Instance()->Get("StartFreenetUpdater",tempval); + option.Get("StartFreenetUpdater",tempval); if(tempval=="true") { + logger().trace("FMSApp::StartThreads starting FreenetMasterThread"); m_threads.Start(new FreenetMasterThread()); + if(isInteractive()) + { + std::cout << "Started Freenet FCP Thread" << std::endl; + } + } + else + { + logger().trace("FMSApp::StartThreads not starting FreenetMasterThread"); } }