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

Last change on this file since 14052 was 14050, checked in by tbretz, 14 years ago
Added InterpreterV8 as base class to allow running JavaScripts
File size: 12.0 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 void JsSleep(uint32_t ms)
150 {
151 const Time timeout = ms<=0 ? Time(Time::none) : Time()+boost::posix_time::millisec(ms);
152
153 T::GetStreamOut().Display(true);
154 T::GetStreamOut().SetBacklog(false);
155 T::GetStreamOut().SetNullOutput(false);
156 while (timeout>Time() && !T::IsScriptStopped())
157 usleep(1);
158 T::GetStreamOut().SetNullOutput(true);
159 T::GetStreamOut().SetBacklog(true);
160 }
161
162 int JsWait(const string &server, int32_t state, uint32_t ms)
163 {
164 const ClientList::const_iterator l = fClientList.find(server);
165 if (l==fClientList.end())
166 {
167 lout << kRed << "Server '" << server << "' not found." << endl;
168 T::StopScript();
169 return -1;
170 }
171
172 const Time timeout = ms<=0 ? Time(Time::none) : Time()+boost::posix_time::millisec(ms);
173
174 T::GetStreamOut().Display(true);
175 T::GetStreamOut().SetBacklog(false);
176 T::GetStreamOut().SetNullOutput(false);
177 while (l->second->GetState()!=state && timeout>Time() && !T::IsScriptStopped())
178 usleep(1);
179 T::GetStreamOut().SetNullOutput(true);
180 T::GetStreamOut().SetBacklog(true);
181
182 return l->second->GetState()==state;
183 }
184
185
186 // ===========================================================================
187
188
189public:
190 // Redirect asynchronous output to the output window
191 RemoteControl(const char *name) : T(name),
192 RemoteControlImp(T::GetStreamOut(), T::GetStreamIn()), fImp(0)
193 {
194 }
195
196 bool PrintGeneralHelp()
197 {
198 T::PrintGeneralHelp();
199 lout << " " << kUnderline << "Specific commands:\n";
200 lout << kBold << " h,help <arg> " << kReset << "List help text for given server or command.\n";
201// lout << kBold << " s,servers " << kReset << "List all servers which are connected." << endl;
202 lout << kBold << " svc,services " << kReset << "List all services in the network.\n";
203 lout << kBold << " st,states " << kReset << "List all states in the network.\n";
204 lout << kBold << " > <text> " << kReset << "Echo <text> to the output stream\n";
205 lout << kBold << " .s " << kReset << "Wait for the state-machine to change to the given state.\n";
206 lout << " " " .s <server> [<state> [<timeout> [<label>]]]\n";
207 lout << " " "<server> The server for which state to wait (e.g. FTM_CONTROL)\n";
208 lout << " " "<state> The state id (see 'states') for which to wait (e.g. 3)\n";
209 lout << " " "<imeout> A timeout in millisenconds how long to wait (e.g. 500)\n";
210 lout << " " "<label> A label (number) until which everything is skipped in case of timeout\n";
211 lout << endl;
212 return true;
213 }
214
215 bool PrintCommands()
216 {
217 lout << endl << kBold << "List of commands:" << endl;
218 PrintDescription(lout, true);
219 return true;
220 }
221
222 // returns whether a command should be put into the history
223 bool Process(const std::string &str)
224 {
225 if (str.substr(0, 2)=="h " || str.substr(0, 5)=="help ")
226 {
227 const size_t p1 = str.find_first_of(' ');
228 const string svc = str.substr(p1+1);
229
230 const size_t p3 = svc.find_first_of('/');
231 const string s = svc.substr(0, p3);
232 const string c = p3==string::npos?"":svc.substr(p3+1);
233
234 lout << endl;
235 if (!fCurrentServer.empty())
236 {
237 if (PrintDescription(lout, true, fCurrentServer, svc)==0)
238 lout << " " << svc << ": <not found>" << endl;
239 }
240 else
241 {
242 if (PrintDescription(lout, true, s, c)==0)
243 lout << " <no matches found>" <<endl;
244 }
245
246 return true;
247 }
248
249 if (str.substr(0, 4)==".js ")
250 {
251 JsRun(Tools::Trim(str.substr(3)));
252 return true;
253 }
254
255 if (str.substr(0, 3)==".s ")
256 {
257 istringstream in(str.substr(3));
258
259 int state=-100, ms=0;
260 string server;
261
262 in >> server >> state >> ms;
263 if (state==-100)
264 {
265 lout << kRed << "Couldn't parse state id in '" << str.substr(3) << "'" << endl;
266 return true;
267 }
268
269 const int rc = JsWait(server, state, ms);
270
271 if (rc<0 || rc==1)
272 return true;
273
274 int label = -1;
275 in >> label;
276 if (in.fail() && !in.eof())
277 {
278 lout << kRed << "Invalid label in '" << str.substr(3) << "'" << endl;
279 T::StopScript();
280 return true;
281 }
282 T::SetLabel(label);
283
284 return true;
285 }
286
287 if (str[0]=='>')
288 {
289 fImp->Comment(Tools::Trim(str.substr(1)));
290 return true;
291 }
292
293 if (ReadlineColor::Process(lout, str))
294 return true;
295
296 if (T::Process(str))
297 return true;
298
299 if (str=="services" || str=="svc")
300 {
301 PrintDescription(lout, false);
302 return true;
303 }
304
305 if (str=="states" || str=="st")
306 {
307 PrintStates(lout);
308 return true;
309 }
310
311 return !ProcessCommand(str);
312 }
313
314 void SetReceiver(MessageImp &imp) { fImp = &imp; }
315};
316
317
318
319// **************************************************************************
320/** @class RemoteStream
321
322 */
323// **************************************************************************
324#include "Console.h"
325
326class RemoteStream : public RemoteControl<ConsoleStream>
327{
328public:
329 RemoteStream(const char *name, bool null = false)
330 : RemoteControl<ConsoleStream>(name) { SetNullOutput(null); }
331};
332
333// **************************************************************************
334/** @class RemoteConsole
335
336@brief Derives the RemoteControl from Control and adds a proper prompt
337
338This is basically a RemoteControl, which derives through the template
339argument from the Console class. It enhances the functionality of
340the remote control with a proper updated prompt.
341
342 */
343// **************************************************************************
344
345class RemoteConsole : public RemoteControl<Console>
346{
347public:
348 RemoteConsole(const char *name, bool continous=false) :
349 RemoteControl<Console>(name)
350 {
351 SetContinous(continous);
352 }
353 string GetUpdatePrompt() const;
354};
355
356// **************************************************************************
357/** @class RemoteShell
358
359@brief Derives the RemoteControl from Shell and adds colored prompt
360
361This is basically a RemoteControl, which derives through the template
362argument from the Shell class. It enhances the functionality of
363the local control with a proper updated prompt.
364
365 */
366// **************************************************************************
367#include "Shell.h"
368
369class RemoteShell : public RemoteControl<Shell>
370{
371public:
372 RemoteShell(const char *name, bool = false) :
373 RemoteControl<Shell>(name)
374 {
375 }
376 string GetUpdatePrompt() const;
377};
378
379#endif
Note: See TracBrowser for help on using the repository browser.