Documentation work

This commit is contained in:
Vinnie Falco
2017-06-17 10:20:45 -07:00
parent a26017d695
commit d12d686167
8 changed files with 198 additions and 58 deletions

View File

@@ -39,8 +39,6 @@ A port handler takes the stream object resulting form an incoming connection
request and constructs a handler-specific connection object which provides request and constructs a handler-specific connection object which provides
the desired behavior. the desired behavior.
## Service
The HTTP ports which come with the example have a system built in which allows The HTTP ports which come with the example have a system built in which allows
installation of framework and user-defined "HTTP services". These services installation of framework and user-defined "HTTP services". These services
inform connections using the port on how to handle specific requests. This is inform connections using the port on how to handle specific requests. This is
@@ -66,3 +64,74 @@ the HTTP ports:
<img width="880" height = "344" alt = "ServerFramework" <img width="880" height = "344" alt = "ServerFramework"
src="https://raw.githubusercontent.com/vinniefalco/Beast/server/doc/images/server.png"> src="https://raw.githubusercontent.com/vinniefalco/Beast/server/doc/images/server.png">
## PortHandler Requirements
```C++
/** An synchronous WebSocket @b PortHandler which implements echo.
This is a port handler which accepts WebSocket upgrade HTTP
requests and implements the echo protocol. All received
WebSocket messages will be echoed back to the remote host.
*/
struct PortHandler
{
/** Accept a TCP/IP socket.
This function is called when the server has accepted an
incoming connection.
@param sock The connected socket.
@param ep The endpoint of the remote host.
*/
void
on_accept(
socket_type&& sock,
endpoint_type ep);
};
```
## Service Requirements
```C++
struct Service
{
/** Initialize the service
@param ec Set to the error, if any occurred
*/
void
init(error_code& ec);
/** Maybe respond to an HTTP request
Upon handling the response, the service may optionally
take ownership of either the stream, the request, or both.
@param stream The stream representing the connection
@param ep The remote endpoint of the stream
@param req The HTTP request
@param send A function object which operates on a single
argument of type beast::http::message. The function object
has this equivalent signature:
@code
template<class Body, class Fields>
void send(beast::http::response<Body, Fields>&& res);
@endcode
@return `true` if the service handled the response.
*/
template<
class Stream,
class Body, class Fields,
class Send>
bool
respond(
Stream&& stream,
endpoint_type const& ep,
beast::http::request<Body, Fields>&& req,
Send const& send) const
};
```

View File

