Cavoke  1.1.0
A Platform for creating and hosting multiplayer turn-based board games
Loading...
Searching...
No Matches
rooms_storage.cpp
1#include "rooms_storage.h"
2#include <utility>
3#include "drogon/orm/Criteria.h"
4#include "sql-models/RoomJoins.h"
5
6namespace cavoke::server::model {
7
8using namespace drogon::orm;
9
10RoomsStorage::RoomsStorage(std::shared_ptr<SessionsStorage> mSessionsStorage)
11 : m_sessions_storage(std::move(mSessionsStorage)) {
12}
13
14std::optional<RoomsStorage::RoomInfo> RoomsStorage::get_by_id(
15 const std::string &room_id) {
16 auto mp_rooms_trans = MAPPER_FOR(drogon_model::cavoke_orm::Rooms);
17 try {
18 const auto &room = mp_rooms_trans.findByPrimaryKey(room_id);
19 const auto &members = get_members(room_id);
20 return RoomInfo::from_room_and_members(room, members);
21 } catch (const UnexpectedRows &e) {
22 return std::nullopt;
23 }
24}
25
26std::vector<GameSessionAccessObject::UserInfo> RoomsStorage::get_members(
27 const std::string &room_id) {
28 auto mp_rooms_trans = MAPPER_FOR(drogon_model::cavoke_orm::Rooms);
29 auto mp_joins_trans = MAPPER_FOR(drogon_model::cavoke_orm::RoomJoins);
30 auto mp_users_trans = MAPPER_FOR(
31 drogon_model::cavoke_orm::Users); // !!! we need a users controller !!!
32
33 auto joins = mp_joins_trans.findBy(
34 Criteria(drogon_model::cavoke_orm::RoomJoins::Cols::_room_id,
35 CompareOperator::EQ, room_id));
36
37 std::vector<GameSessionAccessObject::UserInfo> members;
38 members.reserve(joins.size());
39 std::transform(
40 joins.begin(), joins.end(), std::back_inserter(members),
41 [&mp_users_trans](const drogon_model::cavoke_orm::RoomJoins &join) {
42 return GameSessionAccessObject::UserInfo::from_user(
43 mp_users_trans.findByPrimaryKey(join.getValueOfUserId()));
44 });
45
46 return members;
47}
48
49std::optional<RoomsStorage::RoomInfo> RoomsStorage::get_by_invite_code(
50 const std::string &invite_code) {
51 auto transaction = drogon::app().getDbClient()->newTransaction();
52 auto mp_rooms_trans = MAPPER_FOR(drogon_model::cavoke_orm::Rooms);
53 try {
54 const auto &room = mp_rooms_trans.findOne(
55 Criteria(drogon_model::cavoke_orm::Rooms::Cols::_invite_code,
56 CompareOperator::EQ, invite_code));
57 const auto &members = get_members(room.getValueOfId());
58 return RoomInfo::from_room_and_members(room, members);
59
60 } catch (const UnexpectedRows &) {
61 return std::nullopt;
62 }
63}
64
65void RoomsStorage::add_user(const std::string &room_id,
66 const std::string &user_id) {
67 if (is_member(room_id, user_id)) {
68 return;
69 }
70
71 if (!get_by_id(room_id).has_value()) {
72 throw room_error("Cannot add user. No room with id " + room_id);
73 }
74
75 auto join = drogon_model::cavoke_orm::RoomJoins();
76 {
77 join.setRoomId(room_id);
78 join.setUserId(user_id);
79 }
80
81 auto mp_joins_trans = MAPPER_FOR(drogon_model::cavoke_orm::RoomJoins);
82 mp_joins_trans.insert(join);
83}
84
85void RoomsStorage::remove_user(const std::string &room_id,
86 const std::string &user_id) {
87 if (!is_member(room_id, user_id)) {
88 return;
89 }
90 drogon::app().getDbClient()->execSqlSync(
91 "select leave_room($1::uuid, $2::varchar);", room_id, user_id);
92}
93
94bool RoomsStorage::is_member(const std::string &room_id,
95 const std::string &user_id) {
96 auto mp_joins_trans = MAPPER_FOR(drogon_model::cavoke_orm::RoomJoins);
97 size_t joins_count = mp_joins_trans.count(
98 Criteria(drogon_model::cavoke_orm::RoomJoins::Cols::_room_id,
99 CompareOperator::EQ, room_id) &&
100 Criteria(drogon_model::cavoke_orm::RoomJoins::Cols::_user_id,
101 CompareOperator::EQ, user_id));
102 return joins_count > 0;
103}
104
105RoomsStorage::RoomInfo RoomsStorage::create_room(
106 const std::string &host_id,
107 const std::string &display_name) {
108 auto room = drogon_model::cavoke_orm::Rooms();
109 {
110 room.setId(drogon::utils::getUuid());
111 room.setDisplayName(display_name);
112 room.setSessionIdToNull();
113 }
114
115 auto join = drogon_model::cavoke_orm::RoomJoins();
116 {
117 join.setRoomId(room.getValueOfId());
118 join.setUserId(host_id);
119 }
120
121 {
122 // auto transaction =
123 // drogon::app().getDbClient()->newTransaction();
124 auto mp_rooms_trans = MAPPER_FOR(drogon_model::cavoke_orm::Rooms);
125 auto mp_joins_trans = MAPPER_FOR(drogon_model::cavoke_orm::RoomJoins);
126
127 mp_rooms_trans.insert(room);
128 mp_joins_trans.insert(join);
129
130 room = mp_rooms_trans.findByPrimaryKey(room.getValueOfId());
131 room.setHostId(host_id);
132 mp_rooms_trans.update(room);
133 }
134
135 return RoomsStorage::RoomInfo::from_room_and_members(
136 room, get_members(room.getValueOfId()));
137}
138
139GameSessionAccessObject::GameSessionInfo RoomsStorage::create_session(
140 const std::string &room_id,
141 const GameConfig &game_config) {
142 auto opt_room_info = get_by_id(room_id);
143 if (!opt_room_info.has_value()) {
144 throw room_error("Cannot create session. No room with id " + room_id);
145 }
146 auto room_info = opt_room_info.value();
147
148 if (!room_info.session_id.empty()) {
149 auto current_session =
150 m_sessions_storage->get_sessionAO(room_info.session_id);
151 if (current_session.get_session_info().status !=
152 GameSessionAccessObject::SessionStatus::FINISHED) {
153 throw room_error("Cannot create session in room " + room_id +
154 ". Session already exists and not "
155 "finished.");
156 }
157 }
158
159 auto new_session = m_sessions_storage->create_session(
160 game_config, room_info.host_id, room_id);
161
162 return new_session;
163}
164
165room_error::room_error(std::string message)
166 : cavoke_base_exception(std::move(message),
167 InvalidClientInput,
168 "cavoke/rooms") {
169}
170
171RoomsStorage::RoomInfo RoomsStorage::RoomInfo::from_room_and_members(
172 const drogon_model::cavoke_orm::Rooms &room_orm,
173 const std::vector<GameSessionAccessObject::UserInfo> &members) {
174 return {room_orm.getValueOfId(),
175 room_orm.getValueOfInviteCode(),
176 room_orm.getValueOfDisplayName(),
177 room_orm.getValueOfSessionId(),
178 {},
179 room_orm.getValueOfHostId(),
180 members};
181}
182} // namespace cavoke::server::model