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

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