RemoteProcedure.h
1/*
2 Copyright (C) 2009-2026 by Marc Duerner
3
4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Lesser General Public
6 License as published by the Free Software Foundation; either
7 version 2.1 of the License, or (at your option) any later version.
8
9 As a special exception, you may use this file as part of a free
10 software library without restriction. Specifically, if other files
11 instantiate templates or use macros or inline functions from this
12 file, or you compile this file and link it with other files to
13 produce an executable, this file does not by itself cause the
14 resulting executable to be covered by the GNU General Public
15 License. This exception does not however invalidate any other
16 reasons why the executable file might be covered by the GNU Library
17 General Public License.
18
19 This library is distributed in the hope that it will be useful,
20 but WITHOUT ANY WARRANTY; without even the implied warranty of
21 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22 Lesser General Public License for more details.
23
24 You should have received a copy of the GNU Lesser General Public
25 License along with this library; if not, write to the:
26 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
27 Boston, MA 02110-1301 USA
28*/
29
30#ifndef PT_REMOTING_REMOTEPROCEDURE_H
31#define PT_REMOTING_REMOTEPROCEDURE_H
32
33#include <Pt/Remoting/Api.h>
34#include <Pt/Remoting/Client.h>
35#include <Pt/SerializationContext.h>
36#include <Pt/Composer.h>
37#include <Pt/Decomposer.h>
38#include <Pt/NonCopyable.h>
39#include <Pt/Signal.h>
40#include <Pt/String.h>
41#include <cstddef>
42#include <string>
43
44namespace Pt {
45
46namespace Remoting {
47
50class PT_REMOTING_API RemoteCall : private Pt::NonCopyable
51{
52 public:
53 RemoteCall(Client& client, const String& name);
54
55 RemoteCall(Client& client, const std::string& name);
56
57 RemoteCall(Client& client, const char* name);
58
59 virtual ~RemoteCall();
60
64 { return *_client; }
65
68 const String& name() const
69 { return _name; }
70
73 bool isFailed() const
74 { return _client->isFailed(); }
75
78 void cancel();
79
82 void setReady();
83
86 void endCall();
87
88 protected:
91 virtual void onReady() = 0;
92
95 virtual void onReset() = 0;
96
99 virtual void onClear() = 0;
100
101 private:
102 Client* _client;
103 String _name;
104};
105
106
109template <typename R>
110class Result : private Pt::NonCopyable
111{
112 public:
115 explicit Result(RemoteCall* call = 0)
116 : _call(call)
117 , _result(0)
118 {
119 _result = new (_mem) R;
120 }
121
122 ~Result()
123 {
124 _result->~R();
125 }
126
127 void init(RemoteCall* call)
128 { _call = call; }
129
134 bool isFailed() const
135 {
136 return _call->isFailed();
137 }
138
141 R& value()
142 { return *_result; }
143
151 const R& get() const
152 {
153 _call->endCall();
154 return *_result;
155 }
156
157 void clear()
158 {
159 _result->~R();
160 _result = new (_mem) R;
161 }
162
163 private:
164 RemoteCall* _call;
165 char _mem[ sizeof(R) ];
166 R* _result;
167};
168
169
172template <typename R>
173class RemoteProcedureBase : public RemoteCall
174{
175 public:
176 RemoteProcedureBase(Client& client, const std::string& name)
177 : RemoteCall(client, name)
178 , _result(0)
179 , _r(0)
180 {
181 _result.init(this);
182 }
183
184 ~RemoteProcedureBase()
185 {
186 if(_r)
187 _r->~BasicComposer<R>();
188 }
189
193 {
194 return _result;
195 }
196
199 const Result<R>& result() const
200 {
201 return _result;
202 }
203
207 { return _finished; }
208
209 protected:
210 void onReady()
211 { _finished.send(_result); }
212
213 BasicComposer<R>& beginResult()
214 {
215 if(_r)
216 {
217 _r->~BasicComposer<R>();
218 _r = 0;
219 }
220
221 _r = new (_mem) BasicComposer<R>( &client().context() );
222 _r->begin( result().value() );
223 return *_r;
224 }
225
226 virtual void onReset()
227 {
228 if(_r)
229 {
230 _r->~BasicComposer<R>();
231 _r = 0;
232 }
233 }
234
235 virtual void onClear()
236 {
237 this->onReset();
238 _result.clear();
239 }
240
241 private:
242 Signal< const Result<R>& > _finished;
243 Result<R> _result;
244 char _mem[ sizeof(BasicComposer<R>) ];
245 BasicComposer<R>* _r;
246};
247
248
249template <typename A>
250class RemoteArgument : private Pt::NonCopyable
251{
252 public:
253 RemoteArgument(SerializationContext* )
254 : _decomposer(0)
255 { }
256
257 ~RemoteArgument()
258 {
259 if(_decomposer)
260 _decomposer->~BasicDecomposer<A>();
261 }
262
263 void begin(const A& a, const char* name, SerializationContext& ctx)
264 {
265 if(_decomposer)
266 {
267 _decomposer->~BasicDecomposer<A>();
268 _decomposer = 0;
269 }
270
271 _decomposer = new (_mem) BasicDecomposer<A>(&ctx);
272 _decomposer->begin(a, name);
273 }
274
275 void clear(SerializationContext* )
276 {
277 if(_decomposer)
278 {
279 _decomposer->~BasicDecomposer<A>();
280 _decomposer = 0;
281 }
282 }
283
284 // TODO: return decomposer pointer from begin
285 BasicDecomposer<A>* decomposer()
286 { return reinterpret_cast<BasicDecomposer<A>*>(_mem); }
287
288 private:
289 char _mem[ sizeof(BasicDecomposer<A>) ];
290 BasicDecomposer<A>* _decomposer;
291};
292
293
294template <typename... Ts>
295class RemoteArguments;
296
297
298template <>
299class RemoteArguments<>
300{
301 public:
302 explicit RemoteArguments(SerializationContext* /*ctx*/)
303 { }
304
305 void begin(SerializationContext& /*ctx*/)
306 { }
307
308 void fill(std::size_t i, Decomposer** args)
309 {
310 args[i] = 0;
311 }
312
313 void clear(SerializationContext* /*ctx*/)
314 { }
315};
316
317
318template <typename T, typename... Ts>
319class RemoteArguments<T, Ts...>
320{
321 public:
322 explicit RemoteArguments(SerializationContext* ctx)
323 : _head(ctx)
324 , _tail(ctx)
325 { }
326
327 void begin(SerializationContext& ctx, const T& a, const Ts&... as)
328 {
329 _head.begin(a, "", ctx);
330 _tail.begin(ctx, as...);
331 }
332
333 void fill(std::size_t i, Decomposer** args)
334 {
335 args[i] = _head.decomposer();
336 _tail.fill(i + 1, args);
337 }
338
339 void clear(SerializationContext* ctx)
340 {
341 _head.clear(ctx);
342 _tail.clear(ctx);
343 }
344
345 private:
346 RemoteArgument<T> _head;
347 RemoteArguments<Ts...> _tail;
348};
349
350
372template <typename R, typename... As>
373class RemoteProcedure : public RemoteProcedureBase<R>
374{
375 public:
378 RemoteProcedure(Client& client, const std::string& name)
379 : RemoteProcedureBase<R>(client, name)
380 , _argv( &client.context() )
381 {
382 _argv.fill(0, _args);
383 }
384
388 { }
389
392 void begin(const As&... args)
393 {
394 try
395 {
396 _argv.begin(this->client().context(), args...);
397 BasicComposer<R>& r = this->beginResult();
398
399 this->client().beginCall(r, *this, _args, sizeof...(As));
400 }
401 catch(...)
402 {
403 this->onClear();
404 throw;
405 }
406 }
407
410 const R& call(const As&... args)
411 {
412 try
413 {
414 _argv.begin(this->client().context(), args...);
415 BasicComposer<R>& r = this->beginResult();
416
417 this->client().call(r, *this, _args, sizeof...(As));
418 this->onReset();
419 }
420 catch(...)
421 {
422 this->onClear();
423 throw;
424 }
425
426 return this->result().value();
427 }
428
431 const R& operator()(const As&... args)
432 {
433 return this->call(args...);
434 }
435
436 protected:
437 void onReset()
438 {
439 RemoteProcedureBase<R>::onReset();
440 _argv.clear( &this->client().context() );
441 }
442
443 private:
444 RemoteArguments<As...> _argv;
445 Decomposer* _args[sizeof...(As) + 1];
446};
447
448} // namespace Remoting
449
450} // namespace Pt
451
452#endif // PT_REMOTING_REMOTEPROCEDURE_H
Composes serializable types during serialization.
Definition Composer.h:327
void begin(T &type)
Begin composing a type.
Definition Composer.h:337
Manages the decomposition of types during serialization.
Definition Decomposer.h:121
Base class that disables copy construction and assignment.
Definition NonCopyable.h:59
A client for remote procedure calls.
Definition Client.h:48
void cancel()
Cancels the remote call.
Result< R > & result()
Returns the result of the call.
Definition RemoteProcedure.h:192
void begin(const As &... args)
Begins an asynchronous remote call.
Definition RemoteProcedure.h:392
const R & operator()(const As &... args)
Blocking remote call.
Definition RemoteProcedure.h:431
Signal< const Result< R > & > & finished()
Reports that the result has been received.
Definition RemoteProcedure.h:206
RemoteProcedure(Client &client, const std::string &name)
Construct with procedure name and client.
Definition RemoteProcedure.h:378
Client & client()
Returns the client used for communication.
Definition RemoteProcedure.h:63
const String & name() const
Returns the name of the procedure.
Definition RemoteProcedure.h:68
const R & call(const As &... args)
Blocking remote call.
Definition RemoteProcedure.h:410
bool isFailed() const
Returns true if the procedure failed.
Definition RemoteProcedure.h:73
virtual ~RemoteProcedure()
Destructor.
Definition RemoteProcedure.h:387
const Result< R > & result() const
Returns the result of the call.
Definition RemoteProcedure.h:199
Result of a remote procedure call.
Definition RemoteProcedure.h:111
const R & get() const
Ends a remote procedure call.
Definition RemoteProcedure.h:151
bool isFailed() const
Indicates if the procedure has failed.
Definition RemoteProcedure.h:134
R & value()
The return value.
Definition RemoteProcedure.h:141
Result(RemoteCall *call=0)
Constructor.
Definition RemoteProcedure.h:115
Multicast Signal to call multiple slots.
Definition Signal.h:190
Unicode capable basic_string.
Definition Api-String.h:67
Remote services and clients.
Definition HttpService.h:39
Core module.
Definition Allocator.h:33