-
Notifications
You must be signed in to change notification settings - Fork 6
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #5 from beman-project/cppcon-2024
adding the code created during the cppcon-2024 presentation
- Loading branch information
Showing
3 changed files
with
109 additions
and
0 deletions.
There are no files selected for viewing
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -18,6 +18,7 @@ set(EXAMPLES | |
server | ||
client | ||
task | ||
cppcon-2024 | ||
) | ||
|
||
set(DATA | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,108 @@ | ||
// examples/http-server.cpp -*-C++-*- | ||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
|
||
#include <beman/net29/net.hpp> | ||
#include <beman/execution26/execution.hpp> | ||
#include "demo_algorithm.hpp" | ||
#include "demo_error.hpp" | ||
#include "demo_scope.hpp" | ||
#include "demo_task.hpp" | ||
#include <iostream> | ||
#include <string> | ||
#include <fstream> | ||
#include <sstream> | ||
#include <string_view> | ||
#include <unordered_map> | ||
|
||
namespace ex = beman::execution26; | ||
namespace net = beman::net29; | ||
using namespace std::chrono_literals; | ||
|
||
// ---------------------------------------------------------------------------- | ||
|
||
std::unordered_map<std::string, std::string> files{ | ||
{"/", "examples/data/index.html"}, | ||
{"/favicon.ico", "examples/data/favicon.ico"}, | ||
{"/logo.png", "examples/data/logo.png"}, | ||
}; | ||
|
||
auto process(auto& stream, auto const& request) -> demo::task<> | ||
{ | ||
std::cout << "request=" << request << "\n"; | ||
std::string method, url, version; | ||
std::string body; | ||
std::ostringstream out; | ||
if (std::istringstream(request) >> method >> url >> version | ||
&& files.contains(url)) | ||
{ | ||
std::cout << "url=" << url << "\n"; | ||
out << std::ifstream(files[url]).rdbuf(); | ||
body = out.str(); | ||
out.str({}); | ||
} | ||
|
||
out << "HTTP/1.1 " << (body.empty()? "404 not found": "200 found") << "\r\n" | ||
<< "Content-Length: " << body.size() << "\r\n" | ||
<< "\r\n" | ||
<< body; | ||
auto response{out.str()}; | ||
co_await net::async_send(stream, net::buffer(response)); | ||
} | ||
|
||
auto timeout(auto scheduler, auto duration, auto sender) | ||
{ | ||
return demo::when_any( | ||
std::move(sender), | ||
net::resume_after(scheduler, duration) | ||
| demo::into_error([]{ return std::error_code(demo::timeout, demo::category()); }) | ||
); | ||
} | ||
|
||
auto make_client_handler(auto scheduler, auto stream) -> demo::task<> | ||
{ | ||
char buffer[16]; | ||
std::string request; | ||
while (true) | ||
try { | ||
if (auto n = co_await timeout(scheduler, 2s, net::async_receive(stream, net::buffer(buffer)))) { | ||
std::string_view data(buffer, n); | ||
request += data; | ||
if (request.find("\r\n\r\n") != request.npos) | ||
{ | ||
co_await process(stream, request); | ||
break; | ||
} | ||
} | ||
else { | ||
//std::cout << "ERROR (via expected): " << std::get<0>(n.error()).message() << "\n"; | ||
break; | ||
} | ||
} | ||
catch (std::variant<std::error_code> const& ex) { | ||
std::cout << "ERROR: " << std::get<0>(ex).message() << "\n"; | ||
break; | ||
} | ||
|
||
|
||
co_return; | ||
} | ||
|
||
auto main() -> int | ||
{ | ||
demo::scope scope; | ||
|
||
net::io_context context; | ||
net::ip::tcp::endpoint endpoint(net::ip::address_v4::any(), 12345); | ||
net::ip::tcp::acceptor acceptor(context, endpoint); | ||
|
||
scope.spawn(std::invoke([](auto scheduler, auto& scope, auto& acceptor)->demo::task<> { | ||
while (true) | ||
{ | ||
auto[stream, address] = co_await net::async_accept(acceptor); | ||
std::cout << "received client: " << address << "\n"; | ||
scope.spawn(make_client_handler(scheduler, std::move(stream))); | ||
} | ||
}, context.get_scheduler(), scope, acceptor)); | ||
|
||
context.run(); | ||
} |