Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 996c457

Browse files
committed
async-server-rooms example added
1 parent bc18b9b commit 996c457

File tree

13 files changed

+636
-0
lines changed

13 files changed

+636
-0
lines changed

‎async-server-rooms/CMakeLists.txt‎

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
cmake_minimum_required(VERSION 3.1)
2+
3+
set(project_name async-server-rooms) ## rename your project here
4+
5+
project(${project_name})
6+
7+
set(CMAKE_CXX_STANDARD 11)
8+
9+
include_directories(src)
10+
11+
add_library(${project_name}-lib
12+
src/AppComponent.hpp
13+
src/controller/RoomsController.hpp
14+
src/rooms/Peer.cpp
15+
src/rooms/Peer.hpp
16+
src/rooms/Room.cpp
17+
src/rooms/Room.hpp
18+
src/rooms/Lobby.cpp
19+
src/rooms/Lobby.hpp
20+
)
21+
22+
## link libs
23+
24+
find_package(oatpp 0.19.4 REQUIRED)
25+
find_package(oatpp-websocket 0.19.4 REQUIRED)
26+
27+
target_link_libraries(${project_name}-lib
28+
PUBLIC oatpp::oatpp
29+
PUBLIC oatpp::oatpp-test
30+
PUBLIC oatpp::oatpp-websocket
31+
)
32+
33+
## add executables
34+
35+
add_executable(${project_name}-exe
36+
src/App.cpp
37+
)
38+
target_link_libraries(${project_name}-exe ${project_name}-lib)
39+
add_dependencies(${project_name}-exe ${project_name}-lib)
40+
41+
add_executable(${project_name}-test
42+
test/tests.cpp
43+
test/WSTest.cpp
44+
test/WSTest.hpp
45+
)
46+
target_link_libraries(${project_name}-test ${project_name}-lib)
47+
add_dependencies(${project_name}-test ${project_name}-lib)
48+
49+
set_target_properties(${project_name}-lib ${project_name}-exe ${project_name}-test PROPERTIES
50+
CXX_STANDARD 11
51+
CXX_EXTENSIONS OFF
52+
CXX_STANDARD_REQUIRED ON
53+
LINKER_LANGUAGE CXX
54+
)

