Menu

[r2023]: / framework / trunk / cppcms / rpc_json.h  Maximize  Restore  History

Download this file

372 lines (316 with data), 11.2 kB

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
///////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2008-2010 Artyom Beilis (Tonkikh) <artyomtnk@yahoo.com>
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
///////////////////////////////////////////////////////////////////////////////
#ifndef CPPCMS_RPC_JSON_OBJECT_H
#define CPPCMS_RPC_JSON_OBJECT_H
#include <cppcms/application.h>
#include <booster/function.h>
#include <cppcms/json.h>
#include <cppcms/cppcms_error.h>
namespace cppcms {
///
/// \brief This namespace holds API for implementing various RPC APIs, like JsonRPC
///
namespace rpc {
///
/// \brief The error thrown in case of bad call - parameters mismatch or
/// invalid request.
///
/// User should may throw it case of a error as invalid request inside the
/// method. However return_error() is preferred.
///
class CPPCMS_API call_error : public cppcms_error {
public:
///
/// Define error message
///
call_error(std::string const &message);
};
class json_rpc_server;
///
/// \brief This class represents single call of json-rpc method.
///
/// It is used
/// for handling asynchronous responses only. Similar API is provided
/// in json_rpc_server class for synchronous methods.
///
class CPPCMS_API json_call : public booster::noncopyable {
public:
///
/// Destructor. Automatically deletes appropriate context as once it given to user it owns it.
///
~json_call();
///
/// Get the name of method that was called
///
std::string method();
///
/// Check if method call is notification only. You should not return a value.
///
/// Note: if you do not add restriction when binding json-rpc method on the role of the call
/// you should always check this value. Otherwise trying to call return_result or return_error
/// would throw.
///
bool notification();
///
/// Get call parameters as json::array (vector of json::value)
///
json::array const &params();
///
/// Get context associated with the call. This you may wait on events like async_on_peer_reset
/// of http::context via this member.
///
http::context &context();
///
/// Complete method response with a result. Throws call_error if the method was called as notification
///
void return_result(json::value const &);
///
/// Complete method response with a error. Throws call_error if the method was called as notification
///
void return_error(json::value const &);
private:
json_call(http::context &context);
friend class json_rpc_server;
void return_result(http::context &,json::value const &);
void return_error(http::context &,json::value const &);
void attach_context(booster::shared_ptr<http::context> context);
void check_not_notification();
booster::shared_ptr<http::context> context_;
json::value id_;
json::array params_;
std::string method_;
bool notification_;
struct _data;
booster::hold_ptr<_data> d;
};
///
/// \brief JSON-RPC service application.
///
/// User is expected to derive his own objects from this class in order to implement Json-RPC calls
/// similarly to how cppcms::application is used.
///
class CPPCMS_API json_rpc_server : public application {
public:
///
/// The role of the method - receives notification, returns result or any one of them
///
typedef enum {
any_role, ///< Method may receive notification and return result
method_role, ///< Method can't be used with notification calls
notification_role ///< Method should be used with notification calls only
} role_type;
///
/// Generic type of JSON-RPC method
///
typedef booster::function<void(json::array const &)> method_type;
///
/// Bind method JSON-RPC method with name \a name
///
void bind(std::string const &name,method_type const &,role_type type = any_role);
///
/// Specify service SMD
///
void smd(json::value const &);
///
/// Specify service SMD as raw text rather then JSON value
///
void smd_raw(std::string const &);
///
/// Take service SMD as raw text from file
///
void smd_from_file(std::string const &);
///
/// Main function that dispatches JSON-RPC service calls
///
virtual void main(std::string);
///
/// Release json_call for asynchronous responses. Calls release_context() and
/// assignes it to json_call object.
///
booster::shared_ptr<json_call> release_call();
json_rpc_server(cppcms::service &srv);
~json_rpc_server();
///
/// Get the name of method that was called
///
std::string method();
///
/// Check if method call is notification only. You should not return a value.
///
/// Note: if you do not add restriction when binding json-rpc method on the role of the call
/// you should always check this value. Otherwise trying to call return_result or return_error
/// would throw.
///
bool notification();
///
/// Get call parameters as json::array (vector of json::value)
///
json::array const &params();
///
/// Complete method response with a result. Throws call_error if the method was called as notification
///
void return_result(json::value const &);
///
/// Complete method response with a error. Throws call_error if the method was called as notification
///
void return_error(json::value const &);
private:
void check_call();
struct method_data {
method_type method;
role_type role;
};
typedef std::map<std::string,method_data> methods_map_type;
methods_map_type methods_;
booster::shared_ptr<json_call> current_call_;
std::string smd_;
struct _data;
booster::hold_ptr<_data> d;
};
/// \cond INTERNAL
namespace details {
template<typename T> struct fw_ret { typedef T type; };
template<typename T> struct fw_ret<T const &> { typedef T type; };
template<typename T> struct fw_ret<T const> { typedef T type; };
template<> struct fw_ret<json::value> { typedef json::value const &type; };
template<> struct fw_ret<json::object> { typedef json::object const &type; };
template<> struct fw_ret<json::array> { typedef json::array const &type; };
template<> struct fw_ret<std::string> { typedef std::string const &type; };
template<> struct fw_ret<json::value const &> { typedef json::value const &type; };
template<> struct fw_ret<json::object const &> { typedef json::object const &type; };
template<> struct fw_ret<json::array const &> { typedef json::array const &type; };
template<> struct fw_ret<std::string const &> { typedef std::string const &type; };
template<> struct fw_ret<json::value const> { typedef json::value const &type; };
template<> struct fw_ret<json::object const> { typedef json::object const &type; };
template<> struct fw_ret<json::array const> { typedef json::array const &type; };
template<> struct fw_ret<std::string const> { typedef std::string const &type; };
template<typename T>
struct fw_ret_handle {
static typename fw_ret<T>::type extract(json::value const &v)
{
return v.get_value<typename fw_ret<T>::type>();
}
};
template<>
struct fw_ret_handle<json::value const &>
{
static json::value const &extract(json::value const &v)
{
return v;
}
};
template<>
struct fw_ret_handle<json::array const &>
{
static json::array const &extract(json::value const &v)
{
return v.array();
}
};
template<>
struct fw_ret_handle<json::object const &>
{
static json::object const &extract(json::value const &v)
{
return v.object();
}
};
template<>
struct fw_ret_handle<std::string const &>
{
static std::string const &extract(json::value const &v)
{
return v.str();
}
};
template <typename T>
inline typename fw_ret<T>::type forward_value(json::value const &v)
{
typedef typename fw_ret<T>::type return_type;
return fw_ret_handle<return_type>::extract(v);
}
}
#define CPPCMS_JSON_RPC_BINDER(N) \
namespace details { \
template<typename Class,typename Ptr CPPCMS_TEMPLATE_PARAMS> \
struct binder##N { \
Ptr object; \
void (Class::*member)(CPPCMS_FUNC_PARAMS); \
void operator()(json::array const &a) const \
{ \
if(a.size()!=N) \
throw call_error("Invalid parametres number"); \
((*object).*member)(CPPCMS_CALL_PARAMS); \
} \
}; \
} \
template<typename Class,typename Ptr CPPCMS_TEMPLATE_PARAMS> \
details::binder##N<Class,Ptr CPPCMS_BINDER_PARAMS> \
json_method(void (Class::*m)(CPPCMS_FUNC_PARAMS),Ptr p) \
{ details::binder##N<Class,Ptr CPPCMS_BINDER_PARAMS> tmp={p,m}; return tmp; } \
#define CPPCMS_TEMPLATE_PARAMS
#define CPPCMS_FUNC_PARAMS
#define CPPCMS_CALL_PARAMS
#define CPPCMS_BINDER_PARAMS
CPPCMS_JSON_RPC_BINDER(0)
#undef CPPCMS_TEMPLATE_PARAMS
#undef CPPCMS_FUNC_PARAMS
#undef CPPCMS_CALL_PARAMS
#undef CPPCMS_BINDER_PARAMS
#define CPPCMS_TEMPLATE_PARAMS ,typename P1
#define CPPCMS_FUNC_PARAMS P1
#define CPPCMS_CALL_PARAMS forward_value<P1>(a[0])
#define CPPCMS_BINDER_PARAMS ,P1
CPPCMS_JSON_RPC_BINDER(1)
#undef CPPCMS_TEMPLATE_PARAMS
#undef CPPCMS_FUNC_PARAMS
#undef CPPCMS_CALL_PARAMS
#undef CPPCMS_BINDER_PARAMS
#define CPPCMS_TEMPLATE_PARAMS ,typename P1,typename P2
#define CPPCMS_FUNC_PARAMS P1,P2
#define CPPCMS_CALL_PARAMS forward_value<P1>(a[0]), forward_value<P2>(a[1])
#define CPPCMS_BINDER_PARAMS ,P1,P2
CPPCMS_JSON_RPC_BINDER(2)
#undef CPPCMS_TEMPLATE_PARAMS
#undef CPPCMS_FUNC_PARAMS
#undef CPPCMS_CALL_PARAMS
#undef CPPCMS_BINDER_PARAMS
#define CPPCMS_TEMPLATE_PARAMS ,typename P1,typename P2,typename P3
#define CPPCMS_FUNC_PARAMS P1,P2,P3
#define CPPCMS_CALL_PARAMS forward_value<P1>(a[0]), forward_value<P2>(a[1]), forward_value<P3>(a[2])
#define CPPCMS_BINDER_PARAMS ,P1,P2,P3
CPPCMS_JSON_RPC_BINDER(3)
#undef CPPCMS_TEMPLATE_PARAMS
#undef CPPCMS_FUNC_PARAMS
#undef CPPCMS_CALL_PARAMS
#undef CPPCMS_BINDER_PARAMS
#define CPPCMS_TEMPLATE_PARAMS ,typename P1,typename P2,typename P3,typename P4
#define CPPCMS_FUNC_PARAMS P1,P2,P3,P4
#define CPPCMS_CALL_PARAMS forward_value<P1>(a[0]), forward_value<P2>(a[1]), forward_value<P3>(a[2]), forward_value<P4>(a[3])
#define CPPCMS_BINDER_PARAMS ,P1,P2,P3,P4
CPPCMS_JSON_RPC_BINDER(4)
#undef CPPCMS_TEMPLATE_PARAMS
#undef CPPCMS_FUNC_PARAMS
#undef CPPCMS_CALL_PARAMS
#undef CPPCMS_BINDER_PARAMS
#undef CPPCMS_JSON_RPC_BINDER
/// \endcond
} // rpc
} // cppcms
#endif
MongoDB Logo MongoDB