source: trunk/FACT++/src/RemoteControl.h@ 14085

Last change on this file since 14085 was 14060, checked in by tbretz, 12 years ago
Implemented JsState and JsName, fixed a problem in JsSleep
File size: 12.8 KB
Line 
1#ifndef FACT_RemoteControl
2#define FACT_RemoteControl
3
4#include "InterpreterV8.h"
5
6// **************************************************************************
7/** @class RemoteControlImp
8
9@brief This implements the basic functions of a remote control via dim
10
11Through a ServiceList object this object subscribes to all available
12SERVICE_LISTs in the dim network. This allows to keep an up-to-date
13list of all servers and services. Its ProcessCommand member function
14allows to emit commands according to the services found in the network.
15Its infoHandler() is called as an update notifier from the ClientList
16object.
17
18**/
19// **************************************************************************
20#include "DimNetwork.h"
21
22class RemoteControlImp : public DimNetwork
23{
24protected:
25 std::ostream &lout; /// Output stream for local synchrounous output
26
27 std::string fCurrentServer; /// The server to which we currently cd'ed
28
29protected:
30 // Redirect asynchronous output to the output window
31 RemoteControlImp(std::ostream &out, std::ostream &in) :
32 DimNetwork(out), lout(in)
33 {
34 }
35 bool ProcessCommand(const std::string &str);
36};
37
38
39
40// **************************************************************************
41/** @class RemoteControl
42
43@brief Implements a remote control based on a Readline class for the dim network
44
45This template implements all functions which overwrite any function from the
46Readline class. Since several derivatives of the Readline class implement
47different kind of Readline access, this class can be derived by any of them
48due to its template argument. However, the normal case will be
49deriving it from either Console or Shell.
50
51@tparam T
52 The base class for RemoteControl. Either Readlien or a class
53 deriving from it. This is usually either Console or Shell.
54
55**/
56// **************************************************************************
57#include "WindowLog.h"
58#include "ReadlineColor.h"
59#include "tools.h"
60#include "MainImp.h"
61
62template <class T>
63class RemoteControl : public T, public RemoteControlImp, public InterpreterV8
64{
65private:
66 MessageImp *fImp;
67
68 void SetSection(int s) { if (fImp) fImp->Write(Time(), "", s); }
69
70 int Write(const Time &time, const std::string &txt, int qos=kMessage)
71 {
72 if (!fImp)
73 return 0;
74 return fImp ? fImp->Write(time, txt, qos) : MessageImp::Write(time, txt, qos);
75 }
76
77 void exitHandler(int code) { if (dynamic_cast<MainImp*>(fImp)) dynamic_cast<MainImp*>(fImp)->Stop(code); else exit(code); }
78
79 static void append(std::string &str)
80 {
81 str.append("/");
82 }
83 static void chop(std::string &str)
84 {
85 const size_t p = str.find_first_of('/');
86 if (p!=string::npos)
87 str = str.substr(p+1);
88 }
89
90 // This funtion defines which generator should be called.
91 // If it returns 0 the standard reaqdline generator are called.
92 // Otherwise set the right generator with rl_completion_matches.
93 char **Completion(const char *text, int start, int)
94 {
95 // Get the whole buffer before the tab-position
96 const string b = string(T::GetBuffer());
97 const string s = b.substr(0, start);
98 const string l = Tools::Trim(s.c_str());
99 if (l.empty())
100 {
101 if (fCurrentServer.empty())
102 {
103 const size_t p1 = b.find_first_of(' ');
104 const size_t p2 = b.find_first_of('/');
105
106 if (p1==string::npos && p2!=string::npos)
107 return T::Complete(GetCommandList(), text);
108
109 std::vector<std::string> v = GetServerList();
110 for_each(v.begin(), v.end(), RemoteControl::append);
111 return T::Complete(v, text);
112 }
113 else
114 {
115 std::vector<std::string> v = GetCommandList(fCurrentServer);
116 for_each(v.begin(), v.end(), RemoteControl::chop);
117 return T::Complete(v, text);
118 }
119 }
120 return T::Complete(GetCommandList(l), text);
121 }
122
123 void RemoveServer(std::string s)
124 {
125 DimNetwork::RemoveServer(s);
126 if (fCurrentServer==s)
127 {
128 fCurrentServer = "";
129 T::UpdatePrompt();
130 }
131 }
132
133 void RemoveAllServers()
134 {
135 DimNetwork::RemoveAllServers();
136 fCurrentServer = "";
137 T::UpdatePrompt();
138 }
139
140 // ===========================================================================
141
142 virtual void JsLoad(const std::string &) { SetSection(-2); }
143 virtual void JsStart(const std::string &) { SetSection(-1); }
144 virtual void JsEnd(const std::string &) { SetSection(-3); }
145 virtual bool JsSend(const std::string &str) { return ProcessCommand(str); }
146 virtual void JsPrint(const std::string &msg) { fImp->Comment(msg); }
147 virtual void JsException(const std::string &str) { fImp->Error(str); }
148
149 int JsState(const string &server)
150 {
151 const ClientList::const_iterator l = fClientList.find(server);
152 return l==fClientList.end() ? -256 : l->second->GetState();
153 }
154
155 string JsName(const string &server)
156 {
157
158 const ClientList::const_iterator l = fClientList.find(server);
159 if (l==fClientList.end())
160 return "";
161
162 return GetState(server, l->second->GetState()).name;
163 }
164
165 void JsSleep(uint32_t ms)
166 {
167 const Time timeout = Time()+boost::posix_time::millisec(ms==0?1:ms);
168
169 T::GetStreamOut().Display(true);
170 T::GetStreamOut().SetBacklog(false);
171 T::GetStreamOut().SetNullOutput(false);
172 while (timeout>Time() && !T::IsScriptStopped())
173 usleep(1);
174 T::GetStreamOut().SetNullOutput(true);
175 T::GetStreamOut().SetBacklog(true);
176 }
177
178 int JsWait(const string &server, int32_t state, uint32_t ms)
179 {
180 const ClientList::const_iterator l = fClientList.find(server);
181 if (l==fClientList.end())
182 {
183 lout << kRed << "Server '" << server << "' not found." << endl;
184 T::StopScript();
185 return -1;
186 }
187
188 const Time timeout = ms<=0 ? Time(Time::none) : Time()+boost::posix_time::millisec(ms);
189
190 T::GetStreamOut().Display(true);
191 T::GetStreamOut().SetBacklog(false);
192 T::GetStreamOut().SetNullOutput(false);
193 while (l->second->GetState()!=state && timeout>Time() && !T::IsScriptStopped())
194 usleep(1);
195 T::GetStreamOut().SetNullOutput(true);
196 T::GetStreamOut().SetBacklog(true);
197
198 return l->second->GetState()==state;
199 }
200
201
202 // ===========================================================================
203
204
205public:
206 // Redirect asynchronous output to the output window
207 RemoteControl(const char *name) : T(name),
208 RemoteControlImp(T::GetStreamOut(), T::GetStreamIn()), fImp(0)
209 {
210 }
211
212 bool PrintGeneralHelp()
213 {
214 T::PrintGeneralHelp();
215 lout << " " << kUnderline << "Specific commands:\n";
216 lout << kBold << " h,help <arg> " << kReset << "List help text for given server or command.\n";
217// lout << kBold << " s,servers " << kReset << "List all servers which are connected." << endl;
218 lout << kBold << " svc,services " << kReset << "List all services in the network.\n";
219 lout << kBold << " st,states " << kReset << "List all states in the network.\n";
220 lout << kBold << " > <text> " << kReset << "Echo <text> to the output stream\n";
221 lout << kBold << " .s " << kReset << "Wait for the state-machine to change to the given state.\n";
222 lout << " " " .s <server> [<state> [<timeout> [<label>]]]\n";
223 lout << " " "<server> The server for which state to wait (e.g. FTM_CONTROL)\n";
224 lout << " " "<state> The state id (see 'states') for which to wait (e.g. 3)\n";
225 lout << " " "<imeout> A timeout in millisenconds how long to wait (e.g. 500)\n";
226 lout << " " "<label> A label (number) until which everything is skipped in case of timeout\n";
227 lout << endl;
228 return true;
229 }
230
231 bool PrintCommands()
232 {
233 lout << endl << kBold << "List of commands:" << endl;
234 PrintDescription(lout, true);
235 return true;
236 }
237
238 // returns whether a command should be put into the history
239 bool Process(const std::string &str)
240 {
241 if (str.substr(0, 2)=="h " || str.substr(0, 5)=="help ")
242 {
243 const size_t p1 = str.find_first_of(' ');
244 const string svc = str.substr(p1+1);
245
246 const size_t p3 = svc.find_first_of('/');
247 const string s = svc.substr(0, p3);
248 const string c = p3==string::npos?"":svc.substr(p3+1);
249
250 lout << endl;
251 if (!fCurrentServer.empty())
252 {
253 if (PrintDescription(lout, true, fCurrentServer, svc)==0)
254 lout << " " << svc << ": <not found>" << endl;
255 }
256 else
257 {
258 if (PrintDescription(lout, true, s, c)==0)
259 lout << " <no matches found>" <<endl;
260 }
261
262 return true;
263 }
264
265 if (str.substr(0, 4)==".js ")
266 {
267 string opt(str.substr(4));
268
269 map<string,string> data = Tools::Split(opt, true);
270 if (opt.size()==0)
271 {
272 if (data.size()==0)
273 lout << kRed << "JavaScript filename missing." << endl;
274 else
275 lout << kRed << "Equal sign missing in argument '" << data.begin()->first << "'" << endl;
276
277 return true;
278 }
279
280 T::fScript = opt;
281 JsRun(opt, data);
282 return true;
283 }
284
285 if (str.substr(0, 3)==".s ")
286 {
287 istringstream in(str.substr(3));
288
289 int state=-100, ms=0;
290 string server;
291
292 in >> server >> state >> ms;
293 if (state==-100)
294 {
295 lout << kRed << "Couldn't parse state id in '" << str.substr(3) << "'" << endl;
296 return true;
297 }
298
299 const int rc = JsWait(server, state, ms);
300
301 if (rc<0 || rc==1)
302 return true;
303
304 int label = -1;
305 in >> label;
306 if (in.fail() && !in.eof())
307 {
308 lout << kRed << "Invalid label in '" << str.substr(3) << "'" << endl;
309 T::StopScript();
310 return true;
311 }
312 T::SetLabel(label);
313
314 return true;
315 }
316
317 if (str[0]=='>')
318 {
319 fImp->Comment(Tools::Trim(str.substr(1)));
320 return true;
321 }
322
323 if (ReadlineColor::Process(lout, str))
324 return true;
325
326 if (T::Process(str))
327 return true;
328
329 if (str=="services" || str=="svc")
330 {
331 PrintDescription(lout, false);
332 return true;
333 }
334
335 if (str=="states" || str=="st")
336 {
337 PrintStates(lout);
338 return true;
339 }
340
341 return !ProcessCommand(str);
342 }
343
344 void SetReceiver(MessageImp &imp) { fImp = &imp; }
345};
346
347
348
349// **************************************************************************
350/** @class RemoteStream
351
352 */
353// **************************************************************************
354#include "Console.h"
355
356class RemoteStream : public RemoteControl<ConsoleStream>
357{
358public:
359 RemoteStream(const char *name, bool null = false)
360 : RemoteControl<ConsoleStream>(name) { SetNullOutput(null); }
361};
362
363// **************************************************************************
364/** @class RemoteConsole
365
366@brief Derives the RemoteControl from Control and adds a proper prompt
367
368This is basically a RemoteControl, which derives through the template
369argument from the Console class. It enhances the functionality of
370the remote control with a proper updated prompt.
371
372 */
373// **************************************************************************
374
375class RemoteConsole : public RemoteControl<Console>
376{
377public:
378 RemoteConsole(const char *name, bool continous=false) :
379 RemoteControl<Console>(name)
380 {
381 SetContinous(continous);
382 }
383 string GetUpdatePrompt() const;
384};
385
386// **************************************************************************
387/** @class RemoteShell
388
389@brief Derives the RemoteControl from Shell and adds colored prompt
390
391This is basically a RemoteControl, which derives through the template
392argument from the Shell class. It enhances the functionality of
393the local control with a proper updated prompt.
394
395 */
396// **************************************************************************
397#include "Shell.h"
398
399class RemoteShell : public RemoteControl<Shell>
400{
401public:
402 RemoteShell(const char *name, bool = false) :
403 RemoteControl<Shell>(name)
404 {
405 }
406 string GetUpdatePrompt() const;
407};
408
409#endif
Note: See TracBrowser for help on using the repository browser.