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

Last change on this file since 13827 was 13743, checked in by tbretz, 13 years ago
Little improvements to the help text.
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) { 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 (number) 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()!=-2 && l->second->GetState()!=state)
223 {
224 int label = -1;
225 in >> label;
226 if (in.fail() && !in.eof())
227 {
228 lout << kRed << "Invalid label in '" << str.substr(3) << "'" << endl;
229 label = -2;
230 }
231 else
232 T::SetLabel(label);
233 }
234
235 return true;
236 }
237
238 if (str[0]=='>')
239 {
240 fImp->Comment(Tools::Trim(str.substr(1)));
241 return true;
242 }
243
244 if (ReadlineColor::Process(lout, str))
245 return true;
246
247 if (T::Process(str))
248 return true;
249
250 if (str=="services" || str=="svc")
251 {
252 PrintDescription(lout, false);
253 return true;
254 }
255
256 if (str=="states" || str=="st")
257 {
258 PrintStates(lout);
259 return true;
260 }
261
262 return ProcessCommand(str);
263 }
264
265 void SetReceiver(MessageImp &imp) { fImp = &imp; }
266};
267
268
269
270// **************************************************************************
271/** @class RemoteStream
272
273 */
274// **************************************************************************
275#include "Console.h"
276
277class RemoteStream : public RemoteControl<ConsoleStream>
278{
279public:
280 RemoteStream(const char *name, bool null = false)
281 : RemoteControl<ConsoleStream>(name) { SetNullOutput(null); }
282};
283
284// **************************************************************************
285/** @class RemoteConsole
286
287@brief Derives the RemoteControl from Control and adds a proper prompt
288
289This is basically a RemoteControl, which derives through the template
290argument from the Console class. It enhances the functionality of
291the remote control with a proper updated prompt.
292
293 */
294// **************************************************************************
295
296class RemoteConsole : public RemoteControl<Console>
297{
298public:
299 RemoteConsole(const char *name, bool continous=false) :
300 RemoteControl<Console>(name)
301 {
302 SetContinous(continous);
303 }
304 string GetUpdatePrompt() const;
305};
306
307// **************************************************************************
308/** @class RemoteShell
309
310@brief Derives the RemoteControl from Shell and adds colored prompt
311
312This is basically a RemoteControl, which derives through the template
313argument from the Shell class. It enhances the functionality of
314the local control with a proper updated prompt.
315
316 */
317// **************************************************************************
318#include "Shell.h"
319
320class RemoteShell : public RemoteControl<Shell>
321{
322public:
323 RemoteShell(const char *name, bool = false) :
324 RemoteControl<Shell>(name)
325 {
326 }
327 string GetUpdatePrompt() const;
328};
329
330#endif
Note: See TracBrowser for help on using the repository browser.