(size, (elems, ....))
(a, (b, (c, BOOST_PP_NIL)))
(a)(b)(c)
(a, b, c)
(a)(b)(c)
- sequence. Here, we described a sequence consisting of three elements.(a)
- also sequence, but consisting of one element. (Attention!)(a)(b, c)(d, e, f)
- again the sequence, but consisting of three tuples. (pay attention to the first element - the trick, however, but this is really a tuple)(a)(b, c)(d, (e, f))
- again sequence, and also consisting of three tuples. But! The last tuple consists of two elements: 1) any element, 2) tuple.(a)(b, c)(d, (e, (f)(g)))
- then figure it out yourself;) (proc_name0, // (signature_arg0, signature_arg1, signature_argN) // (signature_arg0) // ) (proc_name1, // (signature_arg0, signature_arg1) // ) (proc_name2, // () // ( ) )
(proc_name0, // procID=0 (signature_arg0, signature_arg1) // sigID=0 ) (proc_name1, // procID=1 (signature_arg0, signature_arg1) // sigID=0 ) (proc_name2, // procID=2 () // sigID=0 )
proc_name0()
we need to add another version with a different signature. (proc_name0, // procID=0 (signature_arg0, signature_arg1) // sigID=0 (signature_arg0, signature_arg1, signature_arg2) // sigID=1 ) (proc_name1, // procID=1 (signature_arg0, signature_arg1) // sigID=0 ) (proc_name2, // procID=2 () // sigID=0 )
MACRO( client_invoker, // name of the client invoker implementation class ((registration, // procedure name ((std::string, std::string)) // message : registration key )) ((activation, ((std::string)) // message )) ((login, ((std::string)) // message )) ((logout, ((std::string)) // message )) ((users_online, ((std::vector<std::string>)) // without args )) , server_invoker, // name of the server invoker implementation class ((registration, ((std::string)) // username )) ((activation, ((std::string, std::string, std::string)) // registration key : username : password )) ((login, ((std::string, std::string)) // username : password )) ((logout, (()) // without args )) ((users_online, (()) // without args ((std::string)) // substring )) )
client_invoker::registration(std::string, std::string)
tells us that the implementation of this procedure will be on the server side, while the interface to this procedure will be on the side customer and vice versa. namespace yarmi { template<typename Impl, typename IO = Impl> struct client_invoker { client_invoker(Impl &impl, IO &io) :impl(impl) ,io(io) {} void yarmi_error(const std::uint8_t &arg0, const std::uint8_t &arg1, const std::string &arg2) { yas::binary_mem_oarchive oa(yas::no_header); oa & static_cast<std::uint8_t>(0) & static_cast<std::uint8_t>(0) & arg0 & arg1 & arg2; yas::binary_mem_oarchive pa; pa & oa.get_intrusive_buffer(); io.send(pa.get_shared_buffer()); } void registration(const std::string &arg0) { yas::binary_mem_oarchive oa(yas::no_header); oa & static_cast<std::uint8_t>(1) & static_cast<std::uint8_t>(0) & arg0; yas::binary_mem_oarchive pa; pa & oa.get_intrusive_buffer(); io.send(pa.get_shared_buffer()); } void activation(const std::string &arg0, const std::string &arg1, const std::string &arg2) { yas::binary_mem_oarchive oa(yas::no_header); oa & static_cast<std::uint8_t>(2) & static_cast<std::uint8_t>(0) & arg0 & arg1 & arg2; yas::binary_mem_oarchive pa; pa & oa.get_intrusive_buffer(); io.send(pa.get_shared_buffer()); } void login(const std::string &arg0, const std::string &arg1) { yas::binary_mem_oarchive oa(yas::no_header); oa & static_cast<std::uint8_t>(3) & static_cast<std::uint8_t>(0) & arg0 & arg1; yas::binary_mem_oarchive pa; pa & oa.get_intrusive_buffer(); io.send(pa.get_shared_buffer()); } void logout() { yas::binary_mem_oarchive oa(yas::no_header); oa & static_cast<std::uint8_t>(4) & static_cast<std::uint8_t>(0); yas::binary_mem_oarchive pa; pa & oa.get_intrusive_buffer(); io.send(pa.get_shared_buffer()); } void users_online() { yas::binary_mem_oarchive oa(yas::no_header); oa & static_cast<std::uint8_t>(5) & static_cast<std::uint8_t>(0); yas::binary_mem_oarchive pa; pa & oa.get_intrusive_buffer(); io.send(pa.get_shared_buffer()); } void users_online(const std::string &arg0) { yas::binary_mem_oarchive oa(yas::no_header); oa & static_cast<std::uint8_t>(5) & static_cast<std::uint8_t>(1) & arg0; yas::binary_mem_oarchive pa; pa & oa.get_intrusive_buffer(); io.send(pa.get_shared_buffer()); } void invoke(const char *ptr, std::size_t size) { std::uint8_t call_id, call_version; static const char* names[] = { "yarmi_error" ,"registration" ,"activation" ,"login" ,"logout" ,"users_online" }; static const std::uint8_t versions[] = { 0, 0, 0, 0, 0, 0 }; try { yas::binary_mem_iarchive ia(ptr, size, yas::no_header); ia & call_id & call_version; if ( call_id < 0 || call_id > 5 ) { char errstr[1024] = {0}; std::snprintf( errstr ,sizeof(errstr) ,"%s::%s(): bad call_id %d" ,"client_invoker" ,__FUNCTION__ ,static_cast<int>(call_id) ); throw std::runtime_error(errstr); } if ( call_version > versions[call_id] ) { char errstr[1024] = {0}; std::snprintf( errstr ,sizeof(errstr) ,"%s::%s(): bad call_version %d for call_id %d(%s::%s())" ,"client_invoker" ,__FUNCTION__ ,static_cast<int>(call_version) ,static_cast<int>(call_id) ,"client_invoker" ,names[call_id] ); throw std::runtime_error(errstr); } switch ( call_id ) { case 0: { std::uint8_t arg0; std::uint8_t arg1; std::string arg2; ia & arg0 & arg1 & arg2; impl.on_yarmi_error( arg0 , arg1 , arg2); }; break; case 1: { std::string arg0; std::string arg1; ia & arg0 & arg1; impl.on_registration(arg0, arg1); }; break; case 2: { std::string arg0; ia & arg0; impl.on_activation(arg0); }; break; case 3: { std::string arg0; ia & arg0; impl.on_login(arg0); }; break; case 4: { std::string arg0; ia & arg0; impl.on_logout(arg0); }; break; case 5: { std::vector<std::string> arg0; ia & arg0; impl.on_users_online(arg0); }; break; } } catch (const std::exception &ex) { char errstr[1024] = {0}; std::snprintf( errstr ,sizeof(errstr) ,"std::exception is thrown when %s::%s() is called: '%s'" ,"client_invoker" ,names[call_id] ,ex.what() ); yarmi_error(call_id, call_version, errstr); } catch (...) { char errstr[1024] = {0}; std::snprintf( errstr ,sizeof(errstr) ,"unknown exception is thrown when %s::%s() is called" ,"client_invoker" ,names[call_id] ); yarmi_error(call_id, call_version, errstr); } } private: Impl &impl; IO &io; }; // struct client_invoker template<typename Impl, typename IO = Impl> struct server_invoker { server_invoker(Impl &impl, IO &io) :impl(impl) ,io(io) {} void yarmi_error(const std::uint8_t &arg0, const std::uint8_t &arg1, const std::string &arg2) { yas::binary_mem_oarchive oa(yas::no_header); oa & static_cast<std::uint8_t>(0) & static_cast<std::uint8_t>(0) & arg0 & arg1 & arg2; yas::binary_mem_oarchive pa; pa & oa.get_intrusive_buffer(); io.send(pa.get_shared_buffer()); } void registration(const std::string &arg0, const std::string &arg1) { yas::binary_mem_oarchive oa(yas::no_header); oa & static_cast<std::uint8_t>(1) & static_cast<std::uint8_t>(0) & arg0 & arg1; yas::binary_mem_oarchive pa; pa & oa.get_intrusive_buffer(); io.send(pa.get_shared_buffer()); } void activation(const std::string &arg0) { yas::binary_mem_oarchive oa(yas::no_header); oa & static_cast<std::uint8_t>(2) & static_cast<std::uint8_t>(0) & arg0; yas::binary_mem_oarchive pa; pa & oa.get_intrusive_buffer(); io.send(pa.get_shared_buffer()); } void login(const std::string &arg0) { yas::binary_mem_oarchive oa(yas::no_header); oa & static_cast<std::uint8_t>(3) & static_cast<std::uint8_t>(0) & arg0; yas::binary_mem_oarchive pa; pa & oa.get_intrusive_buffer(); io.send(pa.get_shared_buffer()); } void logout(const std::string &arg0) { yas::binary_mem_oarchive oa(yas::no_header); oa & static_cast<std::uint8_t>(4) & static_cast<std::uint8_t>(0) & arg0; yas::binary_mem_oarchive pa; pa & oa.get_intrusive_buffer(); io.send(pa.get_shared_buffer()); } void users_online(const std::vector<std::string> &arg0) { yas::binary_mem_oarchive oa(yas::no_header); oa & static_cast<std::uint8_t>(5) & static_cast<std::uint8_t>(0) & arg0; yas::binary_mem_oarchive pa; pa & oa.get_intrusive_buffer(); io.send(pa.get_shared_buffer()); } void invoke(const char *ptr, std::size_t size) { std::uint8_t call_id, call_version; static const char* names[] = { "yarmi_error" ,"registration" ,"activation" ,"login" ,"logout" ,"users_online" }; static const std::uint8_t versions[] = { 0, 0, 0, 0, 0, 1 }; try { yas::binary_mem_iarchive ia(ptr, size, yas::no_header); ia & call_id & call_version; if ( call_id < 0 || call_id > 5 ) { char errstr[1024] = {0}; std::snprintf( errstr ,sizeof(errstr) ,"%s::%s(): bad call_id %d" ,"server_invoker" ,__FUNCTION__ ,static_cast<int>(call_id) ); throw std::runtime_error(errstr); } if ( call_version > versions[call_id] ) { char errstr[1024] = {0}; std::snprintf( errstr ,sizeof(errstr) ,"%s::%s(): bad call_version %d for call_id %d(%s::%s())" ,"server_invoker" ,__FUNCTION__ ,static_cast<int>(call_version) ,static_cast<int>(call_id) ,"server_invoker" ,names[call_id] ); throw std::runtime_error(errstr); } switch ( call_id ) { case 0: { std::uint8_t arg0; std::uint8_t arg1; std::string arg2; ia & arg0 & arg1 & arg2; impl.on_yarmi_error(arg0, arg1, arg2); }; break; case 1: { std::string arg0; ia & arg0; impl.on_registration(arg0); }; break; case 2: { std::string arg0; std::string arg1; std::string arg2; ia & arg0 & arg1 & arg2; impl.on_activation(arg0, arg1, arg2); }; break; case 3: { std::string arg0; std::string arg1; ia & arg0 & arg1; impl.on_login(arg0, arg1); }; break; case 4: { impl.on_logout(); }; break; case 5: { switch ( call_version ) { case 0: { impl.on_users_online(); }; break; case 1: { std::string arg0; ia & arg0; impl.on_users_online(arg0); }; break; } }; break; } } catch (const std::exception &ex) { char errstr[1024] = {0}; std::snprintf( errstr ,sizeof(errstr) ,"std::exception is thrown when %s::%s() is called: '%s'" ,"server_invoker" ,names[call_id] ,ex.what() ); yarmi_error(call_id, call_version, errstr); } catch (...) { char errstr[1024] = {0}; std::snprintf( errstr ,sizeof(errstr) ,"unknown exception is thrown when %s::%s() is called" ,"server_invoker" ,names[call_id] ); yarmi_error(call_id, call_version, errstr); } } private: Impl &impl; IO &io; }; // struct server_invoker } // ns yarmi
yarmi_error()
was added - used to inform the opposite party that an error occurred while trying to make a call. Look carefully, client_invoker::invoke()
, deserialization and call are wrapped in a try{}catch()
block, and in catch()
blocks a call is made to yarmi_error()
. Thus, if an exception is raised during deserialization or a procedure call, it will be successfully intercepted by the catch()
block, and the exception information will be sent to the caller. The same thing will happen in the opposite direction. Those. If the server has called the client for the procedure that caused the exception during the call, the client will send the error information to the server, also giving the ID and the version of the call that caused the exception. But, you can use yarmi_error()
yourself, nothing prohibits this. Example: yarmi_error(call_id, version_id, "message");
on_
client_invoker
and server_invoker
take two parameters. Their first bottom is the class in which the callable procedures are implemented, the second is the class in which the send(yas::shared_buffer buf)
method send(yas::shared_buffer buf)
implemented. struct client_session: yarmi::client_base<client_session>, yarmi::client_invoker<client_session> { client_session(boost::asio::io_service &ios) :yarmi::client_base<client_session>(ios, *this) ,yarmi::client_invoker<client_session>(*this, *this) // <<<<<<<<<<<<<<<<<<<<<<<<< {} };
struct client_session: yarmi::client_base<client_session>, yarmi::client_invoker<client_session> { client_session(boost::asio::io_service &ios) :yarmi::client_base<client_session>(ios, *this) ,yarmi::client_invoker<client_session>(*this, *this) {} void on_registration(const std::string &msg, const std::string ®key) {} void on_activation(const std::string &msg) {} void on_login(const std::string &msg) {} void on_logout(const std::string &msg) {} void on_users_online(const std::vector<std::string> &users) {} };
yarmi::client_invoker
. Ie, for example, being in the constructor of our client_session
, you can call the registration()
procedure as follows: { registration("niXman"); }
client_session::on_registration(std::string msg, std::string regkey)
Source: https://habr.com/ru/post/199496/
All Articles