/* * 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_SERVER_HPP__ #define __ASIO2_RPC_SERVER_HPP__ #if defined(_MSC_VER) && (_MSC_VER >= 1200) #pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #if __has_include() #include #include #include #include #include #include #include #include namespace asio2::detail { ASIO2_CLASS_FORWARD_DECLARE_BASE; ASIO2_CLASS_FORWARD_DECLARE_UDP_BASE; ASIO2_CLASS_FORWARD_DECLARE_UDP_SERVER; ASIO2_CLASS_FORWARD_DECLARE_TCP_BASE; ASIO2_CLASS_FORWARD_DECLARE_TCP_SERVER; template class rpc_server_impl_t : public executor_t , public rpc_invoker_t { friend executor_t; ASIO2_CLASS_FRIEND_DECLARE_BASE; ASIO2_CLASS_FRIEND_DECLARE_UDP_BASE; ASIO2_CLASS_FRIEND_DECLARE_UDP_SERVER; ASIO2_CLASS_FRIEND_DECLARE_TCP_BASE; ASIO2_CLASS_FRIEND_DECLARE_TCP_SERVER; public: using super = executor_t; using self = rpc_server_impl_t; using executor_type = executor_t; using session_type = typename super::session_type; protected: using super::async_send; public: /** * @brief constructor */ template explicit rpc_server_impl_t( Args&&... args ) : super(std::forward(args)...) , rpc_invoker_t() { } /** * @brief destructor */ ~rpc_server_impl_t() { this->stop(); } /** * @brief start the server * @param host - A string identifying a location. May be a descriptive name or * a numeric address string. * @param service - A string identifying the requested service. This may be a * descriptive name or a numeric string corresponding to a port number. */ template inline bool start(String&& host, StrOrInt&& service, Args&&... args) { if constexpr (is_websocket_server::value) { return executor_t::template start( std::forward(host), std::forward(service), std::forward(args)...); } else if constexpr (session_type::net_protocol == asio2::net_protocol::udp) { return executor_t::template start( std::forward(host), std::forward(service), asio2::use_kcp, std::forward(args)...); } else { return executor_t::template start( std::forward(host), std::forward(service), asio2::use_dgram, std::forward(args)...); } } public: /** * @brief call a rpc function for each session */ template inline void call(std::chrono::duration timeout, const std::string& name, const Args&... args) { this->sessions_.for_each([&](std::shared_ptr& session_ptr) mutable { session_ptr->template call(timeout, name, args...); }); } /** * @brief call a rpc function for each session */ template inline void call(const std::string& name, const Args&... args) { this->sessions_.for_each([&](std::shared_ptr& session_ptr) mutable { session_ptr->template call(name, args...); }); } /** * @brief asynchronous call a rpc function for each session * Callback signature : void(return_t result) * if result type is void, the Callback signature is : void() * Because the result value type is not specified in the first template parameter, * so the result value type must be specified in the Callback lambda. */ template inline typename std::enable_if_t, void> async_call(const Callback& fn, const std::string& name, const Args&... args) { this->sessions_.quick_for_each([&](std::shared_ptr& session_ptr) mutable { session_ptr->async_call(fn, name, args...); }); } /** * @brief asynchronous call a rpc function for each session * Callback signature : void(return_t result) * if result type is void, the Callback signature is : void() * Because the result value type is not specified in the first template parameter, * so the result value type must be specified in the Callback lambda */ template inline typename std::enable_if_t, void> async_call(const Callback& fn, std::chrono::duration timeout, const std::string& name, const Args&... args) { this->sessions_.quick_for_each([&](std::shared_ptr& session_ptr) mutable { session_ptr->async_call(fn, timeout, name, args...); }); } /** * @brief asynchronous call a rpc function for each session * Callback signature : void(return_t result) the return_t * is the first template parameter. * if result type is void, the Callback signature is : void() */ template inline void async_call(const Callback& fn, const std::string& name, const Args&... args) { this->sessions_.quick_for_each([&](std::shared_ptr& session_ptr) mutable { session_ptr->template async_call(fn, name, args...); }); } /** * @brief asynchronous call a rpc function for each session * Callback signature : void(return_t result) the return_t * is the first template parameter. * if result type is void, the Callback signature is : void() */ template inline void async_call(const Callback& fn, std::chrono::duration timeout, const std::string& name, const Args&... args) { this->sessions_.quick_for_each([&](std::shared_ptr& session_ptr) mutable { session_ptr->template async_call(fn, timeout, name, args...); }); } /** * @brief asynchronous call a rpc function for each session * Don't care whether the call succeeds */ template inline void async_call(const std::string& name, const Args&... args) { this->sessions_.quick_for_each([&](std::shared_ptr& session_ptr) mutable { session_ptr->async_call(name, args...); }); } protected: template inline std::shared_ptr _make_session(Args&&... args) { return super::_make_session(std::forward(args)..., *this); } protected: }; } namespace asio2 { template class rpc_server_impl_t; template class rpc_server_impl_t : public detail::rpc_server_impl_t> { public: using detail::rpc_server_impl_t>:: rpc_server_impl_t; }; template class rpc_server_impl_t : public detail::rpc_server_impl_t> { public: using detail::rpc_server_impl_t>:: rpc_server_impl_t; }; template class rpc_server_impl_t : public detail::rpc_server_impl_t> { public: using detail::rpc_server_impl_t>:: rpc_server_impl_t; }; template class rpc_server_t : public rpc_server_impl_t, session_t> { public: using rpc_server_impl_t, session_t>::rpc_server_impl_t; }; template class rpc_server_use : public rpc_server_t> { public: using rpc_server_t>::rpc_server_t; }; using rpc_tcp_server = rpc_server_use; using rpc_ws_server = rpc_server_use; using rpc_kcp_server = rpc_server_use; #if !defined(ASIO2_USE_WEBSOCKET_RPC) /// Using tcp dgram mode as the underlying communication support using rpc_server = rpc_server_use; #else /// Using websocket as the underlying communication support using rpc_server = rpc_server_use; #endif } #if defined(ASIO2_INCLUDE_RATE_LIMIT) #include namespace asio2 { template class rpc_rate_server_impl_t; template class rpc_rate_server_impl_t : public detail::rpc_server_impl_t> { public: using detail::rpc_server_impl_t>:: rpc_server_impl_t; }; template class rpc_rate_server_impl_t : public detail::rpc_server_impl_t> { public: using detail::rpc_server_impl_t>:: rpc_server_impl_t; }; template class rpc_rate_server_t : public rpc_rate_server_impl_t, session_t> { public: using rpc_rate_server_impl_t, session_t>::rpc_rate_server_impl_t; }; template class rpc_rate_server_use : public rpc_rate_server_t> { public: using rpc_rate_server_t>::rpc_rate_server_t; }; #if !defined(ASIO2_USE_WEBSOCKET_RPC) /// Using tcp dgram mode as the underlying communication support using rpc_rate_server = rpc_rate_server_use; #else /// Using websocket as the underlying communication support using rpc_rate_server = rpc_rate_server_use; #endif } #endif #include #endif #endif // !__ASIO2_RPC_SERVER_HPP__