forked from boostorg/beast
New server-framework, full featured server example:
A new server framework is introduced, allowing users to quickly get off the ground. Example servers are refactored to use the common framework.
This commit is contained in:
@@ -0,0 +1,242 @@
|
||||
//
|
||||
// Copyright (c) 2013-2017 Vinnie Falco (vinnie dot falco at gmail dot 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)
|
||||
//
|
||||
|
||||
#include "server.hpp"
|
||||
|
||||
#include "http_async_port.hpp"
|
||||
#include "http_sync_port.hpp"
|
||||
#include "ws_async_port.hpp"
|
||||
#include "ws_sync_port.hpp"
|
||||
|
||||
#include "file_service.hpp"
|
||||
#include "ws_upgrade_service.hpp"
|
||||
|
||||
#include <boost/program_options.hpp>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
/// Block until SIGINT or SIGTERM is received.
|
||||
void
|
||||
sig_wait()
|
||||
{
|
||||
// Create our own io_service for this
|
||||
boost::asio::io_service ios;
|
||||
|
||||
// Get notified on the signals we want
|
||||
boost::asio::signal_set signals(
|
||||
ios, SIGINT, SIGTERM);
|
||||
|
||||
// Now perform the asynchronous call
|
||||
signals.async_wait(
|
||||
[&](boost::system::error_code const&, int)
|
||||
{
|
||||
});
|
||||
|
||||
// Block the current thread on run(), when the
|
||||
// signal is received then this call will return.
|
||||
ios.run();
|
||||
}
|
||||
|
||||
/** Set the options on a WebSocket stream.
|
||||
|
||||
This is used by the websocket server port handlers.
|
||||
It is called every time a new websocket stream is
|
||||
created, to provide the opportunity to set settings
|
||||
for the connection.
|
||||
*/
|
||||
class set_ws_options
|
||||
{
|
||||
beast::websocket::permessage_deflate pmd_;
|
||||
|
||||
public:
|
||||
set_ws_options(beast::websocket::permessage_deflate const& pmd)
|
||||
: pmd_(pmd)
|
||||
{
|
||||
}
|
||||
|
||||
template<class NextLayer>
|
||||
void
|
||||
operator()(beast::websocket::stream<NextLayer>& ws) const
|
||||
{
|
||||
ws.auto_fragment(false);
|
||||
ws.set_option(pmd_);
|
||||
ws.read_message_max(64 * 1024 * 1024);
|
||||
}
|
||||
};
|
||||
|
||||
int
|
||||
main(
|
||||
int ac,
|
||||
char const* av[])
|
||||
{
|
||||
// Helper for reporting failures
|
||||
//
|
||||
using namespace framework;
|
||||
using namespace beast::http;
|
||||
|
||||
auto const fail =
|
||||
[&](
|
||||
std::string const& what,
|
||||
error_code const& ec)
|
||||
{
|
||||
std::cerr <<
|
||||
av[0] << ": " <<
|
||||
what << " failed, " <<
|
||||
ec.message() <<
|
||||
std::endl;
|
||||
return EXIT_FAILURE;
|
||||
};
|
||||
|
||||
namespace po = boost::program_options;
|
||||
po::options_description desc("Options");
|
||||
|
||||
desc.add_options()
|
||||
("root,r", po::value<std::string>()->default_value("."),
|
||||
"Set the root directory for serving files")
|
||||
("port,p", po::value<std::uint16_t>()->default_value(1000),
|
||||
"Set the base port number for the server")
|
||||
("ip", po::value<std::string>()->default_value("0.0.0.0"),
|
||||
"Set the IP address to bind to, \"0.0.0.0\" for all")
|
||||
("threads,n", po::value<std::size_t>()->default_value(4),
|
||||
"Set the number of threads to use")
|
||||
;
|
||||
po::variables_map vm;
|
||||
po::store(po::parse_command_line(ac, av, desc), vm);
|
||||
|
||||
// Get the IP address from the options
|
||||
std::string const ip = vm["ip"].as<std::string>();
|
||||
|
||||
// Get the port number from the options
|
||||
std::uint16_t const port = vm["port"].as<std::uint16_t>();
|
||||
|
||||
// Build an endpoint from the address and port
|
||||
address_type const addr{address_type::from_string(ip)};
|
||||
|
||||
// Get the number of threads from the command line
|
||||
std::size_t const threads = vm["threads"].as<std::size_t>();
|
||||
|
||||
// Get the root path from the command line
|
||||
boost::filesystem::path const root = vm["root"].as<std::string>();
|
||||
|
||||
// These settings will be applied to all new websocket connections
|
||||
beast::websocket::permessage_deflate pmd;
|
||||
pmd.client_enable = true;
|
||||
pmd.server_enable = true;
|
||||
pmd.compLevel = 3;
|
||||
|
||||
error_code ec;
|
||||
|
||||
// Create our server instance with the specified number of threads
|
||||
server instance{threads};
|
||||
|
||||
{
|
||||
// Install an asynchronous WebSocket echo port handler
|
||||
//
|
||||
auto wsp = instance.make_port<ws_async_port>(
|
||||
ec,
|
||||
endpoint_type{addr, port},
|
||||
instance,
|
||||
std::cout,
|
||||
set_ws_options{pmd}
|
||||
);
|
||||
|
||||
if(ec)
|
||||
return fail("ws_async_port", ec);
|
||||
|
||||
// Install an asynchronous HTTP port handler
|
||||
//
|
||||
auto sp = instance.make_port<http_async_port<
|
||||
ws_upgrade_service<ws_async_port>,
|
||||
file_service
|
||||
>>(
|
||||
ec,
|
||||
endpoint_type{addr,
|
||||
static_cast<unsigned short>(port + 1)},
|
||||
instance,
|
||||
std::cout);
|
||||
|
||||
if(ec)
|
||||
return fail("http_async_port", ec);
|
||||
|
||||
// Set up the ws_upgrade_service. We will route upgrade
|
||||
// requests to the websocket port handler created earlier.
|
||||
//
|
||||
sp->template init<0>(
|
||||
ec,
|
||||
wsp // The websocket port handler
|
||||
);
|
||||
|
||||
if(ec)
|
||||
return fail("http_async_port/ws_upgrade_service", ec);
|
||||
|
||||
// Set up the file_service to point to the root path.
|
||||
//
|
||||
sp->template init<1>(
|
||||
ec,
|
||||
root, // The root path
|
||||
"http_async_port" // The value for the Server field
|
||||
);
|
||||
|
||||
if(ec)
|
||||
return fail("http_async_port/file_service", ec);
|
||||
}
|
||||
|
||||
{
|
||||
// Install a synchronous WebSocket echo port handler
|
||||
//
|
||||
auto wsp = instance.make_port<ws_sync_port>(
|
||||
ec,
|
||||
endpoint_type{addr,
|
||||
static_cast<unsigned short>(port + 2)},
|
||||
instance,
|
||||
std::cout,
|
||||
set_ws_options{pmd});
|
||||
|
||||
if(ec)
|
||||
return fail("ws_sync_port", ec);
|
||||
|
||||
|
||||
// Install a synchronous HTTP port handler
|
||||
//
|
||||
auto sp = instance.make_port<http_sync_port<
|
||||
ws_upgrade_service<ws_sync_port>,
|
||||
file_service
|
||||
>>(
|
||||
ec,
|
||||
endpoint_type{addr,
|
||||
static_cast<unsigned short>(port + 3)},
|
||||
instance,
|
||||
std::cout);
|
||||
|
||||
if(ec)
|
||||
return fail("http_sync_port", ec);
|
||||
|
||||
// Set up the ws_upgrade_service. We will route upgrade
|
||||
// requests to the websocket port handler created earlier.
|
||||
//
|
||||
sp->template init<0>(
|
||||
ec,
|
||||
wsp
|
||||
);
|
||||
|
||||
if(ec)
|
||||
return fail("http_sync_port/ws_upgrade_service", ec);
|
||||
|
||||
// Set up the file_service to point to the root path.
|
||||
//
|
||||
sp->template init<1>(
|
||||
ec,
|
||||
root,
|
||||
"http_sync_port"
|
||||
);
|
||||
|
||||
if(ec)
|
||||
return fail("http_sync_port/file_service", ec);
|
||||
}
|
||||
|
||||
sig_wait();
|
||||
}
|
||||
Reference in New Issue
Block a user