source: trunk/FACT++/src/dimctrl.cc@ 13750

Last change on this file since 13750 was 13734, checked in by tbretz, 13 years ago
Some updates to the messages sent with the STATE service.
File size: 7.8 KB
Line 
1#ifndef FACT_DimCtrl
2#define FACT_DimCtrl
3
4#include "Main.h"
5#include "tools.h"
6#include "MessageDim.h"
7#include "RemoteControl.h"
8
9using namespace std;
10
11// ========================================================================
12
13
14/*
15 Extract usage clause(s) [if any] for SYNOPSIS.
16 Translators: "Usage" and "or" here are patterns (regular expressions) which
17 are used to match the usage synopsis in program output. An example from cp
18 (GNU coreutils) which contains both strings:
19 Usage: cp [OPTION]... [-T] SOURCE DEST
20 or: cp [OPTION]... SOURCE... DIRECTORY
21 or: cp [OPTION]... -t DIRECTORY SOURCE...
22 */
23void PrintUsage()
24{
25 cout << "\n"
26 "The console connects to all available Dim Servers and allows to "
27 "easily access all of their commands.\n"
28 "\n"
29 "Usage: dimctrl [-c type] [OPTIONS]\n"
30 " or: dimctrl [OPTIONS]\n\n";
31 cout << endl;
32}
33
34void PrintHelp()
35{
36 Main::PrintUsage();
37}
38
39// A simple dummy state machine
40class DimCtrl : public MainImp, public DimCommandHandler, public MessageDimTX
41{
42 int fLabel;
43 int fStop;
44 int fVerbosity;
45 bool fDebug;
46 bool fIsServer;
47
48 DimDescribedService fSrvState;
49 DimCommand fDimStart;
50 DimCommand fDimStop;
51
52 map<string,string> fData;
53 string fScript;
54
55 void ProcessStart()
56 {
57 if (!fScript.empty() || fLabel>=0)
58 {
59 Error("Script execution still in progress.");
60 return;
61 }
62
63 string opt(fDimStart.getString());
64
65 fData = Tools::Split(opt);
66
67 if (opt.size()>0)
68 Debug("Start '"+opt+"' received.");
69
70 if (fDebug)
71 Debug("Received data: "+string(fDimStart.getString()));
72
73 if (opt.size()==0)
74 {
75 if (fData.size()==0)
76 Error("File name missing in DIM_CONTROL/START");
77 else
78 Error("Equal sign missing in argument '"+fData.begin()->first+"'");
79
80 return;
81 }
82
83 if (fDebug)
84 {
85 for (auto it=fData.begin(); it!=fData.end(); it++)
86 Debug(" Arg: "+it->first+" = "+it->second);
87 }
88
89 fScript = opt;
90 }
91
92 void commandHandler()
93 {
94 if (getCommand()==&fDimStop)
95 {
96 Debug("Stop received");
97 Readline::SetLabel(-2);
98 }
99
100 if (getCommand()==&fDimStart)
101 ProcessStart();
102 }
103
104public:
105 DimCtrl(ostream &out=cout) : MessageDimTX("DIM_CONTROL", out),
106 fLabel(-3), fStop(false), fVerbosity(0), fDebug(false), fIsServer(false),
107 fSrvState("DIM_CONTROL/STATE", "C",
108 "Provides the state of the state machine as quality of service."
109 "|Text[string]:A human readable string sent by the last state change."),
110 fDimStart("DIM_CONTROL/START", "C", this),
111 fDimStop("DIM_CONTROL/STOP", "", this)
112 {
113 }
114 ~DimCtrl()
115 {
116 DimServer::stop();
117 }
118
119 bool check(string &str)
120 {
121 for (auto c=str.begin(); c<str.end(); c++)
122 {
123 if ((*c>='A' && *c<='Z') || *c=='_')
124 continue;
125
126 if (*c++!=':')
127 return false;
128
129 if (c==str.end())
130 return false;
131
132 if (*c!=' ')
133 return false;
134
135 str = string(c+1, str.end());
136 return true;
137 }
138
139 return false;
140 }
141
142 string Line(const string &txt, char fill)
143 {
144 const int n = (55-txt.length())/2;
145
146 ostringstream out;
147 out << setfill(fill);
148 out << setw(n) << fill << ' ';
149 out << txt;
150 out << ' ' << setw(n) << fill;
151
152 if (2*n+txt.length()+2 != 57)
153 out << fill;
154
155 return out.str();
156 }
157
158 int Write(const Time &time, const std::string &txt, int qos=kMessage)
159 {
160 if (txt=="")
161 {
162 fLabel = qos;
163
164 if (fDebug)
165 {
166 string msg;
167 switch (fLabel)
168 {
169 case -3: msg = Line("End ["+Readline::GetScript()+"]", '='); break;
170 case -2: msg = Line("Load ["+Readline::GetScript()+"]", '='); break;
171 case -1: msg = Line("Begin ["+Readline::GetScript()+"]", '-'); break;
172 default:
173 {
174 ostringstream out;
175 out << "Label " << fLabel << " [" << Readline::GetScript() << "]";
176 msg = Line(out.str(), '-');
177 }
178 }
179
180 MessageDimTX::Write(time, msg, 90);
181 }
182
183 fSrvState.setQuality(fLabel);
184 switch (fLabel)
185 {
186 case -3: return fSrvState.Update(Readline::GetScript()+" [end]");
187 case -2: return fSrvState.Update(Readline::GetScript()+" [load]");
188 case -1: return fSrvState.Update(Readline::GetScript()+" [start]");
189 }
190
191 ostringstream msg;
192 msg << Readline::GetScript() << " [" << fLabel << "]";
193 return fSrvState.Update(msg.str());
194 }
195
196 if (qos<fVerbosity)
197 return 0;
198
199 // Avoid recursions
200 if (fIsServer && txt.substr(0, 13)=="DIM_CONTROL: ")
201 return 0;
202
203 // Don't send received messages via dim
204 string cpy(txt);
205 if (fIsServer && check(cpy))
206 return MessageImp::Write(time, cpy, qos);
207
208 // Send all of our own messages via dim
209 return MessageDimTX::Write(time, txt, qos);
210 }
211
212 int EvalOptions(Configuration &conf)
213 {
214 fVerbosity = 90;
215
216 if (conf.Get<bool>("stop"))
217 return Dim::SendCommand("DIM_CONTROL/STOP") + 1;
218
219 if (conf.Has("start"))
220 return Dim::SendCommand("DIM_CONTROL/START", conf.Get<string>("start")) + 1;
221
222 fVerbosity = 40;
223
224 fIsServer = conf.Get<bool>("server");
225 if (fIsServer)
226 {
227 // Sleep needed to ensure that the server can send
228 // an EXIT if another instance is already running
229 DimServer::start("DIM_CONTROL");
230 sleep(1);
231 fSrvState.setQuality(-3);
232 fSrvState.Update("[boot]");
233 }
234
235 if (conf.Has("verbosity"))
236 fVerbosity = conf.Get<uint32_t>("verbosity");
237
238 if (conf.Get<bool>("quiet"))
239 fVerbosity = 90;
240
241 fDebug = conf.Get<bool>("debug");
242
243 return -1;
244 }
245
246 void Stop(int stop=1) { fStop = stop; Readline::SetLabel(0); }
247 int Run(bool)
248 {
249 while (!fStop)
250 {
251 const string s = fScript;
252 if (!s.empty())
253 {
254 Readline::Instance()->Execute(s, fData);
255 fScript = "";
256 }
257
258 usleep(1000);
259 }
260 return fStop-1; }
261};
262
263void SetupConfiguration(Configuration &conf)
264{
265 po::options_description control("Dim Control");
266 control.add_options()
267 ("server", po_bool(false), "Start dimctrl as a dim server")
268 ("verbosity,v", var<uint32_t>()->implicit_value(0), "Set a new verbosity level (see MessageImp)")
269 ("quiet,q", po_bool(false), "Suppress all output except comments (log-level>=90)")
270 ("debug", po_bool(false), "Print the labels for debugging purpose")
271 ("start", var<string>(), "")
272 ("stop", po_switch(), "")
273 ;
274
275 conf.AddOptions(control);
276}
277
278int main(int argc, const char *argv[])
279{
280 Configuration conf(argv[0]);
281 conf.SetPrintUsage(PrintUsage);
282 Main::SetupConfiguration(conf);
283 SetupConfiguration(conf);
284
285 if (!conf.DoParse(argc, argv, PrintHelp))
286 return -1;
287
288 if (!conf.Has("console"))
289 return Main::execute<RemoteStream, DimCtrl>(conf);
290
291 if (conf.Get<int>("console")==0)
292 return Main::execute<RemoteShell, DimCtrl>(conf);
293 else
294 return Main::execute<RemoteConsole, DimCtrl>(conf);
295
296 return 0;
297}
298#endif
Note: See TracBrowser for help on using the repository browser.