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

Last change on this file since 13686 was 13672, checked in by tbretz, 13 years ago
Redirect the exit handler; removed obsolete fLabel; added new class for a unattended dimctrl server RemoteStream
File size: 10.3 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 return fImp ? fImp->Write(time, txt, qos) : MessageImp::Write(time, txt, qos);
71 }
72
73 void exitHandler(int code) { if (dynamic_cast<MainImp*>(fImp)) dynamic_cast<MainImp*>(fImp)->Stop(code); else exit(code); }
74
75 static void append(std::string &str)
76 {
77 str.append("/");
78 }
79 static void chop(std::string &str)
80 {
81 const size_t p = str.find_first_of('/');
82 if (p!=string::npos)
83 str = str.substr(p+1);
84 }
85
86 // This funtion defines which generator should be called.
87 // If it returns 0 the standard reaqdline generator are called.
88 // Otherwise set the right generator with rl_completion_matches.
89 char **Completion(const char *text, int start, int)
90 {
91 // Get the whole buffer before the tab-position
92 const string b = string(T::GetBuffer());
93 const string s = b.substr(0, start);
94 const string l = Tools::Trim(s.c_str());
95 if (l.empty())
96 {
97 if (fCurrentServer.empty())
98 {
99 const size_t p1 = b.find_first_of(' ');
100 const size_t p2 = b.find_first_of('/');
101
102 if (p1==string::npos && p2!=string::npos)
103 return T::Complete(GetCommandList(), text);
104
105 std::vector<std::string> v = GetServerList();
106 for_each(v.begin(), v.end(), RemoteControl::append);
107 return T::Complete(v, text);
108 }
109 else
110 {
111 std::vector<std::string> v = GetCommandList(fCurrentServer);
112 for_each(v.begin(), v.end(), RemoteControl::chop);
113 return T::Complete(v, text);
114 }
115 }
116 return T::Complete(GetCommandList(l), text);
117 }
118
119 void infoHandler()
120 {
121 RemoteControlImp::infoHandler();
122 if (!fCurrentServer.empty() && !HasServer(fCurrentServer))
123 {
124 fCurrentServer = "";
125 T::UpdatePrompt();
126 }
127 }
128
129public:
130 // Redirect asynchronous output to the output window
131 RemoteControl(const char *name) : T(name),
132 RemoteControlImp(T::GetStreamOut(), T::GetStreamIn()), fImp(0)
133 {
134 }
135
136 bool PrintGeneralHelp()
137 {
138 T::PrintGeneralHelp();
139 lout << " " << kUnderline << "Specific commands:\n";
140 lout << kBold << " h,help <arg> " << kReset << "List help text for given server or command.\n";
141// lout << kBold << " s,servers " << kReset << "List all servers which are connected." << endl;
142 lout << kBold << " svc,services " << kReset << "List all services in the network.\n";
143 lout << kBold << " st,states " << kReset << "List all states in the network.\n";
144 lout << kBold << " > <text> " << kReset << "Echo <text> to the output stream\n";
145 lout << kBold << " .s " << kReset << "Wait for the state-machine to change to the given state.\n";
146 lout << " " " .s <server> [<state> [<timeout> [<label>]]]\n";
147 lout << " " "<server> The server for which state to wait (e.g. FTM_CONTROL)\n";
148 lout << " " "<state> The state id (see 'states') for which to wait (e.g. 3)\n";
149 lout << " " "<imeout> A timeout in millisenconds how long to wait (e.g. 500)\n";
150 lout << " " "<label> A label until which everything is skipped in case of timeout\n";
151 lout << endl;
152 return true;
153 }
154
155 bool PrintCommands()
156 {
157 lout << endl << kBold << "List of commands:" << endl;
158 PrintDescription(lout, true);
159 return true;
160 }
161
162 // returns whether a command should be put into the history
163 bool Process(const std::string &str)
164 {
165 if (str.substr(0, 2)=="h " || str.substr(0, 5)=="help ")
166 {
167 const size_t p1 = str.find_first_of(' ');
168 const string svc = str.substr(p1+1);
169
170 const size_t p3 = svc.find_first_of('/');
171 const string s = svc.substr(0, p3);
172 const string c = p3==string::npos?"":svc.substr(p3+1);
173
174 lout << endl;
175 if (!fCurrentServer.empty())
176 {
177 if (PrintDescription(lout, true, fCurrentServer, svc)==0)
178 lout << " " << svc << ": <not found>" << endl;
179 }
180 else
181 {
182 if (PrintDescription(lout, true, s, c)==0)
183 lout << " <no matches found>" <<endl;
184 }
185
186 return true;
187 }
188
189 if (str.substr(0, 3)==".s ")
190 {
191 istringstream in(str.substr(3));
192
193 int state=-100, ms=0;
194 string server;
195
196 in >> server >> state >> ms;
197 if (state==-100)
198 {
199 lout << kRed << "Couldn't parse state id in '" << str.substr(3) << "'" << endl;
200 return true;
201 }
202
203 const ClientList::const_iterator l = fClientList.find(server);
204 if (l==fClientList.end())
205 {
206 lout << kRed << "Server '" << server << "' not found." << endl;
207 return true;
208 }
209
210 const Time timeout = ms<=0 ? Time(Time::none) : Time()+boost::posix_time::millisec(ms);
211
212 T::GetStreamOut().Display(true);
213 T::GetStreamOut().SetBacklog(false);
214 T::GetStreamOut().SetNullOutput(false);
215 while (l->second->GetState()!=state && timeout>Time())
216 usleep(1);
217 T::GetStreamOut().SetNullOutput(true);
218 T::GetStreamOut().SetBacklog(true);
219
220 if (l->second->GetState()!=state)
221 {
222 int label = -1;
223 in >> label;
224 T::SetLabel(label);
225 }
226
227 return true;
228 }
229
230 if (str[0]=='#')
231 return true;
232
233 if (str[0]=='>')
234 {
235 fImp->Comment(Tools::Trim(str.substr(1)));
236 return true;
237 }
238
239 if (ReadlineColor::Process(lout, str))
240 return true;
241
242 if (T::Process(str))
243 return true;
244
245 if (str=="services" || str=="svc")
246 {
247 PrintDescription(lout, false);
248 return true;
249 }
250
251 if (str=="states" || str=="st")
252 {
253 PrintStates(lout);
254 return true;
255 }
256
257 return ProcessCommand(str);
258 }
259
260 void SetReceiver(MessageImp &imp) { fImp = &imp; }
261};
262
263
264
265// **************************************************************************
266/** @class RemoteStream
267
268 */
269// **************************************************************************
270#include "Console.h"
271
272class RemoteStream : public RemoteControl<ConsoleStream>
273{
274public:
275 RemoteStream(const char *name, bool null = false)
276 : RemoteControl<ConsoleStream>(name) { SetNullOutput(null); }
277};
278
279// **************************************************************************
280/** @class RemoteConsole
281
282@brief Derives the RemoteControl from Control and adds a proper prompt
283
284This is basically a RemoteControl, which derives through the template
285argument from the Console class. It enhances the functionality of
286the remote control with a proper updated prompt.
287
288 */
289// **************************************************************************
290
291class RemoteConsole : public RemoteControl<Console>
292{
293public:
294 RemoteConsole(const char *name, bool continous=false) :
295 RemoteControl<Console>(name)
296 {
297 SetContinous(continous);
298 }
299 string GetUpdatePrompt() const;
300};
301
302// **************************************************************************
303/** @class RemoteShell
304
305@brief Derives the RemoteControl from Shell and adds colored prompt
306
307This is basically a RemoteControl, which derives through the template
308argument from the Shell class. It enhances the functionality of
309the local control with a proper updated prompt.
310
311 */
312// **************************************************************************
313#include "Shell.h"
314
315class RemoteShell : public RemoteControl<Shell>
316{
317public:
318 RemoteShell(const char *name, bool = false) :
319 RemoteControl<Shell>(name)
320 {
321 }
322 string GetUpdatePrompt() const;
323};
324
325#endif
Note: See TracBrowser for help on using the repository browser.