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

Last change on this file since 13707 was 13702, checked in by tbretz, 13 years ago
Slight change to the meaning of labels; added the direct exit to th eexecution loop; implemented interruption of state waiting
File size: 10.4 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) { 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 infoHandler()
122 {
123 RemoteControlImp::infoHandler();
124 if (!fCurrentServer.empty() && !HasServer(fCurrentServer))
125 {
126 fCurrentServer = "";
127 T::UpdatePrompt();
128 }
129 }
130
131public:
132 // Redirect asynchronous output to the output window
133 RemoteControl(const char *name) : T(name),
134 RemoteControlImp(T::GetStreamOut(), T::GetStreamIn()), fImp(0)
135 {
136 }
137
138 bool PrintGeneralHelp()
139 {
140 T::PrintGeneralHelp();
141 lout << " " << kUnderline << "Specific commands:\n";
142 lout << kBold << " h,help <arg> " << kReset << "List help text for given server or command.\n";
143// lout << kBold << " s,servers " << kReset << "List all servers which are connected." << endl;
144 lout << kBold << " svc,services " << kReset << "List all services in the network.\n";
145 lout << kBold << " st,states " << kReset << "List all states in the network.\n";
146 lout << kBold << " > <text> " << kReset << "Echo <text> to the output stream\n";
147 lout << kBold << " .s " << kReset << "Wait for the state-machine to change to the given state.\n";
148 lout << " " " .s <server> [<state> [<timeout> [<label>]]]\n";
149 lout << " " "<server> The server for which state to wait (e.g. FTM_CONTROL)\n";
150 lout << " " "<state> The state id (see 'states') for which to wait (e.g. 3)\n";
151 lout << " " "<imeout> A timeout in millisenconds how long to wait (e.g. 500)\n";
152 lout << " " "<label> A label until which everything is skipped in case of timeout\n";
153 lout << endl;
154 return true;
155 }
156
157 bool PrintCommands()
158 {
159 lout << endl << kBold << "List of commands:" << endl;
160 PrintDescription(lout, true);
161 return true;
162 }
163
164 // returns whether a command should be put into the history
165 bool Process(const std::string &str)
166 {
167 if (str.substr(0, 2)=="h " || str.substr(0, 5)=="help ")
168 {
169 const size_t p1 = str.find_first_of(' ');
170 const string svc = str.substr(p1+1);
171
172 const size_t p3 = svc.find_first_of('/');
173 const string s = svc.substr(0, p3);
174 const string c = p3==string::npos?"":svc.substr(p3+1);
175
176 lout << endl;
177 if (!fCurrentServer.empty())
178 {
179 if (PrintDescription(lout, true, fCurrentServer, svc)==0)
180 lout << " " << svc << ": <not found>" << endl;
181 }
182 else
183 {
184 if (PrintDescription(lout, true, s, c)==0)
185 lout << " <no matches found>" <<endl;
186 }
187
188 return true;
189 }
190
191 if (str.substr(0, 3)==".s ")
192 {
193 istringstream in(str.substr(3));
194
195 int state=-100, ms=0;
196 string server;
197
198 in >> server >> state >> ms;
199 if (state==-100)
200 {
201 lout << kRed << "Couldn't parse state id in '" << str.substr(3) << "'" << endl;
202 return true;
203 }
204
205 const ClientList::const_iterator l = fClientList.find(server);
206 if (l==fClientList.end())
207 {
208 lout << kRed << "Server '" << server << "' not found." << endl;
209 return true;
210 }
211
212 const Time timeout = ms<=0 ? Time(Time::none) : Time()+boost::posix_time::millisec(ms);
213
214 T::GetStreamOut().Display(true);
215 T::GetStreamOut().SetBacklog(false);
216 T::GetStreamOut().SetNullOutput(false);
217 while (l->second->GetState()!=state && timeout>Time() && T::GetLabel()!=-2)
218 usleep(1);
219 T::GetStreamOut().SetNullOutput(true);
220 T::GetStreamOut().SetBacklog(true);
221
222 if (T::GetLabel()!=0 && l->second->GetState()!=state)
223 {
224 int label = -1;
225 in >> label;
226 T::SetLabel(label);
227 }
228
229 return true;
230 }
231
232 if (str[0]=='#')
233 return true;
234
235 if (str[0]=='>')
236 {
237 fImp->Comment(Tools::Trim(str.substr(1)));
238 return true;
239 }
240
241 if (ReadlineColor::Process(lout, str))
242 return true;
243
244 if (T::Process(str))
245 return true;
246
247 if (str=="services" || str=="svc")
248 {
249 PrintDescription(lout, false);
250 return true;
251 }
252
253 if (str=="states" || str=="st")
254 {
255 PrintStates(lout);
256 return true;
257 }
258
259 return ProcessCommand(str);
260 }
261
262 void SetReceiver(MessageImp &imp) { fImp = &imp; }
263};
264
265
266
267// **************************************************************************
268/** @class RemoteStream
269
270 */
271// **************************************************************************
272#include "Console.h"
273
274class RemoteStream : public RemoteControl<ConsoleStream>
275{
276public:
277 RemoteStream(const char *name, bool null = false)
278 : RemoteControl<ConsoleStream>(name) { SetNullOutput(null); }
279};
280
281// **************************************************************************
282/** @class RemoteConsole
283
284@brief Derives the RemoteControl from Control and adds a proper prompt
285
286This is basically a RemoteControl, which derives through the template
287argument from the Console class. It enhances the functionality of
288the remote control with a proper updated prompt.
289
290 */
291// **************************************************************************
292
293class RemoteConsole : public RemoteControl<Console>
294{
295public:
296 RemoteConsole(const char *name, bool continous=false) :
297 RemoteControl<Console>(name)
298 {
299 SetContinous(continous);
300 }
301 string GetUpdatePrompt() const;
302};
303
304// **************************************************************************
305/** @class RemoteShell
306
307@brief Derives the RemoteControl from Shell and adds colored prompt
308
309This is basically a RemoteControl, which derives through the template
310argument from the Shell class. It enhances the functionality of
311the local control with a proper updated prompt.
312
313 */
314// **************************************************************************
315#include "Shell.h"
316
317class RemoteShell : public RemoteControl<Shell>
318{
319public:
320 RemoteShell(const char *name, bool = false) :
321 RemoteControl<Shell>(name)
322 {
323 }
324 string GetUpdatePrompt() const;
325};
326
327#endif
Note: See TracBrowser for help on using the repository browser.