‎async-server-rooms/src/App.cpp‎

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
#include "controller/RoomsController.hpp"
2+
#include "./AppComponent.hpp"
3+
4+
#include "oatpp/network/server/Server.hpp"
5+
6+
#include <iostream>
7+
8+
void run() {
9+
10+
/* Register Components in scope of run() method */
11+
AppComponent components;
12+
13+
/* Get router component */
14+
OATPP_COMPONENT(std::shared_ptr<oatpp::web::server::HttpRouter>, router);
15+
16+
/* Create RoomsController and add all of its endpoints to router */
17+
auto myController = std::make_shared<RoomsController>();
18+
myController->addEndpointsToRouter(router);
19+
20+
/* Get connection handler component */
21+
OATPP_COMPONENT(std::shared_ptr<oatpp::network::server::ConnectionHandler>, connectionHandler, "http");
22+
23+
/* Get connection provider component */
24+
OATPP_COMPONENT(std::shared_ptr<oatpp::network::ServerConnectionProvider>, connectionProvider);
25+
26+
/* Create server which takes provided TCP connections and passes them to HTTP connection handler */
27+
oatpp::network::server::Server server(connectionProvider, connectionHandler);
28+
29+
/* Priny info about server port */
30+
OATPP_LOGI("MyApp", "Server running on port %s", connectionProvider->getProperty("port").getData());
31+
32+
/* Run server */
33+
server.run();
34+
35+
}
36+
37+
int main(int argc, const char * argv[]) {
38+
39+
oatpp::base::Environment::init();
40+
41+
run();
42+
43+
oatpp::base::Environment::destroy();
44+
45+
return 0;
46+
}
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
#ifndef AppComponent_hpp
2+
#define AppComponent_hpp
3+
4+
#include "rooms/Lobby.hpp"
5+
6+
#include "oatpp/web/server/AsyncHttpConnectionHandler.hpp"
7+
#include "oatpp/web/server/HttpRouter.hpp"
8+
#include "oatpp/network/server/SimpleTCPConnectionProvider.hpp"
9+
10+
#include "oatpp/parser/json/mapping/ObjectMapper.hpp"
11+
12+
#include "oatpp/core/macro/component.hpp"
13+
14+
/**
15+
* Class which creates and holds Application components and registers components in oatpp::base::Environment
16+
* Order of components initialization is from top to bottom
17+
*/
18+
class AppComponent {
19+
public:
20+
21+
/**
22+
* Create Async Executor
23+
*/
24+
OATPP_CREATE_COMPONENT(std::shared_ptr<oatpp::async::Executor>, executor)([] {
25+
return std::make_shared<oatpp::async::Executor>(
26+
4 /* Data-Processing threads */,
27+
1 /* I/O threads */,
28+
1 /* Timer threads */
29+
);
30+
}());
31+
32+
/**
33+
* Create ConnectionProvider component which listens on the port
34+
*/
35+
OATPP_CREATE_COMPONENT(std::shared_ptr<oatpp::network::ServerConnectionProvider>, serverConnectionProvider)([] {
36+
return oatpp::network::server::SimpleTCPConnectionProvider::createShared(8000);
37+
}());
38+
39+
/**
40+
* Create Router component
41+
*/
42+
OATPP_CREATE_COMPONENT(std::shared_ptr<oatpp::web::server::HttpRouter>, httpRouter)([] {
43+
return oatpp::web::server::HttpRouter::createShared();
44+
}());
45+
46+
/**
47+
* Create ConnectionHandler component which uses Router component to route requests
48+
*/
49+
OATPP_CREATE_COMPONENT(std::shared_ptr<oatpp::network::server::ConnectionHandler>, serverConnectionHandler)("http", [] {
50+
OATPP_COMPONENT(std::shared_ptr<oatpp::web::server::HttpRouter>, router); // get Router component
51+
OATPP_COMPONENT(std::shared_ptr<oatpp::async::Executor>, executor); // get Async executor component
52+
return oatpp::web::server::AsyncHttpConnectionHandler::createShared(router, executor);
53+
}());
54+
55+
/**
56+
* Create ObjectMapper component to serialize/deserialize DTOs in Contoller's API
57+
*/
58+
OATPP_CREATE_COMPONENT(std::shared_ptr<oatpp::data::mapping::ObjectMapper>, apiObjectMapper)([] {
59+
return oatpp::parser::json::mapping::ObjectMapper::createShared();
60+
}());
61+
62+
/**
63+
* Create websocket connection handler
64+
*/
65+
OATPP_CREATE_COMPONENT(std::shared_ptr<oatpp::network::server::ConnectionHandler>, websocketConnectionHandler)("websocket", [] {
66+
OATPP_COMPONENT(std::shared_ptr<oatpp::async::Executor>, executor);
67+
auto connectionHandler = oatpp::websocket::AsyncConnectionHandler::createShared(executor);
68+
connectionHandler->setSocketInstanceListener(std::make_shared<Lobby>());
69+
return connectionHandler;
70+
}());
71+
72+
};
73+
74+
#endif /* AppComponent_hpp */
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
2+
#ifndef RoomsController_hpp
3+
#define RoomsController_hpp
4+
5+
#include "oatpp-websocket/Handshaker.hpp"
6+
7+
#include "oatpp/web/server/api/ApiController.hpp"
8+
9+
#include "oatpp/network/server/ConnectionHandler.hpp"
10+
11+
#include "oatpp/core/macro/codegen.hpp"
12+
#include "oatpp/core/macro/component.hpp"
13+
14+
/**
15+
* Controller with WebSocket-connect endpoint.
16+
*/
17+
class RoomsController : public oatpp::web::server::api::ApiController {
18+
private:
19+
typedef RoomsController __ControllerType;
20+
private:
21+
OATPP_COMPONENT(std::shared_ptr<oatpp::network::server::ConnectionHandler>, websocketConnectionHandler, "websocket");
22+
public:
23+
RoomsController(OATPP_COMPONENT(std::shared_ptr<ObjectMapper>, objectMapper))
24+
: oatpp::web::server::api::ApiController(objectMapper)
25+
{}
26+
public:
27+
28+
/**
29+
* Begin ENDPOINTs generation ('ApiController' codegen)
30+
*/
31+
#include OATPP_CODEGEN_BEGIN(ApiController)
32+
33+
ENDPOINT_ASYNC("GET", "/", Root) {
34+
35+
ENDPOINT_ASYNC_INIT(Root)
36+
37+
const char* pageTemplate =
38+
"<html lang='en'>"
39+
"<head>"
40+
"<meta charset=utf-8/>"
41+
"</head>"
42+
"<body>"
43+
"<p>Hello Async WebSocket Rooms Server!</p>"
44+
"<p>Connect to chat room:</p>"
45+
"<code>localhost:8000/ws/chat/{room_name}/?nickname={nickname}</code>"
46+
"</body>"
47+
"</html>";
48+
49+
Action act() override {
50+
return _return(controller->createResponse(Status::CODE_200, pageTemplate));
51+
}
52+
53+
};
54+
55+
ENDPOINT_ASYNC("GET", "ws/chat/{room-name}/*", WS) {
56+
57+
ENDPOINT_ASYNC_INIT(WS)
58+
59+
Action act() override {
60+
61+
auto roomName = request->getPathVariable("room-name");
62+
auto nickname = request->getQueryParameter("nickname");
63+
64+
OATPP_ASSERT_HTTP(nickname, Status::CODE_400, "No nickname specified.");
65+
66+
/* Websocket handshake */
67+
auto response = oatpp::websocket::Handshaker::serversideHandshake(request->getHeaders(), controller->websocketConnectionHandler);
68+
69+
auto parameters = std::make_shared<oatpp::network::server::ConnectionHandler::ParameterMap>();
70+
71+
(*parameters)["roomName"] = roomName;
72+
(*parameters)["nickname"] = nickname;
73+
74+
/* Set connection upgrade params */
75+
response->setConnectionUpgradeParameters(parameters);
76+
77+
return _return(response);
78+
79+
}
80+
81+
};
82+
83+
// TODO Insert Your endpoints here !!!
84+
85+
/**
86+
* Finish ENDPOINTs generation ('ApiController' codegen)
87+
*/
88+
#include OATPP_CODEGEN_END(ApiController)
89+
90+
};
91+
92+
#endif /* RoomsController_hpp */
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
2+
#include "Lobby.hpp"
3+
4+
v_int32 Lobby::obtainNewUserId() {
5+
return m_userIdCounter ++;
6+
}
7+
8+
std::shared_ptr<Room> Lobby::getOrCreateRoom(const oatpp::String& roomName) {
9+
std::lock_guard<std::mutex> lock(m_roomsMutex);
10+
std::shared_ptr<Room>& room = m_rooms[roomName];
11+
if(!room) {
12+
room = std::make_shared<Room>(roomName);
13+
}
14+
return room;
15+
}
16+
17+
void Lobby::onAfterCreate_NonBlocking(const std::shared_ptr<AsyncWebSocket>& socket, const std::shared_ptr<const ParameterMap>& params) {
18+
19+
auto roomName = params->find("roomName")->second;
20+
auto nickname = params->find("nickname")->second;
21+
auto room = getOrCreateRoom(roomName);
22+
23+
auto peer = std::make_shared<Peer>(socket, room, nickname, obtainNewUserId());
24+
socket->setListener(peer);
25+
26+
room->addPeer(peer);
27+
room->sendMessage(nickname + " joined " + roomName);
28+
29+
}
30+
31+
void Lobby::onBeforeDestroy_NonBlocking(const std::shared_ptr<AsyncWebSocket>& socket) {
32+
33+
auto peer = std::static_pointer_cast<Peer>(socket->getListener());
34+
auto nickname = peer->getNickname();
35+
auto room = peer->getRoom();
36+
37+
room->removePeerByUserId(peer->getUserId());
38+
39+
room->sendMessage(nickname + " left the room");
40+
41+
/* Remove circle `std::shared_ptr` dependencies */
42+
socket->setListener(nullptr);
43+
44+
}
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
2+
#ifndef ASYNC_SERVER_ROOMS_LOBBY_HPP
3+
#define ASYNC_SERVER_ROOMS_LOBBY_HPP
4+
5+
#include "./Room.hpp"
6+
7+
#include "oatpp-websocket/AsyncConnectionHandler.hpp"
8+
9+
#include <unordered_map>
10+
#include <mutex>
11+
12+
class Lobby : public oatpp::websocket::AsyncConnectionHandler::SocketInstanceListener {
13+
public:
14+
std::atomic<v_int32> m_userIdCounter;
15+
std::unordered_map<oatpp::String, std::shared_ptr<Room>> m_rooms;
16+
std::mutex m_roomsMutex;
17+
public:
18+
19+
Lobby()
20+
: m_userIdCounter(0)
21+
{}
22+
23+
/**
24+
* Generate id for new user
25+
* @return
26+
*/
27+
v_int32 obtainNewUserId();
28+
29+
/**
30+
* Get room by name or create new one if not exists.
31+
* @param roomName
32+
* @return
33+
*/
34+
std::shared_ptr<Room> getOrCreateRoom(const oatpp::String& roomName);
35+
36+
public:
37+
38+
/**
39+
* Called when socket is created
40+
*/
41+
void onAfterCreate_NonBlocking(const std::shared_ptr<AsyncWebSocket>& socket, const std::shared_ptr<const ParameterMap>& params) override;
42+
43+
/**
44+
* Called before socket instance is destroyed.
45+
*/
46+
void onBeforeDestroy_NonBlocking(const std::shared_ptr<AsyncWebSocket>& socket) override;
47+
48+
};
49+
50+
51+
#endif //ASYNC_SERVER_ROOMS_LOBBY_HPP

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /