Stop the timer in console IPC client sample once we don't need it any more.
[wxWidgets.git] / samples / ipc / baseclient.cpp
1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: samples/ipc/baseclient.cpp
3 // Purpose: IPC sample: console client
4 // Author: Anders Larsen
5 // Most of the code was stolen from: samples/ipc/client.cpp
6 // (c) Julian Smart, Jurgen Doornik
7 // Created: 2007-11-08
8 // RCS-ID: $Id$
9 // Copyright: (c) 2007 Anders Larsen
10 // License: wxWindows licence
11 ///////////////////////////////////////////////////////////////////////////////
12
13 // ============================================================================
14 // declarations
15 // ============================================================================
16
17 // ----------------------------------------------------------------------------
18 // headers
19 // ----------------------------------------------------------------------------
20
21 // For compilers that support precompilation, includes "wx.h".
22 #include "wx/wxprec.h"
23
24 #ifdef __BORLANDC__
25 #pragma hdrstop
26 #endif
27
28 #ifndef WX_PRECOMP
29 #include "wx/wx.h"
30 #endif
31
32 // Settings common to both executables: determines whether
33 // we're using TCP/IP or real DDE.
34 #include "ipcsetup.h"
35
36 #include "connection.h"
37
38 #include "wx/timer.h"
39 #include "wx/datetime.h"
40 #include "wx/vector.h"
41
42 class MyClient;
43
44 // ----------------------------------------------------------------------------
45 // classes
46 // ----------------------------------------------------------------------------
47
48 class MyApp : public wxApp
49 {
50 public:
51 MyApp() { Connect(wxEVT_IDLE, wxIdleEventHandler(MyApp::OnIdle)); }
52
53 virtual bool OnInit();
54 virtual int OnExit();
55
56 private:
57 void OnIdle(wxIdleEvent& event);
58
59 MyClient *m_client;
60 };
61
62 class MyConnection : public MyConnectionBase
63 {
64 public:
65 virtual bool DoExecute(const void *data, size_t size, wxIPCFormat format);
66 virtual const void *Request(const wxString& item, size_t *size = NULL, wxIPCFormat format = wxIPC_TEXT);
67 virtual bool DoPoke(const wxString& item, const void* data, size_t size, wxIPCFormat format);
68 virtual bool OnAdvise(const wxString& topic, const wxString& item, const void *data, size_t size, wxIPCFormat format);
69 virtual bool OnDisconnect();
70 };
71
72 class MyClient : public wxClient,
73 private wxTimer
74 {
75 public:
76 MyClient();
77 virtual ~MyClient();
78
79 bool Connect(const wxString& sHost, const wxString& sService, const wxString& sTopic);
80 void Disconnect();
81 wxConnectionBase *OnMakeConnection();
82 bool IsConnected() { return m_connection != NULL; };
83
84 virtual void Notify();
85
86 void StartNextTestIfNecessary();
87
88 private:
89 void TestRequest();
90 void TestPoke();
91 void TestExecute();
92 void TestStartAdvise();
93 void TestStopAdvise();
94 void TestDisconnect();
95
96
97 MyConnection *m_connection;
98
99 // the test functions to be executed by StartNextTestIfNecessary()
100 typedef void (MyClient::*MyClientTestFunc)();
101 wxVector<MyClientTestFunc> m_tests;
102
103 // number of seconds since the start of the test
104 int m_step;
105 };
106
107 // ============================================================================
108 // implementation
109 // ============================================================================
110
111 IMPLEMENT_APP_CONSOLE(MyApp)
112
113 // ----------------------------------------------------------------------------
114 // MyApp
115 // ----------------------------------------------------------------------------
116
117 // The `main program' equivalent, creating the windows and returning the
118 // main frame
119 bool MyApp::OnInit()
120 {
121 if ( !wxApp::OnInit() )
122 return false;
123
124 // Create a new client
125 m_client = new MyClient;
126 bool retval = m_client->Connect("localhost", "4242", "IPC TEST");
127
128 wxLogMessage("Client host=\"localhost\" port=\"4242\" topic=\"IPC TEST\" %s",
129 retval ? "connected" : "failed to connect");
130
131 return retval;
132 }
133
134 int MyApp::OnExit()
135 {
136 delete m_client;
137
138 return 0;
139 }
140
141 void MyApp::OnIdle(wxIdleEvent& event)
142 {
143 if ( m_client )
144 m_client->StartNextTestIfNecessary();
145
146 event.Skip();
147 }
148
149 // ----------------------------------------------------------------------------
150 // MyClient
151 // ----------------------------------------------------------------------------
152
153 MyClient::MyClient()
154 : wxClient()
155 {
156 m_connection = NULL;
157 m_step = 0;
158 }
159
160 bool
161 MyClient::Connect(const wxString& sHost,
162 const wxString& sService,
163 const wxString& sTopic)
164 {
165 // suppress the log messages from MakeConnection()
166 wxLogNull nolog;
167
168 m_connection = (MyConnection *)MakeConnection(sHost, sService, sTopic);
169 if ( !m_connection )
170 return false;
171
172 Start(1000);
173
174 return true;
175 }
176
177 wxConnectionBase *MyClient::OnMakeConnection()
178 {
179 return new MyConnection;
180 }
181
182 void MyClient::Disconnect()
183 {
184 if (m_connection)
185 {
186 m_connection->Disconnect();
187 delete m_connection;
188 m_connection = NULL;
189 wxLogMessage("Client disconnected from server");
190 }
191 wxGetApp().ExitMainLoop();
192 }
193
194 MyClient::~MyClient()
195 {
196 Disconnect();
197 }
198
199 void MyClient::Notify()
200 {
201 // we shouldn't call wxIPC methods from here directly as we may be called
202 // from inside an IPC call when using TCP/IP as the sockets are used in
203 // non-blocking code and so can dispatch events, including the timer ones,
204 // while waiting for IO and so starting another IPC call would result in
205 // fatal reentrancies -- instead, just set a flag and perform the test
206 // indicated by it later from our idle event handler
207 MyClientTestFunc testfunc = NULL;
208 switch ( m_step++ )
209 {
210 case 0:
211 testfunc = &MyClient::TestRequest;
212 break;
213
214 case 1:
215 testfunc = &MyClient::TestPoke;
216 break;
217
218 case 2:
219 testfunc = &MyClient::TestExecute;
220 break;
221
222 case 3:
223 testfunc = &MyClient::TestStartAdvise;
224 break;
225
226 case 10:
227 testfunc = &MyClient::TestStopAdvise;
228 break;
229
230 case 15:
231 testfunc = &MyClient::TestDisconnect;
232 // We don't need the timer any more, we're going to exit soon.
233 Stop();
234 break;
235
236 default:
237 // No need to wake up idle handling.
238 return;
239 }
240
241 m_tests.push_back(testfunc);
242
243 wxWakeUpIdle();
244 }
245
246 void MyClient::StartNextTestIfNecessary()
247 {
248 while ( !m_tests.empty() )
249 {
250 MyClientTestFunc testfunc = m_tests.front();
251 m_tests.erase(m_tests.begin());
252 (this->*testfunc)();
253 }
254 }
255
256 void MyClient::TestRequest()
257 {
258 size_t size;
259 m_connection->Request("Date");
260 m_connection->Request("Date+len", &size);
261 m_connection->Request("bytes[3]", &size, wxIPC_PRIVATE);
262 }
263
264 void MyClient::TestPoke()
265 {
266 wxString s = wxDateTime::Now().Format();
267 m_connection->Poke("Date", s);
268 s = wxDateTime::Now().FormatTime() + " " + wxDateTime::Now().FormatDate();
269 m_connection->Poke("Date", (const char *)s.c_str(), s.length() + 1);
270 char bytes[3];
271 bytes[0] = '1'; bytes[1] = '2'; bytes[2] = '3';
272 m_connection->Poke("bytes[3]", bytes, 3, wxIPC_PRIVATE);
273 }
274
275 void MyClient::TestExecute()
276 {
277 wxString s = "Date";
278 m_connection->Execute(s);
279 m_connection->Execute((const char *)s.c_str(), s.length() + 1);
280 char bytes[3];
281 bytes[0] = '1';
282 bytes[1] = '2';
283 bytes[2] = '3';
284 m_connection->Execute(bytes, WXSIZEOF(bytes));
285 }
286
287 void MyClient::TestStartAdvise()
288 {
289 wxLogMessage("StartAdvise(\"something\")");
290 m_connection->StartAdvise("something");
291 }
292
293 void MyClient::TestStopAdvise()
294 {
295 wxLogMessage("StopAdvise(\"something\")");
296 m_connection->StopAdvise("something");
297 }
298
299 void MyClient::TestDisconnect()
300 {
301 Disconnect();
302 }
303
304 // ----------------------------------------------------------------------------
305 // MyConnection
306 // ----------------------------------------------------------------------------
307
308 bool MyConnection::OnAdvise(const wxString& topic, const wxString& item, const void *data,
309 size_t size, wxIPCFormat format)
310 {
311 Log("OnAdvise", topic, item, data, size, format);
312 return true;
313 }
314
315 bool MyConnection::OnDisconnect()
316 {
317 wxLogMessage("OnDisconnect()");
318 wxGetApp().ExitMainLoop();
319 return true;
320 }
321
322 bool MyConnection::DoExecute(const void *data, size_t size, wxIPCFormat format)
323 {
324 Log("Execute", wxEmptyString, wxEmptyString, data, size, format);
325 bool retval = wxConnection::DoExecute(data, size, format);
326 if (!retval)
327 {
328 wxLogMessage("Execute failed!");
329 }
330 return retval;
331 }
332
333 const void *MyConnection::Request(const wxString& item, size_t *size, wxIPCFormat format)
334 {
335 const void *data = wxConnection::Request(item, size, format);
336 Log("Request", wxEmptyString, item, data, size ? *size : wxNO_LEN, format);
337 return data;
338 }
339
340 bool MyConnection::DoPoke(const wxString& item, const void *data, size_t size, wxIPCFormat format)
341 {
342 Log("Poke", wxEmptyString, item, data, size, format);
343 return wxConnection::DoPoke(item, data, size, format);
344 }