forked from couchbaselabs/crouton
-
Notifications
You must be signed in to change notification settings - Fork 1
/
demo_server.cc
101 lines (83 loc) · 2.99 KB
/
demo_server.cc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
//
// demo_server.cc
//
// Copyright 2023-Present Couchbase, Inc. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
#include "crouton/Crouton.hh"
#include "crouton/io/TCPServer.hh"
#include "crouton/util/Logging.hh"
#include <functional>
#include <iomanip>
#include "crouton/util/MiniOStream.hh"
#include <memory>
using namespace std;
using namespace crouton;
using namespace crouton::io;
/* NOTE to newbies: this file uses some simple/optional macros that are used everywhere in Crouton
to highlight suspend points and use of asynchronous code:
static ASYNC --> [[nodiscard]] static Future
AWAIT --> co_await
RETURN --> co_return
*/
static constexpr uint16_t kPort = 34567;
static ASYNC<void> serveRoot(http::Handler::Request const& req, http::Handler::Response& res) {
res.writeHeader("Content-Type", "text/plain");
AWAIT res.writeToBody("Hi!\r\n");
RETURN noerror;
}
static ASYNC<void> serveWebSocket(http::Handler::Request const& req, http::Handler::Response& res) {
ws::ServerWebSocket socket;
if (! AWAIT socket.connect(req, res))
RETURN noerror;
Log->info("-- Opened WebSocket");
Generator<ws::Message> rcvr = socket.receive();
Result<ws::Message> msg;
while ((msg = AWAIT rcvr)) {
Log->info("\treceived {}", msg);
switch (msg->type) {
case ws::Message::Text:
case ws::Message::Binary:
(void) socket.send(*msg); // no need to wait
break;
case ws::Message::Close:
AWAIT socket.send(*msg); // echo the close request to complete the close.
break;
default:
break; // WebSocket itself handles Ping and Pong
}
}
Log->info("-- Closing WebSocket");
AWAIT socket.close();
RETURN noerror;
}
static std::vector<http::Handler::Route> sRoutes = {
{http::Method::GET, regex("/"), serveRoot},
{http::Method::GET, regex("/ws/?"), serveWebSocket},
};
static Task connectionTask(std::shared_ptr<ISocket> client) {
Log->info("-- Accepted connection");
http::Handler handler(client->stream(), sRoutes);
AWAIT handler.run();
Log->info("-- Done!\n");
}
static Task run() {
static TCPServer server(kPort);
Log->info("Listening at http://localhost:{}/ and ws://localhost:{}/ws", kPort, kPort);
server.listen([](std::shared_ptr<ISocket> client) {
connectionTask(std::move(client));
});
RETURN;
}
CROUTON_MAIN(run)