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.
 
 
 
 
 
 

170 lines
5.2 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. #include <cppcms/application.h>
  20. #include <cppcms/url_dispatcher.h>
  21. #include <cppcms/applications_pool.h>
  22. #include <cppcms/service.h>
  23. #include <cppcms/http_response.h>
  24. #include <cppcms/http_request.h>
  25. #include <cppcms/http_context.h>
  26. #include <cppcms/rpc_json.h>
  27. #include <cppcms/json.h>
  28. #include <booster/intrusive_ptr.h>
  29. #include <booster/aio/deadline_timer.h>
  30. #include <booster/system_error.h>
  31. #include <set>
  32. #include <boost/bind.hpp>
  33. using boost::bind;
  34. class chat : public cppcms::rpc::json_rpc_server {
  35. public:
  36. chat(cppcms::service &srv) :
  37. cppcms::rpc::json_rpc_server(srv),
  38. timer_(srv.get_io_service())
  39. {
  40. // Our main methods
  41. bind("post",cppcms::rpc::json_method(&chat::post,this),notification_role);
  42. bind("get",cppcms::rpc::json_method(&chat::get,this),method_role);
  43. // Add timeouts to the system
  44. last_wake_ = time(0);
  45. on_timer(booster::system::error_code());
  46. }
  47. // Handle new message call
  48. void post(std::string const &author,std::string const &message)
  49. {
  50. cppcms::json::value obj;
  51. obj["author"]=author;
  52. obj["message"]=message;
  53. messages_.push_back(obj);
  54. broadcast(messages_.size()-1);
  55. }
  56. void on_timer(booster::system::error_code const &e)
  57. {
  58. if(e) return; // cancelation
  59. // check idle connections for more then 10 seconds
  60. if(time(0) - last_wake_ > 10) {
  61. broadcast(messages_.size());
  62. }
  63. // restart timer
  64. timer_.expires_from_now(booster::ptime::seconds(1));
  65. timer_.async_wait(boost::bind(&chat::on_timer,booster::intrusive_ptr<chat>(this),_1));
  66. }
  67. // Handle request
  68. void get(unsigned from)
  69. {
  70. if(from < messages_.size()) {
  71. // not long polling - return result now
  72. return_result(make_response(from));
  73. return;
  74. }
  75. else if(from == messages_.size()) {
  76. // Can't answer now
  77. // Add long polling request to the list
  78. booster::shared_ptr<cppcms::rpc::json_call> call=release_call();
  79. waiters_.insert(call);
  80. // set disconnect callback
  81. call->context().async_on_peer_reset(
  82. boost::bind(
  83. &chat::remove_context,
  84. booster::intrusive_ptr<chat>(this),
  85. call));
  86. }
  87. else {
  88. return_error("Invalid position");
  89. }
  90. }
  91. // handle client disconnect
  92. void remove_context(booster::shared_ptr<cppcms::rpc::json_call> call)
  93. {
  94. waiters_.erase(call);
  95. }
  96. void broadcast(size_t from)
  97. {
  98. // update timeout
  99. last_wake_ = time(0);
  100. // Prepare response
  101. cppcms::json::value response = make_response(from);
  102. // Send it to everybody
  103. for(waiters_type::iterator waiter=waiters_.begin();waiter!=waiters_.end();++waiter) {
  104. booster::shared_ptr<cppcms::rpc::json_call> call = *waiter;
  105. call->return_result(response);
  106. }
  107. waiters_.clear();
  108. }
  109. // Prepare response to the client
  110. cppcms::json::value make_response(size_t n)
  111. {
  112. cppcms::json::value v;
  113. // Small optimization
  114. v=cppcms::json::array();
  115. cppcms::json::array &ar = v.array();
  116. ar.reserve(messages_.size() - n);
  117. // prepare all messages
  118. for(size_t i=n;i<messages_.size();i++) {
  119. ar.push_back(messages_[i]);
  120. }
  121. return v;
  122. }
  123. private:
  124. // message store
  125. std::vector<cppcms::json::value> messages_;
  126. // long poll requests
  127. typedef std::set<booster::shared_ptr<cppcms::rpc::json_call> > waiters_type;
  128. waiters_type waiters_;
  129. // timer for resetting idle requests
  130. booster::aio::deadline_timer timer_;
  131. time_t last_wake_;
  132. };
  133. int main(int argc,char **argv)
  134. {
  135. try {
  136. cppcms::service service(argc,argv);
  137. booster::intrusive_ptr<chat> c=new chat(service);
  138. service.applications_pool().mount(c);
  139. service.run();
  140. }
  141. catch(std::exception const &e) {
  142. std::cerr<<"Catched exception: "<<e.what()<<std::endl;
  143. return 1;
  144. }
  145. return 0;
  146. }
  147. // vim: tabstop=4 expandtab shiftwidth=4 softtabstop=4