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