// // Copyright (c) 2016-2019 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) // // Official repository: https://github.com/boostorg/beast // //------------------------------------------------------------------------------ // // Example: WebSocket server, asynchronous // //------------------------------------------------------------------------------ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include std::optional parse_config(const char* filename) { try { std::ifstream in(filename, std::ios::in | std::ios::binary); if (in) { std::stringstream contents; contents << in.rdbuf(); in.close(); std::cout << contents.str() << std::endl; boost::json::value value = boost::json::parse(contents.str()); return value.as_object(); } } catch (std::exception const& e) { std::cout << e.what() << std::endl; } return {}; } std::optional parse_certs(const char* certFilename, const char* keyFilename) { std::ifstream readCert(certFilename, std::ios::in | std::ios::binary); if (!readCert) return {}; std::stringstream contents; contents << readCert.rdbuf(); readCert.close(); std::string cert = contents.str(); std::ifstream readKey(keyFilename, std::ios::in | std::ios::binary); if(!readKey) return {}; contents.str(""); contents << readKey.rdbuf(); readKey.close(); std::string key = contents.str(); ssl::context ctx{ssl::context::tlsv12}; ctx.set_options( boost::asio::ssl::context::default_workarounds | boost::asio::ssl::context::no_sslv2); ctx.use_certificate_chain( boost::asio::buffer(cert.data(), cert.size())); ctx.use_private_key( boost::asio::buffer(key.data(), key.size()), boost::asio::ssl::context::file_format::pem); return ctx; } void initLogLevel(int level) { switch (level) { case 0: boost::log::core::get()->set_filter( boost::log::trivial::severity >= boost::log::trivial::trace); break; case 1: boost::log::core::get()->set_filter( boost::log::trivial::severity >= boost::log::trivial::debug); break; case 2: boost::log::core::get()->set_filter( boost::log::trivial::severity >= boost::log::trivial::info); break; case 3: boost::log::core::get()->set_filter( boost::log::trivial::severity >= boost::log::trivial::warning); break; case 4: boost::log::core::get()->set_filter( boost::log::trivial::severity >= boost::log::trivial::error); break; case 5: boost::log::core::get()->set_filter( boost::log::trivial::severity >= boost::log::trivial::fatal); break; default: boost::log::core::get()->set_filter( boost::log::trivial::severity >= boost::log::trivial::info); } } void start(boost::asio::io_context& ioc, std::uint32_t numThreads) { std::vector v; v.reserve(numThreads - 1); for (auto i = numThreads - 1; i > 0; --i) v.emplace_back([&ioc] { ioc.run(); }); std::make_shared>( ioc, ctx, boost::asio::ip::tcp::endpoint{address, port}, etl) ->run(); } int main(int argc, char* argv[]) { // Check command line arguments. if (argc < 5 || argc > 6) { std::cerr << "Usage: websocket-server-async " " \n" << "Example:\n" << " websocket-server-async 1 config.json cert.pem key.pem 2\n"; return EXIT_FAILURE; } auto const threads = std::max(1, std::atoi(argv[1])); auto const config = parse_config(argv[2]); auto const ctx = parse_certs(argv[3], argv[4]); if (argc > 5) { initLogLevel(std::atoi(argv[5])); } else { initLogLevel(2); } if (!config) { std::cerr << "Ccouldnt parse config. Exiting..." << std::endl; return EXIT_FAILURE; } if (!ctx) { std::cerr << "Couldn't parse SSL certificates" << std::endl; return EXIT_FAILURE; } boost::asio::io_context ioc{threads}; DOSGuard dosGuard{config.value(), ioc}; std::shared_ptr backend{Backend::make_Backend(*config)}; std::shared_ptr subscriptions{ SubscriptionManager::make_SubscriptionManager()}; std::shared_ptr ledgers{ NetworkValidatedLedgers::make_ValidatedLedgers()}; std::shared_ptr balancer{ ETLLoadBalancer::make_ETLLoadBalancer( *config, ioc, backend, subscriptions, ledgers)}; std::shared_ptr etl{ReportingETL::make_ReportingETL( *config, ioc, backend, subscriptions, balancer, ledgers)}; listener::make_listener( ioc, boost::asio::ip::tcp::endpoint{address, port}, backend, subscriptions, balancer, dosGuard); // Blocks until stopped. // When stopped, shared_ptrs fall out of scope // Calls destructors on all resources, and destructs in order start(ioc, threads); return EXIT_SUCCESS; }