ChipMaster's trial hacks on C++CMS starting with v1.2.1. Not sure I'll follow on with the v2 since it looks to be breaking and mostly frivolous.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

361 lines
10 KiB

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