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.
 
 
 
 
 
 

286 lines
8.5 KiB

  1. ///////////////////////////////////////////////////////////////////////////////
  2. //
  3. // Copyright (C) 2008-2010 Artyom Beilis (Tonkikh) <artyomtnk@yahoo.com>
  4. //
  5. // This program is free software: you can redistribute it and/or modify
  6. // it under the terms of the GNU Lesser General Public License as published by
  7. // the Free Software Foundation, either version 3 of the License, or
  8. // (at your option) any later version.
  9. //
  10. // This program is distributed in the hope that it will be useful,
  11. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. // GNU Lesser General Public License for more details.
  14. //
  15. // You should have received a copy of the GNU Lesser General Public License
  16. // along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. //
  18. ///////////////////////////////////////////////////////////////////////////////
  19. #ifndef CPPCMS_RPC_JSON_OBJECT_H
  20. #define CPPCMS_RPC_JSON_OBJECT_H
  21. #include <cppcms/application.h>
  22. #include <booster/function.h>
  23. #include <cppcms/json.h>
  24. #include <cppcms/cppcms_error.h>
  25. namespace cppcms {
  26. namespace rpc {
  27. ///
  28. /// The error thrown in case of bad call - parameters mismatch or
  29. /// invalid request.
  30. ///
  31. /// User should may throw it case of a error as invalid request inside the
  32. /// method. However return_error() is preferred.
  33. ///
  34. class CPPCMS_API call_error : public cppcms_error {
  35. public:
  36. ///
  37. /// Define error message
  38. ///
  39. call_error(std::string const &message);
  40. };
  41. class json_rpc_server;
  42. ///
  43. /// This class represents single call of json-rpc method. It is used
  44. /// for handling asynchronous responses only. Similar API is provided
  45. /// in json_rpc_server class for synchronous methods.
  46. ///
  47. class CPPCMS_API json_call : public booster::noncopyable {
  48. public:
  49. ///
  50. /// Destructor. Automatically deletes appropriate context as once it given to user it owns it.
  51. ///
  52. ~json_call();
  53. ///
  54. /// Get the name of method that was called
  55. ///
  56. std::string method();
  57. ///
  58. /// Check if method call is notification only. You should not return a value.
  59. ///
  60. /// Note: if you do not add restriction when binding json-rpc method on the role of the call
  61. /// you should always check this value. Otherwise trying to call return_result or return_error
  62. /// would throw.
  63. ///
  64. bool notification();
  65. ///
  66. /// Get call parameters as json::array (vector of json::value)
  67. ///
  68. json::array const &params();
  69. ///
  70. /// Get context associated with the call. This you may wait on events like async_on_peer_reset
  71. /// of http::context via this member.
  72. ///
  73. http::context &context();
  74. ///
  75. /// Complete method response with a result. Throws call_error if the method was called as notification
  76. ///
  77. void return_result(json::value const &);
  78. ///
  79. /// Complete method response with a error. Throws call_error if the method was called as notification
  80. ///
  81. void return_error(json::value const &);
  82. private:
  83. json_call(http::context &context);
  84. friend class json_rpc_server;
  85. void return_result(http::context &,json::value const &);
  86. void return_error(http::context &,json::value const &);
  87. void attach_context(booster::shared_ptr<http::context> context);
  88. void check_not_notification();
  89. booster::shared_ptr<http::context> context_;
  90. json::value id_;
  91. json::array params_;
  92. std::string method_;
  93. bool notification_;
  94. struct data;
  95. booster::hold_ptr<data> d;
  96. };
  97. ///
  98. /// JSON-RPC service provider
  99. ///
  100. class CPPCMS_API json_rpc_server : public application {
  101. public:
  102. ///
  103. /// The role of the method - receives notification, returns result or any one of them
  104. ///
  105. typedef enum {
  106. any_role, ///< Method may receive notification and return result
  107. method_role, ///< Method can't be used with notification calls
  108. notification_role ///< Method should be used with notification calls only
  109. } role_type;
  110. ///
  111. /// Generic type of JSON-RPC method
  112. ///
  113. typedef booster::function<void(json::array const &)> method_type;
  114. ///
  115. /// Bind method JSON-RPC method with name \a name
  116. ///
  117. void bind(std::string const &name,method_type const &,role_type type = any_role);
  118. ///
  119. /// Specify service SMD
  120. ///
  121. void smd(json::value const &);
  122. ///
  123. /// Specify service SMD as raw text rather then JSON value
  124. ///
  125. void smd_raw(std::string const &);
  126. ///
  127. /// Take service SMD as raw text from file
  128. ///
  129. void smd_from_file(std::string const &);
  130. ///
  131. /// Main function that dispatches JSON-RPC service calls
  132. ///
  133. virtual void main(std::string);
  134. ///
  135. /// Release json_call for asynchronous responses. Calls release_context() and
  136. /// assignes it to json_call object.
  137. ///
  138. booster::shared_ptr<json_call> release_call();
  139. json_rpc_server(cppcms::service &srv);
  140. ~json_rpc_server();
  141. ///
  142. /// Get the name of method that was called
  143. ///
  144. std::string method();
  145. ///
  146. /// Check if method call is notification only. You should not return a value.
  147. ///
  148. /// Note: if you do not add restriction when binding json-rpc method on the role of the call
  149. /// you should always check this value. Otherwise trying to call return_result or return_error
  150. /// would throw.
  151. ///
  152. bool notification();
  153. ///
  154. /// Get call parameters as json::array (vector of json::value)
  155. ///
  156. json::array const &params();
  157. ///
  158. /// Complete method response with a result. Throws call_error if the method was called as notification
  159. ///
  160. void return_result(json::value const &);
  161. ///
  162. /// Complete method response with a error. Throws call_error if the method was called as notification
  163. ///
  164. void return_error(json::value const &);
  165. private:
  166. void check_call();
  167. struct method_data {
  168. method_type method;
  169. role_type role;
  170. };
  171. typedef std::map<std::string,method_data> methods_map_type;
  172. methods_map_type methods_;
  173. booster::shared_ptr<json_call> current_call_;
  174. std::string smd_;
  175. struct data;
  176. booster::hold_ptr<data> d;
  177. };
  178. #define CPPCMS_JSON_RPC_BINDER(N) \
  179. namespace details { \
  180. template<typename Class,typename Ptr CPPCMS_TEMPLATE_PARAMS> \
  181. struct binder##N { \
  182. Ptr object; \
  183. void (Class::*member)(CPPCMS_FUNC_PARAMS); \
  184. void operator()(json::array const &a) const \
  185. { \
  186. if(a.size()!=N) \
  187. throw call_error("Invalid parametres number"); \
  188. ((*object).*member)(CPPCMS_CALL_PARAMS); \
  189. } \
  190. }; \
  191. } \
  192. template<typename Class,typename Ptr CPPCMS_TEMPLATE_PARAMS> \
  193. details::binder##N<Class,Ptr CPPCMS_BINDER_PARAMS> \
  194. json_method(void (Class::*m)(CPPCMS_FUNC_PARAMS),Ptr p) \
  195. { details::binder##N<Class,Ptr CPPCMS_BINDER_PARAMS> tmp={p,m}; return tmp; } \
  196. #define CPPCMS_TEMPLATE_PARAMS
  197. #define CPPCMS_FUNC_PARAMS
  198. #define CPPCMS_CALL_PARAMS
  199. #define CPPCMS_BINDER_PARAMS
  200. CPPCMS_JSON_RPC_BINDER(0)
  201. #undef CPPCMS_TEMPLATE_PARAMS
  202. #undef CPPCMS_FUNC_PARAMS
  203. #undef CPPCMS_CALL_PARAMS
  204. #undef CPPCMS_BINDER_PARAMS
  205. #define CPPCMS_TEMPLATE_PARAMS ,typename P1
  206. #define CPPCMS_FUNC_PARAMS P1
  207. #define CPPCMS_CALL_PARAMS a[0].get_value<P1>()
  208. #define CPPCMS_BINDER_PARAMS ,P1
  209. CPPCMS_JSON_RPC_BINDER(1)
  210. #undef CPPCMS_TEMPLATE_PARAMS
  211. #undef CPPCMS_FUNC_PARAMS
  212. #undef CPPCMS_CALL_PARAMS
  213. #undef CPPCMS_BINDER_PARAMS
  214. #define CPPCMS_TEMPLATE_PARAMS ,typename P1,typename P2
  215. #define CPPCMS_FUNC_PARAMS P1,P2
  216. #define CPPCMS_CALL_PARAMS a[0].get_value<P1>(),a[1].get_value<P2>()
  217. #define CPPCMS_BINDER_PARAMS ,P1,P2
  218. CPPCMS_JSON_RPC_BINDER(2)
  219. #undef CPPCMS_TEMPLATE_PARAMS
  220. #undef CPPCMS_FUNC_PARAMS
  221. #undef CPPCMS_CALL_PARAMS
  222. #undef CPPCMS_BINDER_PARAMS
  223. #define CPPCMS_TEMPLATE_PARAMS ,typename P1,typename P2,typename P3
  224. #define CPPCMS_FUNC_PARAMS P1,P2,P3
  225. #define CPPCMS_CALL_PARAMS a[0].get_value<P1>(),a[1].get_value<P2>(),a[2].get_value<P3>()
  226. #define CPPCMS_BINDER_PARAMS ,P1,P2,P3
  227. CPPCMS_JSON_RPC_BINDER(3)
  228. #undef CPPCMS_TEMPLATE_PARAMS
  229. #undef CPPCMS_FUNC_PARAMS
  230. #undef CPPCMS_CALL_PARAMS
  231. #undef CPPCMS_BINDER_PARAMS
  232. #define CPPCMS_TEMPLATE_PARAMS ,typename P1,typename P2,typename P3,typename P4
  233. #define CPPCMS_FUNC_PARAMS P1,P2,P3,P4
  234. #define CPPCMS_CALL_PARAMS a[0].get_value<P1>(),a[1].get_value<P2>(),a[2].get_value<P3>(), \
  235. a[3].get_value<P4>()
  236. #define CPPCMS_BINDER_PARAMS ,P1,P2,P3,P4
  237. CPPCMS_JSON_RPC_BINDER(4)
  238. #undef CPPCMS_TEMPLATE_PARAMS
  239. #undef CPPCMS_FUNC_PARAMS
  240. #undef CPPCMS_CALL_PARAMS
  241. #undef CPPCMS_BINDER_PARAMS
  242. #undef CPPCMS_JSON_RPC_BINDER
  243. } // rpc
  244. } // cppcms
  245. #endif