source: trunk/FACT++/src/StateMachineDimControl.cc@ 14404

Last change on this file since 14404 was 14370, checked in by tbretz, 12 years ago
Adapted ChangeState to properly send informations; adapted Write to keep mssages in sync; renamed DIM_CONTROL2 to DIM_CONTROL
File size: 14.1 KB
Line 
1#include "StateMachineDimControl.h"
2
3#include "Dim.h"
4#include "Event.h"
5#include "RemoteControl.h"
6#include "Configuration.h"
7#include "Converter.h"
8
9using namespace std;
10
11// ------------------------------------------------------------------------
12
13bool StateMachineDimControl::fIsServer = false;
14
15string StateMachineDimControl::Line(const string &txt, char fill)
16{
17 const int n = (55-txt.length())/2;
18
19 ostringstream out;
20 out << setfill(fill);
21 out << setw(n) << fill << ' ';
22 out << txt;
23 out << ' ' << setw(n) << fill;
24
25 if (2*n+txt.length()+2 != 57)
26 out << fill;
27
28 return out.str();
29}
30
31int StateMachineDimControl::ChangeState(int qos, const Time &time, int scriptdepth, string scriptfile, string user)
32{
33 string msg;
34 /*
35 switch (qos)
36 {
37 case -3: msg = "End"; break;
38 case -2: msg = "Load"; break;
39 case -1: msg = "Start"; break;
40 default:
41 {
42 ostringstream out;
43 out << "Label " << qos;
44 msg = out.str();
45 }
46 }
47 */
48
49 //if (qos<0)
50 msg += to_string(scriptdepth);
51
52 msg += ":"+scriptfile+"["+user+":"+to_string(getpid())+"]";
53
54 //if (fDebug)
55 //Write(time, Line(msg, qos<-1 ? '=' :'-'), MessageImp::kInternal);
56
57 if (qos==-3)
58 fScriptUser = fUser;
59
60 SetCurrentState(qos+3, msg.c_str());
61 //SetCurrentState(qos+3, Line(msg, qos<-1 ? '=' :'-').c_str());
62 return GetCurrentState();
63
64 //return qos+3;
65}
66
67int StateMachineDimControl::Write(const Time &time, const std::string &txt, int qos)
68{
69 if (txt=="")
70 {
71 return ChangeState(qos, time, Readline::GetScriptDepth(), Readline::GetScript(), fScriptUser);
72 /*
73 === This might be necessary for thread safety,
74 === but it break that the signal for the start of a new
75 === script arrives synchronously before the first output
76 === from the script
77
78 // Post an anonymous event to the event loop
79 Event evt("");
80 evt.AssignFunction(bind(&StateMachineDimControl::ChangeState, this,
81 qos, time, Readline::GetScriptDepth(),
82 Readline::GetScript(), fScriptUser));
83 return PostEvent(evt);
84 */
85 }
86
87 // if (qos<fVerbosity)
88 // return 0;
89
90 return StateMachineDim::Write(time, txt, qos);
91}
92
93int StateMachineDimControl::StartScript(const EventImp &imp, const string &cmd)
94{
95 string opt(imp.GetString());
96
97 const map<string,string> data = Tools::Split(opt, true);
98
99 if (imp.GetSize()==0 || opt.size()==0 || opt[0]==0)
100 {
101 Error("File name missing in DIM_CONTROL/START");
102 return GetCurrentState();
103 }
104
105 if (fDebug)
106 Debug("Start '"+opt+"' received.");
107
108 if (fDebug)
109 Debug("Received data: "+imp.GetString());
110
111 const auto user = data.find("user");
112 fScriptUser = user==data.end() ? fUser : user->second;
113
114 if (fDebug)
115 {
116 for (auto it=data.begin(); it!=data.end(); it++)
117 Debug(" Arg: "+it->first+" = "+it->second);
118 }
119
120 Readline::SetExternalInput(cmd+imp.GetString());
121 return 1;
122}
123
124int StateMachineDimControl::StopScript()
125{
126 Readline::StopScript();
127 InterpreterV8::JsStop();
128 return GetCurrentState();
129}
130
131void StateMachineDimControl::SendDimCommand(const string &server, string str, ostream &lout)
132{
133 const lock_guard<mutex> guard(fMutex);
134
135 if (fServerList.find(server)==fServerList.end())
136 throw runtime_error("Server '"+server+"' not online.");
137
138 str = Tools::Trim(str);
139
140 // Find the delimiter between the command name and the data
141 size_t p0 = str.find_first_of(' ');
142 if (p0==string::npos)
143 p0 = str.length();
144
145 // Get just the command name separated from the data
146 const string name = str.substr(0, p0);
147
148 // Compile the command which will be sent to the state-machine
149 for (auto is=fServiceList.begin(); is!=fServiceList.end(); is++)
150 {
151 if (is->server!=server || is->service!=name)
152 continue;
153
154 if (!is->iscmd)
155 throw runtime_error("'"+server+"/"+name+" not a command.");
156
157 // Avoid compiler warning of unused parameter
158 lout << flush;
159
160 // Convert the user entered data according to the format string
161 // into a data block which will be attached to the event
162#ifndef DEBUG
163 ostringstream sout;
164 const Converter conv(sout, is->format, false);
165#else
166 const Converter conv(lout, is->format, false);
167#endif
168 if (!conv)
169 throw runtime_error("Couldn't properly parse the format... ignored.");
170
171#ifdef DEBUG
172 lout << kBlue << server << '/' << name;
173#endif
174 const vector<char> v = conv.GetVector(str.substr(p0));
175#ifdef DEBUG
176 lout << kBlue << " [" << v.size() << "]" << endl;
177#endif
178 const string cmd = server + '/' + name;
179 const int rc = DimClient::sendCommand(cmd.c_str(), (void*)v.data(), v.size());
180 if (!rc)
181 throw runtime_error("ERROR - Sending command "+cmd+" failed.");
182
183 return;
184 }
185
186 throw runtime_error("Unkown server '"+server+"'");
187}
188
189int StateMachineDimControl::PrintStates(std::ostream &out, const std::string &serv)
190{
191 const lock_guard<mutex> guard(fMutex);
192
193 int rc = 0;
194 for (auto it=fServerList.begin(); it!=fServerList.end(); it++)
195 {
196 if (!serv.empty() && *it!=serv)
197 continue;
198
199 out << kRed << "----- " << *it << " -----" << endl;
200
201 int cnt = 0;
202 for (auto is=fStateDescriptionList.begin(); is!=fStateDescriptionList.end(); is++)
203 {
204 const string &server = is->first.first;
205
206 if (server!=*it)
207 continue;
208
209 const int32_t &state = is->first.second;
210 const string &name = is->second.first;
211 const string &comment = is->second.second;
212
213 out << kBold << setw(5) << state << kReset << ": ";
214 out << kYellow << name;
215 if (!comment.empty())
216 out << kBlue << " (" << comment << ")";
217 out << endl;
218
219 cnt++;
220 }
221
222 if (cnt==0)
223 out << " <no states>" << endl;
224 else
225 rc++;
226
227 out << endl;
228 }
229
230 return rc;
231}
232
233int StateMachineDimControl::PrintDescription(std::ostream &out, bool iscmd, const std::string &serv, const std::string &service)
234{
235 const lock_guard<mutex> guard(fMutex);
236
237 int rc = 0;
238 for (auto it=fServerList.begin(); it!=fServerList.end(); it++)
239 {
240 if (!serv.empty() && *it!=serv)
241 continue;
242
243 out << kRed << "----- " << *it << " -----" << endl << endl;
244
245 for (auto is=fServiceList.begin(); is!=fServiceList.end(); is++)
246 {
247 if (is->server!=*it)
248 continue;
249
250 if (!service.empty() && is->service!=service)
251 continue;
252
253 if (is->iscmd!=iscmd)
254 continue;
255
256 rc++;
257
258 out << " " << is->service;
259 if (!is->format.empty())
260 out << '[' << is->format << ']';
261
262 const auto id = fServiceDescriptionList.find(*it+"/"+is->service);
263 if (id!=fServiceDescriptionList.end())
264 {
265 const vector<Description> &v = id->second;
266
267 for (auto j=v.begin()+1; j!=v.end(); j++)
268 out << " <" << j->name << ">";
269 out << endl;
270
271 if (!v[0].comment.empty())
272 out << " " << v[0].comment << endl;
273
274 for (auto j=v.begin()+1; j!=v.end(); j++)
275 {
276 out << " " << kGreen << j->name;
277 if (!j->comment.empty())
278 out << kReset << ": " << kBlue << j->comment;
279 if (!j->unit.empty())
280 out << kYellow << " [" << j->unit << "]";
281 out << endl;
282 }
283 }
284 out << endl;
285 }
286 out << endl;
287 }
288
289 return rc;
290}
291
292int StateMachineDimControl::HandleStateChange(const string &server, DimDescriptions *dim)
293{
294 fMutex.lock();
295 const State state = dim->description();
296 fCurrentStateList[server] = make_pair(dim->state(), state.index==DimState::kNotAvailable?"":state.name);
297 fMutex.unlock();
298
299 return GetCurrentState();
300}
301
302pair<int32_t, string> StateMachineDimControl::GetServerState(const std::string &server)
303{
304 const lock_guard<mutex> guard(fMutex);
305
306 const auto it = fCurrentStateList.find(server);
307 return it==fCurrentStateList.end() ? make_pair(-256, string()) : it->second;
308}
309
310int StateMachineDimControl::HandleStates(const string &server, DimDescriptions *dim)
311{
312 fMutex.lock();
313 for (auto it=dim->states.begin(); it!=dim->states.end(); it++)
314 fStateDescriptionList[make_pair(server, it->index)] = make_pair(it->name, it->comment);
315 fMutex.unlock();
316
317 return GetCurrentState();
318}
319
320int StateMachineDimControl::HandleDescriptions(DimDescriptions *dim)
321{
322 fMutex.lock();
323
324 for (auto it=dim->descriptions.begin(); it!=dim->descriptions.end(); it++)
325 fServiceDescriptionList[it->front().name].assign(it->begin(), it->end());
326
327 fMutex.unlock();
328
329 return GetCurrentState();
330}
331
332std::vector<Description> StateMachineDimControl::GetDescription(const std::string &service)
333{
334 const lock_guard<mutex> guard(fMutex);
335
336 const auto it = fServiceDescriptionList.find(service);
337 return it==fServiceDescriptionList.end() ? vector<Description>() : it->second;
338}
339
340int StateMachineDimControl::HandleServerAdd(const string &server)
341{
342 if (server!="DIS_DNS")
343 {
344 DimDescriptions *d = new DimDescriptions(server);
345
346 fDimDescriptionsList.push_back(d);
347 d->SetCallback(bind(&StateMachineDimControl::HandleStateChange, this, server, d));
348 d->SetCallbackStates(bind(&StateMachineDimControl::HandleStates, this, server, d));
349 d->SetCallbackDescriptions(bind(&StateMachineDimControl::HandleDescriptions, this, d));
350 d->Subscribe(*this);
351 }
352
353 // Make a copy of the list to be able to
354 // lock the access to the list
355 fMutex.lock();
356 fServerList.insert(server);
357 fMutex.unlock();
358
359 return GetCurrentState();
360}
361
362int StateMachineDimControl::HandleServerRemove(const string &server)
363{
364 fMutex.lock();
365 fServerList.erase(server);
366 fMutex.unlock();
367
368 return GetCurrentState();
369}
370
371vector<string> StateMachineDimControl::GetServerList()
372{
373 vector<string> rc;
374
375 fMutex.lock();
376
377 rc.reserve(fServerList.size());
378 for (auto it=fServerList.begin(); it!=fServerList.end(); it++)
379 rc.push_back(*it);
380
381 fMutex.unlock();
382
383 return rc;
384}
385
386vector<string> StateMachineDimControl::GetCommandList(const string &server)
387{
388 const lock_guard<mutex> guard(fMutex);
389
390 const string s = server.substr(0, server.length()-1);
391
392 if (fServerList.find(s)==fServerList.end())
393 return vector<string>();
394
395 vector<string> rc;
396
397 for (auto it=fServiceList.begin(); it!=fServiceList.end(); it++)
398 if (it->iscmd && it->server==s)
399 rc.push_back(server+it->service);
400
401 return rc;
402}
403
404vector<string> StateMachineDimControl::GetCommandList()
405{
406 vector<string> rc;
407
408 fMutex.lock();
409
410 for (auto it=fServiceList.begin(); it!=fServiceList.end(); it++)
411 if (it->iscmd)
412 rc.push_back(it->server+"/"+it->service);
413
414 fMutex.unlock();
415 return rc;
416}
417
418
419int StateMachineDimControl::HandleAddService(const Service &svc)
420{
421 // Make a copy of the list to be able to
422 // lock the access to the list
423 fMutex.lock();
424 fServiceList.insert(svc);
425 fMutex.unlock();
426
427 return GetCurrentState();
428}
429
430bool StateMachineDimControl::HasServer(const std::string &server)
431{
432 fMutex.lock();
433 const bool rc = fServerList.find(server)!=fServerList.end();
434 fMutex.unlock();
435
436 return rc;
437}
438
439StateMachineDimControl::StateMachineDimControl(ostream &out) : StateMachineDim(out, fIsServer?"DIM_CONTROL":"")
440{
441 fDim.Subscribe(*this);
442 fDimList.Subscribe(*this);
443
444 fDimList.SetCallbackServerAdd (bind(&StateMachineDimControl::HandleServerAdd, this, placeholders::_1));
445 fDimList.SetCallbackServerRemove(bind(&StateMachineDimControl::HandleServerRemove, this, placeholders::_1));
446 fDimList.SetCallbackServiceAdd (bind(&StateMachineDimControl::HandleAddService, this, placeholders::_1));
447
448 // State names
449 AddStateName(0, "Idle", "No script currently in processing.");
450 AddStateName(1, "Load", "Script being loaded.");
451 AddStateName(2, "Started", "Script execution started.");
452
453 AddEvent("START", "C", 0)
454 (bind(&StateMachineDimControl::StartScript, this, placeholders::_1, ".js "))
455 ("Start a JavaScript");
456
457 AddEvent("EXECUTE", "C", 0)
458 (bind(&StateMachineDimControl::StartScript, this, placeholders::_1, ".x "))
459 ("Execute a batch script");
460
461 AddEvent("STOP", "C")
462 (bind(&StateMachineDimControl::StopScript, this))
463 ("Stop a runnning batch script or JavaScript");
464}
465
466StateMachineDimControl::~StateMachineDimControl()
467{
468 for (auto it=fDimDescriptionsList.begin(); it!=fDimDescriptionsList.end(); it++)
469 delete *it;
470}
471
472int StateMachineDimControl::EvalOptions(Configuration &conf)
473{
474 fDebug = conf.Get<bool>("debug");
475 fUser = conf.Get<string>("user");
476 fScriptUser = fUser;
477
478 // fVerbosity = 40;
479
480 // if (conf.Has("verbosity"))
481 // fVerbosity = conf.Get<uint32_t>("verbosity");
482
483 // if (conf.Get<bool>("quiet"))
484 // fVerbosity = 90;
485
486 const int cnt = conf.Get<bool>("stop")+conf.Has("start")+conf.Has("batch");
487
488 if (fIsServer)
489 {
490 if (cnt>0)
491 {
492 Error("--start, --batch, --stop are mutually exclusive to --server.");
493 return 3;
494 }
495 return -1;
496 }
497
498 if (cnt>1)
499 {
500 Error("--start, --batch and --stop are all mutually exclusive.");
501 return 4;
502 }
503
504 if (conf.Get<bool>("stop"))
505 return Dim::SendCommand("DIM_CONTROL/STOP", fUser) + 1;
506
507 if (conf.Has("start"))
508 return Dim::SendCommand("DIM_CONTROL/START", conf.Get<string>("start")+" user="+fUser) + 1;
509
510 if (conf.Has("batch"))
511 return Dim::SendCommand("DIM_CONTROL/EXECUTE", conf.Get<string>("batch")+" user="+fUser) + 1;
512
513 if (conf.Has("msg"))
514 return Dim::SendCommand("CHAT/MSG", fUser+": "+conf.Get<string>("msg")) + 1;
515
516 return -1;
517}
Note: See TracBrowser for help on using the repository browser.