request-response.cpp 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102
  1. //
  2. // Copyright (c) 2019 Ivan Baidakou (basiliscos) (the dot dmol at gmail dot com)
  3. //
  4. // Distributed under the MIT Software License
  5. //
  6. // in the example the usage of request-response pattern is demonstrated
  7. // the "server" actor takes the number from request and replies to
  8. // "client" actor with square root if the value is >= 0, otherwise
  9. // it replies with error.
  10. //
  11. // The key point here is that request is timeout supervised, i.e.
  12. // if the server will not answer with the specified timeout,
  13. // the client will know that.
  14. #include "rotor.hpp"
  15. #include "rotor/asio.hpp"
  16. #include <iostream>
  17. #include <cmath>
  18. #include <system_error>
  19. namespace asio = boost::asio;
  20. namespace pt = boost::posix_time;
  21. namespace payload {
  22. struct sample_res_t {
  23. double value;
  24. };
  25. struct sample_req_t {
  26. using response_t = sample_res_t;
  27. double value;
  28. };
  29. } // namespace payload
  30. namespace message {
  31. using request_t = rotor::request_traits_t<payload::sample_req_t>::request::message_t;
  32. using response_t = rotor::request_traits_t<payload::sample_req_t>::response::message_t;
  33. } // namespace message
  34. struct server_actor : public rotor::actor_base_t {
  35. using rotor::actor_base_t::actor_base_t;
  36. void on_request(message::request_t &req) noexcept {
  37. auto in = req.payload.request_payload.value;
  38. if (in >= 0) {
  39. auto value = std::sqrt(in);
  40. reply_to(req, value);
  41. } else {
  42. // IRL, it should be your custom error codes
  43. auto ec = std::make_error_code(std::errc::invalid_argument);
  44. reply_with_error(req, ec);
  45. }
  46. }
  47. void init_start() noexcept override {
  48. subscribe(&server_actor::on_request);
  49. rotor::actor_base_t::init_start();
  50. }
  51. };
  52. struct client_actor : public rotor::actor_base_t {
  53. using rotor::actor_base_t::actor_base_t;
  54. rotor::address_ptr_t server_addr;
  55. void set_server(const rotor::address_ptr_t addr) { server_addr = addr; }
  56. void init_start() noexcept override {
  57. subscribe(&client_actor::on_response);
  58. rotor::actor_base_t::init_start();
  59. }
  60. void on_response(message::response_t &res) noexcept {
  61. if (!res.payload.ec) { // check for possible error
  62. auto &in = res.payload.req->payload.request_payload.value;
  63. auto &out = res.payload.res.value;
  64. std::cout << " in = " << in << ", out = " << out << "\n";
  65. }
  66. supervisor.do_shutdown(); // optional;
  67. }
  68. void on_start(rotor::message_t<rotor::payload::start_actor_t> &msg) noexcept override {
  69. rotor::actor_base_t::on_start(msg);
  70. auto timeout = rotor::pt::milliseconds{1};
  71. request<payload::sample_req_t>(server_addr, 25.0).send(timeout);
  72. }
  73. };
  74. int main() {
  75. asio::io_context io_context;
  76. auto system_context = rotor::asio::system_context_asio_t::ptr_t{new rotor::asio::system_context_asio_t(io_context)};
  77. auto stand = std::make_shared<asio::io_context::strand>(io_context);
  78. auto timeout = boost::posix_time::milliseconds{500};
  79. rotor::asio::supervisor_config_asio_t conf{timeout, std::move(stand)};
  80. auto sup = system_context->create_supervisor<rotor::asio::supervisor_asio_t>(conf);
  81. auto server = sup->create_actor<server_actor>(timeout);
  82. auto client = sup->create_actor<client_actor>(timeout);
  83. client->set_server(server->get_address());
  84. sup->do_process();
  85. return 0;
  86. }