123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276 |
- /*
- * Copyright (c) 2017-2023 zhllxt
- *
- * author : zhllxt
- * email : 37792738@qq.com
- *
- * Distributed under the Boost Software License, Version 1.0. (See accompanying
- * file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
- */
- #ifndef __ASIO2_RPC_PROTOCOL_HPP__
- #define __ASIO2_RPC_PROTOCOL_HPP__
- #if defined(_MSC_VER) && (_MSC_VER >= 1200)
- #pragma once
- #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
- #include <string>
- #include <string_view>
- #include <asio2/base/detail/util.hpp>
- #include <asio2/rpc/detail/rpc_serialization.hpp>
- namespace asio2::detail
- {
- struct use_tcp {};
- struct use_websocket {};
- /*
- * request : message type + request id + function name + parameters value...
- * response : message type + request id + function name + error code + result value
- *
- * message type : q - request, p - response
- *
- * if result type is void, then result type will wrapped to std::int8_t
- */
- static constexpr char rpc_type_req = 'q';
- static constexpr char rpc_type_rep = 'p';
- class rpc_header
- {
- public:
- using id_type = std::uint64_t;
- rpc_header() noexcept {}
- rpc_header(char type, id_type id, std::string_view name)
- : type_(type), id_(id), name_(name) {}
- ~rpc_header() = default;
- rpc_header(const rpc_header& r) : type_(r.type_), id_(r.id_), name_(r.name_) {}
- rpc_header(rpc_header&& r) noexcept : type_(r.type_), id_(r.id_), name_(std::move(r.name_)) {}
- inline rpc_header& operator=(const rpc_header& r)
- {
- type_ = r.type_;
- id_ = r.id_;
- name_ = r.name_;
- return (*this);
- }
- inline rpc_header& operator=(rpc_header&& r) noexcept
- {
- type_ = r.type_;
- id_ = r.id_;
- name_ = std::move(r.name_);
- return (*this);
- }
- //template <class Archive>
- //inline void serialize(Archive & ar)
- //{
- // ar(type_, id_, name_);
- //}
- template <class Archive>
- void save(Archive & ar) const
- {
- ar(type_, id_, name_);
- }
- template <class Archive>
- void load(Archive & ar)
- {
- ar(type_, id_, name_);
- }
- inline char type() const noexcept { return this->type_; }
- inline id_type id () const noexcept { return this->id_; }
- inline const std::string& name() const noexcept { return this->name_; }
- inline char get_type() const noexcept { return this->type_; }
- inline id_type get_id () const noexcept { return this->id_; }
- inline const std::string& get_name() const noexcept { return this->name_; }
- inline bool is_request () const noexcept { return this->type_ == rpc_type_req; }
- inline bool is_response() const noexcept { return this->type_ == rpc_type_rep; }
- inline rpc_header& type(char type ) noexcept { this->type_ = type; return (*this); }
- inline rpc_header& id (id_type id ) noexcept { this->id_ = id ; return (*this); }
- inline rpc_header& name(std::string_view name) { this->name_ = name; return (*this); }
- inline rpc_header& set_type(char type ) noexcept { this->type_ = type; return (*this); }
- inline rpc_header& set_id (id_type id ) noexcept { this->id_ = id ; return (*this); }
- inline rpc_header& set_name(std::string_view name) { this->name_ = name; return (*this); }
- protected:
- char type_;
- id_type id_ = 0;
- std::string name_;
- };
- template<class ...Args>
- class rpc_request : public rpc_header
- {
- protected:
- template<class T>
- struct value_t
- {
- using type = T;
- };
- template<class... Ts>
- struct value_t<std::basic_string_view<Ts...>>
- {
- using type = typename std::basic_string_view<Ts...>::value_type;
- };
- template<class T>
- struct result_t
- {
- // if the parameters of rpc calling is raw pointer like char* , must convert it to std::string
- // if the parameters of rpc calling is std::string_view , must convert it to std::string
- // if the parameters of rpc calling is reference like std::string& , must remove it's
- // reference to std::string
- using ncvr_type = std::remove_cv_t<std::remove_reference_t<T>>;
- using char_type = std::remove_cv_t<std::remove_reference_t<
- std::remove_all_extents_t<std::remove_pointer_t<ncvr_type>>>>;
- using type = std::conditional_t<
- (std::is_pointer_v<ncvr_type> || std::is_array_v<ncvr_type>) && (
- std::is_same_v<char_type, std::string::value_type> ||
- std::is_same_v<char_type, std::wstring::value_type> ||
- std::is_same_v<char_type, std::u16string::value_type> ||
- std::is_same_v<char_type, std::u32string::value_type>)
- , std::basic_string<char_type>
- , std::conditional_t<is_template_instance_of_v<std::basic_string_view, ncvr_type>
- , std::basic_string<typename value_t<ncvr_type>::type>
- , ncvr_type>>;
- };
- public:
- rpc_request() noexcept : rpc_header() { this->type_ = rpc_type_req; }
- // can't use tp_(std::forward_as_tuple(std::forward<Args>(args)...))
- // if use tp_(std::forward_as_tuple(std::forward<Args>(args)...)),
- // when the args is nlohmann::json and under gcc 9.4.0, the json::object
- // maybe changed to json::array, like this:
- // {"name":"hello","age":10} will changed to [{"name":"hello","age":10}]
- // i don't why?
- rpc_request(std::string_view name, Args&&... args)
- : rpc_header(rpc_type_req, 0, name), tp_(std::forward<Args>(args)...) {}
- rpc_request(id_type id, std::string_view name, Args&&... args)
- : rpc_header(rpc_type_req, id, name), tp_(std::forward<Args>(args)...) {}
- ~rpc_request() = default;
- rpc_request(const rpc_request& r) : rpc_header(r), tp_(r.tp_) {}
- rpc_request(rpc_request&& r) noexcept : rpc_header(std::move(r)), tp_(std::move(r.tp_)) {}
- inline rpc_request& operator=(const rpc_request& r)
- {
- static_cast<rpc_header&>(*this) = r;
- tp_ = r.tp_;
- return (*this);
- }
- inline rpc_request& operator=(rpc_request&& r) noexcept
- {
- static_cast<rpc_header&>(*this) = std::move(r);
- tp_ = std::move(r.tp_);
- return (*this);
- }
- //template <class Archive>
- //void serialize(Archive & ar)
- //{
- // ar(cereal::base_class<rpc_header>(this));
- // detail::for_each_tuple(tp_, [&ar](auto& elem) mutable
- // {
- // ar(elem);
- // });
- //}
- template <class Archive>
- void save(Archive & ar) const
- {
- ar(cereal::base_class<rpc_header>(this));
- detail::for_each_tuple(tp_, [&ar](const auto& elem) mutable
- {
- ar << elem;
- });
- }
- template <class Archive>
- void load(Archive & ar)
- {
- ar(cereal::base_class<rpc_header>(this));
- detail::for_each_tuple(tp_, [&ar](auto& elem) mutable
- {
- ar >> elem;
- });
- }
- protected:
- std::tuple<typename result_t<Args>::type...> tp_;
- };
- template<class T>
- class rpc_response : public rpc_header
- {
- public:
- rpc_response() noexcept : rpc_header() { this->type_ = rpc_type_rep; }
- rpc_response(id_type id, std::string_view name) : rpc_header(rpc_type_rep, id, name) {}
- rpc_response(id_type id, std::string_view name, const error_code& ec, T&& ret)
- : rpc_header(rpc_type_rep, id, name), ec_(ec), ret_(std::forward<T>(ret)) {}
- ~rpc_response() = default;
- rpc_response(const rpc_response& r)
- : rpc_header(r), ec_(r.ec_), ret_(r.ret_) {}
- rpc_response(rpc_response&& r) noexcept
- : rpc_header(std::move(r)), ec_(std::move(r.ec_)), ret_(std::move(r.ret_)) {}
- inline rpc_response& operator=(const rpc_response& r)
- {
- static_cast<rpc_header&>(*this) = r;
- ec_ = r.ec_;
- ret_ = r.ret_;
- return (*this);
- }
- inline rpc_response& operator=(rpc_response&& r) noexcept
- {
- static_cast<rpc_header&>(*this) = std::move(r);
- ec_ = std::move(r.ec_);
- ret_ = std::move(r.ret_);
- return (*this);
- }
- //template <class Archive>
- //void serialize(Archive & ar)
- //{
- // ar(cereal::base_class<rpc_header>(this));
- // ar(ec_.value());
- // ar(ret_);
- //}
- template <class Archive>
- void save(Archive & ar) const
- {
- ar << cereal::base_class<rpc_header>(this);
- ar << ec_.value();
- ar << ret_;
- }
- template <class Archive>
- void load(Archive & ar)
- {
- ar >> cereal::base_class<rpc_header>(this);
- ar >> ec_.value();
- ar >> ret_;
- }
- protected:
- error_code ec_;
- T ret_;
- };
- }
- #endif // !__ASIO2_RPC_PROTOCOL_HPP__
|