#ifndef FACT_DimCtrl #define FACT_DimCtrl #include "Main.h" #include "tools.h" #include "MessageDim.h" #include "RemoteControl.h" using namespace std; // ======================================================================== /* Extract usage clause(s) [if any] for SYNOPSIS. Translators: "Usage" and "or" here are patterns (regular expressions) which are used to match the usage synopsis in program output. An example from cp (GNU coreutils) which contains both strings: Usage: cp [OPTION]... [-T] SOURCE DEST or: cp [OPTION]... SOURCE... DIRECTORY or: cp [OPTION]... -t DIRECTORY SOURCE... */ void PrintUsage() { cout << "\n" "The console connects to all available Dim Servers and allows to " "easily access all of their commands.\n" "\n" "Usage: dimctrl [-c type] [OPTIONS]\n" " or: dimctrl [OPTIONS]\n\n"; cout << endl; } void PrintHelp() { Main::PrintUsage(); } // A simple dummy state machine class DimCtrl : public MainImp, public DimCommandHandler, public MessageDimTX { int fLabel; int fStop; int fVerbosity; bool fDebug; bool fIsServer; DimDescribedService fSrvState; DimCommand fDimStart; DimCommand fDimStop; map fData; string fScript; void ProcessStart() { if (!fScript.empty() || fLabel>=0) { Error("Script execution still in progress."); return; } string opt(fDimStart.getString()); fData = Tools::Split(opt); if (opt.size()>0) Debug("Start '"+opt+"' received."); if (fDebug) Debug("Received data: "+string(fDimStart.getString())); if (opt.size()==0) { if (fData.size()==0) Error("File name missing in DIM_CONTROL/START"); else Error("Equal sign missing in argument '"+fData.begin()->first+"'"); return; } if (fDebug) { for (auto it=fData.begin(); it!=fData.end(); it++) Debug(" Arg: "+it->first+" = "+it->second); } fScript = opt; } void commandHandler() { if (getCommand()==&fDimStop) { Debug("Stop received"); Readline::SetLabel(-2); } if (getCommand()==&fDimStart) ProcessStart(); } public: DimCtrl(ostream &out=cout) : MessageDimTX("DIM_CONTROL", out), fLabel(-3), fStop(false), fVerbosity(0), fDebug(false), fIsServer(false), fSrvState("DIM_CONTROL/STATE", "C", "Provides the state of the state machine as quality of service." "|Text[string]:A human readable string sent by the last state change."), fDimStart("DIM_CONTROL/START", "C", this), fDimStop("DIM_CONTROL/STOP", "", this) { } ~DimCtrl() { DimServer::stop(); } bool check(string &str) { for (auto c=str.begin(); c='A' && *c<='Z') || *c=='_') continue; if (*c++!=':') return false; if (c==str.end()) return false; if (*c!=' ') return false; str = string(c+1, str.end()); return true; } return false; } string Line(const string &txt, char fill) { const int n = (55-txt.length())/2; ostringstream out; out << setfill(fill); out << setw(n) << fill << ' '; out << txt; out << ' ' << setw(n) << fill; if (2*n+txt.length()+2 != 57) out << fill; return out.str(); } int Write(const Time &time, const std::string &txt, int qos=kMessage) { if (txt=="") { fLabel = qos; if (fDebug) { string msg; switch (fLabel) { case -3: msg = Line("End ["+fScript+"]", '='); break; case -2: msg = Line("Load ["+fScript+"]", '='); break; case -1: msg = Line("Begin ["+fScript+"]", '-'); break; default: { ostringstream out; out << "Label " << fLabel << " [" << fScript << "]"; msg = Line(out.str(), '-'); } } MessageDimTX::Write(time, msg, 90); } fSrvState.setQuality(fLabel); switch (fLabel) { case -3: return fSrvState.Update(fScript+" [end]"); case -2: return fSrvState.Update(fScript+" [load]"); case -1: return fSrvState.Update(fScript+" [start]"); } ostringstream msg; msg << fScript << " [label=" << fLabel << "]"; return fSrvState.Update(msg.str()); } if (qos("stop")) return Dim::SendCommand("DIM_CONTROL/STOP") + 1; if (conf.Has("start")) return Dim::SendCommand("DIM_CONTROL/START", conf.Get("start")) + 1; fVerbosity = 40; fIsServer = conf.Get("server"); if (fIsServer) { // Sleep needed to ensure that the server can send // an EXIT if another instance is already running DimServer::start("DIM_CONTROL"); sleep(1); } if (conf.Has("verbosity")) fVerbosity = conf.Get("verbosity"); if (conf.Get("quiet")) fVerbosity = 90; fDebug = conf.Get("debug"); return -1; } void Stop(int stop=1) { fStop = stop; Readline::SetLabel(0); } int Run(bool) { while (!fStop) { const string s = fScript; if (!s.empty()) { Readline::Instance()->Execute(s, fData); fScript = ""; } usleep(1000); } return fStop-1; } }; void SetupConfiguration(Configuration &conf) { po::options_description control("Dim Control"); control.add_options() ("server", po_bool(false), "Start dimctrl as a dim server") ("verbosity,v", var()->implicit_value(0), "Set a new verbosity level (see MessageImp)") ("quiet,q", po_bool(false), "Suppress all output except comments (log-level>=90)") ("debug", po_bool(false), "Print the labels for debugging purpose") ("start", var(), "") ("stop", po_switch(), "") ; conf.AddOptions(control); } int main(int argc, const char *argv[]) { Configuration conf(argv[0]); conf.SetPrintUsage(PrintUsage); Main::SetupConfiguration(conf); SetupConfiguration(conf); if (!conf.DoParse(argc, argv, PrintHelp)) return -1; if (!conf.Has("console")) return Main::execute(conf); if (conf.Get("console")==0) return Main::execute(conf); else return Main::execute(conf); return 0; } #endif