@@ -27,7 +27,7 @@
namespace framework { namespace framework {
// Base class for a type-erased, queued asynchronous HTTP write // Base class for a type-erased, queued asynchronous HTTP write operation
// //
struct queued_http_write struct queued_http_write
{ {
@@ -111,7 +111,7 @@ make_queued_http_write(
asynchronous calls. asynchronous calls.
It uses the Curiously Recurring Template pattern (CRTP) where It uses the Curiously Recurring Template pattern (CRTP) where
we refer to the derivd class in order to access the stream object we refer to the derived class in order to access the stream object
to use for reading and writing. This lets the same class be used to use for reading and writing. This lets the same class be used
for plain and SSL stream objects. for plain and SSL stream objects.
@@ -492,7 +492,12 @@ class http_async_port
service_list<Services...> services_; service_list<Services...> services_;
public: public:
// Constructor /** Constructor
@param instance The server instance which owns this port
@param log The stream to use for logging
*/
http_async_port( http_async_port(
server& instance, server& instance,
std::ostream& log) std::ostream& log)

View File

@@ -35,7 +35,7 @@ namespace framework {
synchronous calls. synchronous calls.
It uses the Curiously Recurring Template pattern (CRTP) where It uses the Curiously Recurring Template pattern (CRTP) where
we refer to the derivd class in order to access the stream object we refer to the derived class in order to access the stream object
to use for reading and writing. This lets the same class be used to use for reading and writing. This lets the same class be used
for plain and SSL stream objects. for plain and SSL stream objects.
@@ -45,6 +45,7 @@ template<class Derived, class... Services>
class sync_http_con class sync_http_con
: public http_base : public http_base
{ {
// This function lets us access members of the derived class
Derived& Derived&
impl() impl()
{ {
@@ -271,6 +272,7 @@ public:
} }
// Returns the stream. // Returns the stream.
//
// The base class calls this to obtain the object to // The base class calls this to obtain the object to
// use for reading and writing HTTP messages. // use for reading and writing HTTP messages.
// //
@@ -297,7 +299,12 @@ class http_sync_port
service_list<Services...> services_; service_list<Services...> services_;
public: public:
// Constructor /** Constructor
@param instance The server instance which owns this port
@param log The stream to use for logging
*/
http_sync_port( http_sync_port(
server& instance, server& instance,
std::ostream& log) std::ostream& log)

View File

@@ -154,6 +154,10 @@ public:
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
/* This implementation class wraps the PortHandler and
manages the listening socket. Upon an incoming connection
it transfers ownership of the socket to the PortHandler.
*/
template<class PortHandler> template<class PortHandler>
class port class port
: public std::enable_shared_from_this< : public std::enable_shared_from_this<
@@ -228,7 +232,11 @@ private:
if(ec == boost::asio::error::operation_aborted) if(ec == boost::asio::error::operation_aborted)
return; return;
if(! ec) if(! ec)
{
// Transfer ownership of the socket to the PortHandler
//
handler_.on_accept(std::move(sock_), ep_); handler_.on_accept(std::move(sock_), ep_);
}
acceptor_.async_accept(sock_, ep_, acceptor_.async_accept(sock_, ep_,
std::bind(&port::on_accept, this->shared_from_this(), std::bind(&port::on_accept, this->shared_from_this(),
std::placeholders::_1)); std::placeholders::_1));

View File

@@ -24,38 +24,6 @@ namespace framework {
`true` if the request is processed or `false` if it does not `true` if the request is processed or `false` if it does not
process the request. process the request.
@b Service requirements
@code
struct Service
{
// Initialize the service
//
void
init(error_code& ec);
// Maybe respond to an HTTP request
//
// Returns `true` if it handled the response.
//
// Upon handling the response, the service may optionally
// take ownership of either the stream, the request, or both.
//
template<
class Stream,
class Body, class Fields,
class Send>
bool
respond(
Stream&&,
endpoint_type const& ep,
beast::http::request<Body, Fields>&& req,
Send const& send) const
};
@endcode
@see file_service, ws_upgrade_service @see file_service, ws_upgrade_service
*/ */
template<class... Services> template<class... Services>

View File

@@ -35,9 +35,19 @@ template<
bool isRequest, class Body, class Fields> bool isRequest, class Body, class Fields>
class write_msg_op class write_msg_op
{ {
// This composed operation has a state which is not trivial
// to copy (msg) so we need to store the state in an allocated
// object.
//
struct data struct data
{ {
// The stream we are writing to
AsyncWriteStream& stream; AsyncWriteStream& stream;
// The message we are sending. Note that this composed
// operation takes ownership of the message and destroys
// it when it is done.
//
beast::http::message<isRequest, Body, Fields> msg; beast::http::message<isRequest, Body, Fields> msg;
data( data(
@@ -50,19 +60,40 @@ class write_msg_op
} }
}; };
// `handler_ptr` is a utility which helps to manage a composed
// operation's state. It is similar to a shared pointer, but
// it uses handler allocation hooks to allocate and free memory,
// and it also helps to meet Asio's deallocate-before-invocation
// guarantee.
//
beast::handler_ptr<data, Handler> d_; beast::handler_ptr<data, Handler> d_;
public: public:
// Asio can move and copy the handler, we support both
write_msg_op(write_msg_op&&) = default; write_msg_op(write_msg_op&&) = default;
write_msg_op(write_msg_op const&) = default; write_msg_op(write_msg_op const&) = default;
template<class DeducedHandler, class... Args> // Constructor
write_msg_op(DeducedHandler&& h, AsyncWriteStream& s, Args&&... args) //
// We take the handler as a template type to
// support both const and rvalue references.
//
template<
class DeducedHandler,
class... Args>
write_msg_op(
DeducedHandler&& h,
AsyncWriteStream& s,
Args&&... args)
: d_(std::forward<DeducedHandler>(h), : d_(std::forward<DeducedHandler>(h),
s, std::forward<Args>(args)...) s, std::forward<Args>(args)...)
{ {
} }
// Entry point
//
// The initiation function calls this to start the operation
//
void void
operator()() operator()()
{ {
@@ -71,12 +102,22 @@ public:
d.stream, d.msg, std::move(*this)); d.stream, d.msg, std::move(*this));
} }
// Completion handler
//
// This gets called when beast::http::async_write completes
//
void void
operator()(error_code ec) operator()(error_code ec)
{ {
d_.invoke(ec); d_.invoke(ec);
} }
//
// These hooks are necessary for Asio
//
// The meaning is explained in the Beast documentation
//
friend friend
void* asio_handler_allocate( void* asio_handler_allocate(
std::size_t size, write_msg_op* op) std::size_t size, write_msg_op* op)

View File

@@ -21,13 +21,11 @@ namespace framework {
// This object holds the state of the connection // This object holds the state of the connection
// including, most importantly, the socket or stream. // including, most importantly, the socket or stream.
// //
// `Stream` is the type of socket or stream used as the
// transport. Examples include boost::asio::ip::tcp::socket
// or `ssl_stream`.
// //
template<class Derived> template<class Derived>
class async_ws_con class async_ws_con
{ {
// This function lets us access members of the derived class
Derived& Derived&
impl() impl()
{ {
@@ -201,12 +199,28 @@ private:
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// This class represents an asynchronous WebSocket connection
// which uses a plain TCP/IP socket (no encryption) as the stream.
//
class async_ws_con_plain class async_ws_con_plain
// Note that we give this object the `enable_shared_from_this`, and have
// the base class call `impl().shared_from_this()` when needed.
//
: public std::enable_shared_from_this<async_ws_con_plain> : public std::enable_shared_from_this<async_ws_con_plain>
// We want the socket to be created before the base class so we use
// the "base from member" idiom which Boost provides as a class.
//
, public base_from_member<beast::websocket::stream<socket_type>> , public base_from_member<beast::websocket::stream<socket_type>>
// Declare this base last now that everything else got set up first.
//
, public async_ws_con<async_ws_con_plain> , public async_ws_con<async_ws_con_plain>
{ {
public: public:
// Construct the plain connection.
//
template<class... Args> template<class... Args>
explicit explicit
async_ws_con_plain( async_ws_con_plain(
@@ -217,6 +231,10 @@ public:
{ {
} }
// Returns the stream.
//
// The base class calls this to obtain the websocket stream object.
//
beast::websocket::stream<socket_type>& beast::websocket::stream<socket_type>&
ws() ws()
{ {
@@ -226,7 +244,7 @@ public:
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
/** An synchronous WebSocket @b PortHandler which implements echo. /** An asynchronous WebSocket @b PortHandler which implements echo.
This is a port handler which accepts WebSocket upgrade HTTP This is a port handler which accepts WebSocket upgrade HTTP
requests and implements the echo protocol. All received requests and implements the echo protocol. All received
@@ -272,10 +290,10 @@ public:
{ {
} }
/** Accept a TCP/IP async_ws_con. /** Accept a TCP/IP connection.
This function is called when the server has accepted an This function is called when the server has accepted an
incoming async_ws_con. incoming connection.
@param sock The connected socket. @param sock The connected socket.
@@ -298,10 +316,10 @@ public:
/** Accept a WebSocket upgrade request. /** Accept a WebSocket upgrade request.
This is used to accept a async_ws_con that has already This is used to accept a connection that has already
delivered the handshake. delivered the handshake.
@param stream The stream corresponding to the async_ws_con. @param stream The stream corresponding to the connection.
@param ep The remote endpoint. @param ep The remote endpoint.
@@ -310,12 +328,12 @@ public:
template<class Body, class Fields> template<class Body, class Fields>
void void
accept( accept(
socket_type&& stream, socket_type&& sock,
endpoint_type ep, endpoint_type ep,
beast::http::request<Body, Fields>&& req) beast::http::request<Body, Fields>&& req)
{ {
std::make_shared<async_ws_con_plain>( std::make_shared<async_ws_con_plain>(
std::move(stream), std::move(sock),
"ws_async_port", "ws_async_port",
log_, log_,
instance_.next_id(), instance_.next_id(),

View File

@@ -19,16 +19,20 @@
namespace framework { namespace framework {
// The connection object holds the state of the connection /** A synchronous WebSocket connection.
// including, most importantly, the socket or stream.
// This base class implements a WebSocket connection object
// `Stream` is the type of socket or stream used as the using synchronous calls.
// transport. Examples include boost::asio::ip::tcp::socket
// or `ssl_stream`. It uses the Curiously Recurring Template pattern (CRTP) where
// we refer to the derived class in order to access the stream object
to use for reading and writing. This lets the same class be used
for plain and SSL stream objects.
*/
template<class Derived> template<class Derived>
class sync_ws_con class sync_ws_con
{ {
// This function lets us access members of the derived class
Derived& Derived&
impl() impl()
{ {
@@ -237,12 +241,28 @@ private:
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// This class represents a synchronous WebSocket connection
// which uses a plain TCP/IP socket (no encryption) as the stream.
//
class sync_ws_con_plain class sync_ws_con_plain
// Note that we give this object the `enable_shared_from_this`, and have
// the base class call `impl().shared_from_this()` when needed.
//
: public std::enable_shared_from_this<sync_ws_con_plain> : public std::enable_shared_from_this<sync_ws_con_plain>
// We want the socket to be created before the base class so we use
// the "base from member" idiom which Boost provides as a class.
//
, public base_from_member<beast::websocket::stream<socket_type>> , public base_from_member<beast::websocket::stream<socket_type>>
// Declare this base last now that everything else got set up first.
//
, public sync_ws_con<sync_ws_con_plain> , public sync_ws_con<sync_ws_con_plain>
{ {
public: public:
// Construct the plain connection.
//
template<class... Args> template<class... Args>
explicit explicit
sync_ws_con_plain( sync_ws_con_plain(
@@ -253,6 +273,10 @@ public:
{ {
} }
// Returns the stream.
//
// The base class calls this to obtain the websocket stream object.
//
beast::websocket::stream<socket_type>& beast::websocket::stream<socket_type>&
ws() ws()
{ {