request-response-discovery.cpp 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113
  1. //
  2. // Copyright (c) 2019-2020 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. // this is an improved version, as client dynamically locates the server, i.e.
  15. // it pulls-in all dependencies
  16. #include "rotor.hpp"
  17. #include "rotor/asio.hpp"
  18. #include <iostream>
  19. #include <cmath>
  20. #include <system_error>
  21. namespace asio = boost::asio;
  22. namespace pt = boost::posix_time;
  23. namespace payload {
  24. struct sample_res_t {
  25. double value;
  26. };
  27. struct sample_req_t {
  28. using response_t = sample_res_t;
  29. double value;
  30. };
  31. } // namespace payload
  32. namespace message {
  33. using request_t = rotor::request_traits_t<payload::sample_req_t>::request::message_t;
  34. using response_t = rotor::request_traits_t<payload::sample_req_t>::response::message_t;
  35. } // namespace message
  36. struct server_actor : public rotor::actor_base_t {
  37. using rotor::actor_base_t::actor_base_t;
  38. void configure(rotor::plugin::plugin_base_t &plugin) noexcept override {
  39. rotor::actor_base_t::configure(plugin);
  40. plugin.with_casted<rotor::plugin::starter_plugin_t>(
  41. [](auto &p) { p.subscribe_actor(&server_actor::on_request); });
  42. plugin.with_casted<rotor::plugin::registry_plugin_t>(
  43. [&](auto &p) { p.register_name("server", get_address()); });
  44. }
  45. void on_request(message::request_t &req) noexcept {
  46. auto in = req.payload.request_payload.value;
  47. if (in >= 0) {
  48. auto value = std::sqrt(in);
  49. reply_to(req, value);
  50. } else {
  51. // IRL, it should be your custom error codes
  52. auto ec = std::make_error_code(std::errc::invalid_argument);
  53. reply_with_error(req, ec);
  54. }
  55. }
  56. };
  57. struct client_actor : public rotor::actor_base_t {
  58. using rotor::actor_base_t::actor_base_t;
  59. rotor::address_ptr_t server_addr;
  60. void set_server(const rotor::address_ptr_t addr) { server_addr = addr; }
  61. void configure(rotor::plugin::plugin_base_t &plugin) noexcept override {
  62. rotor::actor_base_t::configure(plugin);
  63. plugin.with_casted<rotor::plugin::starter_plugin_t>(
  64. [](auto &p) { p.subscribe_actor(&client_actor::on_response); });
  65. plugin.with_casted<rotor::plugin::registry_plugin_t>(
  66. [&](auto &p) { p.discover_name("server", server_addr, true).link(); });
  67. }
  68. void on_response(message::response_t &res) noexcept {
  69. if (!res.payload.ec) { // check for possible error
  70. auto &in = res.payload.req->payload.request_payload.value;
  71. auto &out = res.payload.res.value;
  72. std::cout << " in = " << in << ", out = " << out << "\n";
  73. }
  74. supervisor->do_shutdown(); // optional;
  75. }
  76. void on_start() noexcept override {
  77. rotor::actor_base_t::on_start();
  78. auto timeout = rotor::pt::milliseconds{1};
  79. request<payload::sample_req_t>(server_addr, 25.0).send(timeout);
  80. }
  81. };
  82. int main() {
  83. asio::io_context io_context;
  84. auto system_context = rotor::asio::system_context_asio_t::ptr_t{new rotor::asio::system_context_asio_t(io_context)};
  85. auto strand = std::make_shared<asio::io_context::strand>(io_context);
  86. auto timeout = boost::posix_time::milliseconds{500};
  87. auto sup = system_context->create_supervisor<rotor::asio::supervisor_asio_t>()
  88. .strand(strand)
  89. .create_registry()
  90. .timeout(timeout)
  91. .finish();
  92. auto server = sup->create_actor<server_actor>().timeout(timeout).finish();
  93. auto client = sup->create_actor<client_actor>().timeout(timeout).finish();
  94. sup->do_process();
  95. return 0;
  96. }