-
Notifications
You must be signed in to change notification settings - Fork 1.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Trivial: Rename ServerHandlerImp
to ServerHandler
#4516
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -20,21 +20,200 @@ | |
#ifndef RIPPLE_RPC_SERVERHANDLER_H_INCLUDED | ||
#define RIPPLE_RPC_SERVERHANDLER_H_INCLUDED | ||
|
||
#include <ripple/basics/BasicConfig.h> | ||
#include <ripple/beast/utility/Journal.h> | ||
#include <ripple/core/Config.h> | ||
#include <ripple/app/main/CollectorManager.h> | ||
#include <ripple/core/JobQueue.h> | ||
#include <ripple/resource/ResourceManager.h> | ||
#include <ripple/rpc/impl/ServerHandlerImp.h> | ||
#include <ripple/server/Port.h> | ||
#include <boost/asio/io_service.hpp> | ||
#include <boost/asio/ip/address.hpp> | ||
#include <memory> | ||
#include <ripple/json/Output.h> | ||
#include <ripple/rpc/RPCHandler.h> | ||
#include <ripple/rpc/impl/WSInfoSub.h> | ||
#include <ripple/server/Server.h> | ||
#include <ripple/server/Session.h> | ||
#include <ripple/server/WSSession.h> | ||
#include <boost/beast/core/tcp_stream.hpp> | ||
#include <boost/beast/ssl/ssl_stream.hpp> | ||
#include <boost/utility/string_view.hpp> | ||
#include <condition_variable> | ||
#include <map> | ||
#include <mutex> | ||
#include <vector> | ||
|
||
namespace ripple { | ||
|
||
using ServerHandler = ServerHandlerImp; | ||
inline bool | ||
operator<(Port const& lhs, Port const& rhs) | ||
{ | ||
return lhs.name < rhs.name; | ||
} | ||
|
||
class ServerHandler | ||
{ | ||
public: | ||
struct Setup | ||
{ | ||
explicit Setup() = default; | ||
|
||
std::vector<Port> ports; | ||
|
||
// Memberspace | ||
struct client_t | ||
{ | ||
explicit client_t() = default; | ||
|
||
bool secure = false; | ||
std::string ip; | ||
std::uint16_t port = 0; | ||
std::string user; | ||
std::string password; | ||
std::string admin_user; | ||
std::string admin_password; | ||
}; | ||
|
||
// Configuration when acting in client role | ||
client_t client; | ||
|
||
// Configuration for the Overlay | ||
struct overlay_t | ||
{ | ||
explicit overlay_t() = default; | ||
|
||
boost::asio::ip::address ip; | ||
std::uint16_t port = 0; | ||
}; | ||
|
||
overlay_t overlay; | ||
|
||
void | ||
makeContexts(); | ||
}; | ||
|
||
private: | ||
using socket_type = boost::beast::tcp_stream; | ||
using stream_type = boost::beast::ssl_stream<socket_type>; | ||
|
||
Application& app_; | ||
Resource::Manager& m_resourceManager; | ||
beast::Journal m_journal; | ||
NetworkOPs& m_networkOPs; | ||
std::unique_ptr<Server> m_server; | ||
Setup setup_; | ||
JobQueue& m_jobQueue; | ||
beast::insight::Counter rpc_requests_; | ||
beast::insight::Event rpc_size_; | ||
beast::insight::Event rpc_time_; | ||
std::mutex mutex_; | ||
std::condition_variable condition_; | ||
bool stopped_{false}; | ||
std::map<std::reference_wrapper<Port const>, int> count_; | ||
|
||
// A private type used to restrict access to the ServerHandler constructor. | ||
struct ServerHandlerCreator | ||
{ | ||
explicit ServerHandlerCreator() = default; | ||
}; | ||
|
||
// Friend declaration that allows make_ServerHandler to access the | ||
// private type that restricts access to the ServerHandler ctor. | ||
friend std::unique_ptr<ServerHandler> | ||
make_ServerHandler( | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can you please point me to resources about this
I'm new to this design pattern, I'd like to learn more about it. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
It could be a
Factory functions can have a number of different purposes. In this case it's because we want to prevent anyone from constructing a Factory functions can be used for other purposes as well. For example, the Meyer's Singleton is (in effect) a factory function: https://en.wikipedia.org/wiki/Singleton_pattern The (ancient) Gang of Four Design Patterns book has a chapter on Factory Method. Factory functions really just solve the problem that sometimes a simple constructor can't do quite enough. The factory function can do the extra work that is required. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. hmm okay. I'll check out these resources 👍 |
||
Application& app, | ||
boost::asio::io_service&, | ||
JobQueue&, | ||
NetworkOPs&, | ||
Resource::Manager&, | ||
CollectorManager& cm); | ||
|
||
public: | ||
// Must be public so make_unique can call it. | ||
ServerHandler( | ||
ServerHandlerCreator const&, | ||
Application& app, | ||
boost::asio::io_service& io_service, | ||
JobQueue& jobQueue, | ||
NetworkOPs& networkOPs, | ||
Resource::Manager& resourceManager, | ||
CollectorManager& cm); | ||
|
||
~ServerHandler(); | ||
|
||
using Output = Json::Output; | ||
|
||
void | ||
setup(Setup const& setup, beast::Journal journal); | ||
|
||
Setup const& | ||
setup() const | ||
{ | ||
return setup_; | ||
} | ||
|
||
void | ||
stop(); | ||
|
||
// | ||
// Handler | ||
// | ||
|
||
bool | ||
onAccept(Session& session, boost::asio::ip::tcp::endpoint endpoint); | ||
|
||
Handoff | ||
onHandoff( | ||
Session& session, | ||
std::unique_ptr<stream_type>&& bundle, | ||
http_request_type&& request, | ||
boost::asio::ip::tcp::endpoint const& remote_address); | ||
|
||
Handoff | ||
onHandoff( | ||
Session& session, | ||
http_request_type&& request, | ||
boost::asio::ip::tcp::endpoint const& remote_address) | ||
{ | ||
return onHandoff( | ||
session, | ||
{}, | ||
std::forward<http_request_type>(request), | ||
remote_address); | ||
} | ||
|
||
void | ||
onRequest(Session& session); | ||
|
||
void | ||
onWSMessage( | ||
std::shared_ptr<WSSession> session, | ||
std::vector<boost::asio::const_buffer> const& buffers); | ||
|
||
void | ||
onClose(Session& session, boost::system::error_code const&); | ||
|
||
void | ||
onStopped(Server&); | ||
|
||
private: | ||
Json::Value | ||
processSession( | ||
std::shared_ptr<WSSession> const& session, | ||
std::shared_ptr<JobQueue::Coro> const& coro, | ||
Json::Value const& jv); | ||
|
||
void | ||
processSession( | ||
std::shared_ptr<Session> const&, | ||
std::shared_ptr<JobQueue::Coro> coro); | ||
|
||
void | ||
processRequest( | ||
Port const& port, | ||
std::string const& request, | ||
beast::IP::Endpoint const& remoteIPAddress, | ||
Output&&, | ||
std::shared_ptr<JobQueue::Coro> coro, | ||
boost::string_view forwardedFor, | ||
boost::string_view user); | ||
|
||
Handoff | ||
statusResponse(http_request_type const& request) const; | ||
}; | ||
|
||
ServerHandler::Setup | ||
setup_ServerHandler(Config const& c, std::ostream&& log); | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -17,6 +17,8 @@ | |
*/ | ||
//============================================================================== | ||
|
||
#include <ripple/rpc/ServerHandler.h> | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is it okay to leave an extra line in the include headers? I hoped the clang-format command took care of extra whitespace lines. My apologies, I don't mean to be anal about coding style here, just wanted to bring it to your attention. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This line of whitespace is allowed by clang-format and actually serves a purpose. We ask clang-format to alphabetize our But there are situations where we don't want things alphabetized. Here is one of them. In the book Large Scale C++ Software Design, John Lakos recommends that in an implementation file the first file that should be included is the header file for that implementation. Here's the principle he gives for that rule (pg 111 of the edition I own):
By placing that header first the compiler can show us that the header itself includes all of the headers it needs to be complete. Suppose that a header relied in If there's at least one place where the header is included first, then the compiler can assure us that the header contains everything it needs to stand alone. Mr. Lakos suggests that one place can be the implementation file. We follow his advice. So, back to the line of whitespace. clang-format only alphabetizes contiguous We may also use a line of white space between ripple There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this is really helpful, thanks for letting me know about the convention 👍 I understood the dependency ordering of the #include's in the third paragraph from the end 👍 |
||
#include <ripple/app/main/Application.h> | ||
#include <ripple/app/misc/NetworkOPs.h> | ||
#include <ripple/basics/Log.h> | ||
|
@@ -35,9 +37,7 @@ | |
#include <ripple/resource/ResourceManager.h> | ||
#include <ripple/rpc/RPCHandler.h> | ||
#include <ripple/rpc/Role.h> | ||
#include <ripple/rpc/ServerHandler.h> | ||
#include <ripple/rpc/impl/RPCHelpers.h> | ||
#include <ripple/rpc/impl/ServerHandlerImp.h> | ||
#include <ripple/rpc/impl/Tuning.h> | ||
#include <ripple/rpc/json_body.h> | ||
#include <ripple/server/Server.h> | ||
|
@@ -101,7 +101,8 @@ authorized(Port const& port, std::map<std::string, std::string> const& h) | |
return strUser == port.user && strPassword == port.password; | ||
} | ||
|
||
ServerHandlerImp::ServerHandlerImp( | ||
ServerHandler::ServerHandler( | ||
ServerHandlerCreator const&, | ||
Application& app, | ||
boost::asio::io_service& io_service, | ||
JobQueue& jobQueue, | ||
|
@@ -121,13 +122,13 @@ ServerHandlerImp::ServerHandlerImp( | |
rpc_time_ = group->make_event("time"); | ||
} | ||
|
||
ServerHandlerImp::~ServerHandlerImp() | ||
ServerHandler::~ServerHandler() | ||
{ | ||
m_server = nullptr; | ||
} | ||
|
||
void | ||
ServerHandlerImp::setup(Setup const& setup, beast::Journal journal) | ||
ServerHandler::setup(Setup const& setup, beast::Journal journal) | ||
{ | ||
setup_ = setup; | ||
m_server->ports(setup.ports); | ||
|
@@ -136,7 +137,7 @@ ServerHandlerImp::setup(Setup const& setup, beast::Journal journal) | |
//------------------------------------------------------------------------------ | ||
|
||
void | ||
ServerHandlerImp::stop() | ||
ServerHandler::stop() | ||
{ | ||
m_server->close(); | ||
{ | ||
|
@@ -148,7 +149,7 @@ ServerHandlerImp::stop() | |
//------------------------------------------------------------------------------ | ||
|
||
bool | ||
ServerHandlerImp::onAccept( | ||
ServerHandler::onAccept( | ||
Session& session, | ||
boost::asio::ip::tcp::endpoint endpoint) | ||
{ | ||
|
@@ -170,7 +171,7 @@ ServerHandlerImp::onAccept( | |
} | ||
|
||
Handoff | ||
ServerHandlerImp::onHandoff( | ||
ServerHandler::onHandoff( | ||
Session& session, | ||
std::unique_ptr<stream_type>&& bundle, | ||
http_request_type&& request, | ||
|
@@ -272,7 +273,7 @@ buffers_to_string(ConstBufferSequence const& bs) | |
} | ||
|
||
void | ||
ServerHandlerImp::onRequest(Session& session) | ||
ServerHandler::onRequest(Session& session) | ||
{ | ||
// Make sure RPC is enabled on the port | ||
if (session.port().protocol.count("http") == 0 && | ||
|
@@ -312,7 +313,7 @@ ServerHandlerImp::onRequest(Session& session) | |
} | ||
|
||
void | ||
ServerHandlerImp::onWSMessage( | ||
ServerHandler::onWSMessage( | ||
std::shared_ptr<WSSession> session, | ||
std::vector<boost::asio::const_buffer> const& buffers) | ||
{ | ||
|
@@ -362,14 +363,14 @@ ServerHandlerImp::onWSMessage( | |
} | ||
|
||
void | ||
ServerHandlerImp::onClose(Session& session, boost::system::error_code const&) | ||
ServerHandler::onClose(Session& session, boost::system::error_code const&) | ||
{ | ||
std::lock_guard lock(mutex_); | ||
--count_[session.port()]; | ||
} | ||
|
||
void | ||
ServerHandlerImp::onStopped(Server&) | ||
ServerHandler::onStopped(Server&) | ||
{ | ||
std::lock_guard lock(mutex_); | ||
stopped_ = true; | ||
|
@@ -398,7 +399,7 @@ logDuration( | |
} | ||
|
||
Json::Value | ||
ServerHandlerImp::processSession( | ||
ServerHandler::processSession( | ||
std::shared_ptr<WSSession> const& session, | ||
std::shared_ptr<JobQueue::Coro> const& coro, | ||
Json::Value const& jv) | ||
|
@@ -545,7 +546,7 @@ ServerHandlerImp::processSession( | |
|
||
// Run as a coroutine. | ||
void | ||
ServerHandlerImp::processSession( | ||
ServerHandler::processSession( | ||
std::shared_ptr<Session> const& session, | ||
std::shared_ptr<JobQueue::Coro> coro) | ||
{ | ||
|
@@ -586,7 +587,7 @@ Json::Int constexpr forbidden = -32605; | |
Json::Int constexpr wrong_version = -32606; | ||
|
||
void | ||
ServerHandlerImp::processRequest( | ||
ServerHandler::processRequest( | ||
Port const& port, | ||
std::string const& request, | ||
beast::IP::Endpoint const& remoteIPAddress, | ||
|
@@ -1022,7 +1023,7 @@ ServerHandlerImp::processRequest( | |
is reported, meaning the server can accept more connections. | ||
*/ | ||
Handoff | ||
ServerHandlerImp::statusResponse(http_request_type const& request) const | ||
ServerHandler::statusResponse(http_request_type const& request) const | ||
{ | ||
using namespace boost::beast::http; | ||
Handoff handoff; | ||
|
@@ -1252,8 +1253,14 @@ make_ServerHandler( | |
Resource::Manager& resourceManager, | ||
CollectorManager& cm) | ||
{ | ||
return std::make_unique<ServerHandlerImp>( | ||
app, io_service, jobQueue, networkOPs, resourceManager, cm); | ||
return std::make_unique<ServerHandler>( | ||
ServerHandler::ServerHandlerCreator(), | ||
app, | ||
io_service, | ||
jobQueue, | ||
networkOPs, | ||
resourceManager, | ||
cm); | ||
} | ||
|
||
} // namespace ripple |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm curious about using other types as a private tag in constructors. Can we use an
int
or achar
or some static variable (in the private access specifier of class) as a tag?I know that this struct is being passed with
const&
and may not incur high overhead.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
First it's worth noting that we're pushing C++ to do something it's not naturally inclined to do. We're trying to limit who is allowed to construct this type.
Let's look at how
ServerHandlerCreator
is being used. Here's the implementation ofmake_ServerHandler
:Note that
make_ServerHandler()
does not return aServerHandler
or even a reference to aServerHandler
. It returns astd::unique_ptr<ServerHandler>
. And it does so by callingstd::make_unique()
. This is awkward because somewhere in the depths ofstd::make_unique
the constructor ofServerHandler
will be invoked. We have no idea where in the standard library that invocation will occur. So we can't declare the part of the standard library as a friend. And even if we could, different standard library implementations will do it differently.The work around is to pass a unique type (e.g.
ServerHandlerCreator
) to the constructor ofServerHandler
. We can make sure that onlymake_ServerHandler()
has access to that type by making the typeprivate
and then declaringmake_ServerHandler()
afriend
. Oncemake_ServerHandler()
has constructed that unique type, the type can be passed around to anyone.In effect we've made a way for only
make_serverHandler()
to give permission tostd::make_unique()
to construct aServerHandler
.We have to use a type for this. Parameter lists are sensitive to types. If we used an
int
or achar
to grant this permission, well, anyone can pass anint
or achar
. If we make the permission thing a type, then the compiler can assure us that the correct type is being passed as a parameter.Make sense?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
okay, that makes a lot of sense. Yeah, we can't impersonate types, understood.