mirror of
https://github.com/SWG-Source/stationapi.git
synced 2026-10-18 09:02:53 -04:00
Split into library and application code to prepare for future stationapi based apps
This commit is contained in:
@@ -0,0 +1,84 @@
|
||||
include_directories(
|
||||
${CMAKE_CURRENT_SOURCE_DIR}
|
||||
${PROJECT_SOURCE_DIR}/src/stationapi
|
||||
${PROJECT_SOURCE_DIR}/externals/easyloggingpp
|
||||
${PROJECT_SOURCE_DIR}/externals/udplibrary
|
||||
${Boost_INCLUDE_DIRS}
|
||||
${SQLite3_INCLUDE_DIR})
|
||||
|
||||
set(SOURCES
|
||||
protocol/AddBan.hpp
|
||||
protocol/AddFriend.hpp
|
||||
protocol/AddIgnore.hpp
|
||||
protocol/AddInvite.hpp
|
||||
protocol/AddModerator.hpp
|
||||
protocol/CreateRoom.hpp
|
||||
protocol/DestroyAvatar.hpp
|
||||
protocol/DestroyRoom.hpp
|
||||
protocol/EnterRoom.hpp
|
||||
protocol/FailoverReLoginAvatar.hpp
|
||||
protocol/FriendStatus.hpp
|
||||
protocol/GetAnyAvatar.hpp
|
||||
protocol/GetPersistentHeaders.hpp
|
||||
protocol/GetPersistentMessage.hpp
|
||||
protocol/GetRoom.hpp
|
||||
protocol/GetRoomSummaries.hpp
|
||||
protocol/IgnoreStatus.hpp
|
||||
protocol/KickAvatar.hpp
|
||||
protocol/LeaveRoom.hpp
|
||||
protocol/LoginAvatar.hpp
|
||||
protocol/LogoutAvatar.hpp
|
||||
protocol/Protocol.cpp
|
||||
protocol/RegistrarGetChatServer.hpp
|
||||
protocol/RemoveBan.hpp
|
||||
protocol/RemoveFriend.hpp
|
||||
protocol/RemoveIgnore.hpp
|
||||
protocol/RemoveInvite.hpp
|
||||
protocol/RemoveModerator.hpp
|
||||
protocol/SendInstantMessage.hpp
|
||||
protocol/SendPersistentMessage.hpp
|
||||
protocol/SendRoomMessage.hpp
|
||||
protocol/SetApiVersion.hpp
|
||||
protocol/SetAvatarAttributes.hpp
|
||||
protocol/UpdatePersistentMessage.hpp
|
||||
|
||||
ChatAvatar.cpp
|
||||
ChatAvatar.hpp
|
||||
ChatAvatarService.cpp
|
||||
ChatAvatarService.hpp
|
||||
ChatEnums.cpp
|
||||
ChatEnums.hpp
|
||||
ChatRoom.cpp
|
||||
ChatRoom.hpp
|
||||
ChatRoomService.cpp
|
||||
ChatRoomService.hpp
|
||||
GatewayClient.cpp
|
||||
GatewayClient.hpp
|
||||
GatewayNode.cpp
|
||||
GatewayNode.hpp
|
||||
main.cpp
|
||||
Message.hpp
|
||||
PersistentMessage.hpp
|
||||
PersistentMessageService.cpp
|
||||
PersistentMessageService.hpp
|
||||
RegistrarClient.cpp
|
||||
RegistrarClient.hpp
|
||||
RegistrarNode.cpp
|
||||
RegistrarNode.hpp
|
||||
StationChatApp.cpp
|
||||
StationChatApp.hpp
|
||||
StationChatConfig.hpp)
|
||||
|
||||
add_executable(stationchat ${SOURCES})
|
||||
|
||||
GroupSourceByFilesystem("${SOURCES}")
|
||||
|
||||
target_link_libraries(stationchat
|
||||
stationapi
|
||||
udplibrary
|
||||
${Boost_LIBRARIES}
|
||||
${SQLite3_LIBRARY})
|
||||
|
||||
if(WIN32)
|
||||
target_link_libraries(stationchat ws2_32)
|
||||
endif()
|
||||
@@ -0,0 +1,91 @@
|
||||
#include "ChatAvatar.hpp"
|
||||
#include "ChatAvatarService.hpp"
|
||||
#include "ChatRoom.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
ChatAvatar::ChatAvatar(ChatAvatarService * avatarService)
|
||||
: avatarService_{avatarService} {}
|
||||
|
||||
ChatAvatar::ChatAvatar(ChatAvatarService* avatarService, const std::u16string& name, const std::u16string& address, uint32_t userId,
|
||||
uint32_t attributes, const std::u16string& loginLocation)
|
||||
: avatarService_{avatarService}
|
||||
, userId_{userId}
|
||||
, name_{name}
|
||||
, address_{address}
|
||||
, attributes_{attributes}
|
||||
, loginLocation_{loginLocation} {}
|
||||
|
||||
void ChatAvatar::SetAttributes(const uint32_t attributes) { attributes_ = attributes; }
|
||||
|
||||
void ChatAvatar::AddFriend(ChatAvatar* avatar, const std::u16string& comment) {
|
||||
if (IsFriend(avatar)) return;
|
||||
if (IsIgnored(avatar)) RemoveIgnore(avatar);
|
||||
|
||||
friendList_.push_back(FriendContact{avatar, comment});
|
||||
|
||||
avatarService_->PersistFriend(avatarId_, avatar->avatarId_, comment);
|
||||
}
|
||||
|
||||
void ChatAvatar::RemoveFriend(const ChatAvatar* avatar) {
|
||||
auto del_iter = std::remove_if(std::begin(friendList_), std::end(friendList_),
|
||||
[avatar](auto& frnd) { return frnd.frnd->GetAvatarId() == avatar->GetAvatarId(); });
|
||||
|
||||
if (del_iter != std::end(friendList_)) {
|
||||
friendList_.erase(del_iter);
|
||||
|
||||
avatarService_->RemoveFriend(avatarId_, avatar->avatarId_);
|
||||
}
|
||||
}
|
||||
|
||||
void ChatAvatar::UpdateFriendComment(const ChatAvatar* avatar, const std::u16string& comment) {
|
||||
auto find_iter = std::find_if(std::begin(friendList_), std::end(friendList_),
|
||||
[avatar](auto& frnd) { return frnd.frnd->GetAvatarId() == avatar->GetAvatarId(); });
|
||||
|
||||
if (find_iter != std::end(friendList_)) {
|
||||
find_iter->comment = comment;
|
||||
avatarService_->UpdateFriendComment(avatarId_, avatar->avatarId_, comment);
|
||||
}
|
||||
}
|
||||
|
||||
bool ChatAvatar::IsFriend(const ChatAvatar* avatar) {
|
||||
auto find_iter = std::find_if(std::begin(friendList_), std::end(friendList_),
|
||||
[avatar](auto& frnd) { return frnd.frnd->GetAvatarId() == avatar->GetAvatarId(); });
|
||||
|
||||
if (find_iter != std::end(friendList_)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void ChatAvatar::AddIgnore(ChatAvatar* avatar) {
|
||||
if (IsIgnored(avatar)) return;
|
||||
if (IsFriend(avatar)) RemoveFriend(avatar);
|
||||
|
||||
ignoreList_.push_back(IgnoreContact{avatar});
|
||||
|
||||
avatarService_->PersistIgnore(avatarId_, avatar->avatarId_);
|
||||
}
|
||||
|
||||
void ChatAvatar::RemoveIgnore(const ChatAvatar* avatar) {
|
||||
auto del_iter = std::remove_if(std::begin(ignoreList_), std::end(ignoreList_),
|
||||
[avatar](auto& ignored) { return ignored.ignored->GetAvatarId() == avatar->GetAvatarId(); });
|
||||
|
||||
if (del_iter != std::end(ignoreList_)) {
|
||||
ignoreList_.erase(del_iter);
|
||||
|
||||
avatarService_->RemoveIgnore(avatarId_, avatar->avatarId_);
|
||||
}
|
||||
}
|
||||
|
||||
bool ChatAvatar::IsIgnored(const ChatAvatar* avatar) {
|
||||
auto find_iter = std::find_if(std::begin(ignoreList_), std::end(ignoreList_),
|
||||
[avatar](auto& ignored) { return ignored.ignored->GetAvatarId() == avatar->GetAvatarId(); });
|
||||
|
||||
if (find_iter != std::end(ignoreList_)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
@@ -0,0 +1,131 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Serialization.hpp"
|
||||
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
class ChatAvatar;
|
||||
class ChatAvatarService;
|
||||
class ChatRoom;
|
||||
|
||||
enum class AvatarAttribute : uint32_t {
|
||||
INVISIBLE = 1 << 0,
|
||||
GM = 1 << 1,
|
||||
SUPERGM = 1 << 2,
|
||||
SUPERSNOOP = 1 << 3,
|
||||
EXTENDED = 1 << 4
|
||||
};
|
||||
|
||||
struct FriendContact {
|
||||
FriendContact(const ChatAvatar* frnd_, const std::u16string& comment_)
|
||||
: frnd{frnd_}
|
||||
, comment{comment_} {}
|
||||
|
||||
const ChatAvatar* frnd;
|
||||
std::u16string comment = u"";
|
||||
};
|
||||
|
||||
struct IgnoreContact {
|
||||
IgnoreContact(const ChatAvatar* ignored_)
|
||||
: ignored{ignored_} {}
|
||||
|
||||
const ChatAvatar* ignored;
|
||||
};
|
||||
|
||||
class ChatAvatar {
|
||||
public:
|
||||
explicit ChatAvatar(ChatAvatarService* avatarService);
|
||||
ChatAvatar(ChatAvatarService* avatarService, const std::u16string& name, const std::u16string& address, uint32_t userId,
|
||||
uint32_t attributes, const std::u16string& loginLocation);
|
||||
|
||||
bool IsInvisible() const { return (attributes_ & static_cast<uint32_t>(AvatarAttribute::INVISIBLE)) != 0; }
|
||||
bool IsGm() const { return (attributes_ & static_cast<uint32_t>(AvatarAttribute::GM)) != 0; }
|
||||
bool IsSuperGm() const { return (attributes_ & static_cast<uint32_t>(AvatarAttribute::SUPERGM)) != 0; }
|
||||
bool IsSuperSnoop() const { return (attributes_ & static_cast<uint32_t>(AvatarAttribute::SUPERSNOOP)) != 0; }
|
||||
|
||||
const uint32_t GetAvatarId() const { return avatarId_; }
|
||||
const uint32_t GetUserId() const { return userId_; }
|
||||
const std::u16string& GetName() const { return name_; }
|
||||
const std::u16string& GetAddress() const { return address_; }
|
||||
const uint32_t GetAttributes() const { return attributes_; }
|
||||
void SetAttributes(const uint32_t attributes);
|
||||
const std::u16string& GetLoginLocation() const { return loginLocation_; }
|
||||
const std::u16string& GetServer() const { return server_; }
|
||||
const std::u16string& GetGateway() const { return gateway_; }
|
||||
const uint32_t GetServerId() const { return serverId_; }
|
||||
const uint32_t GetGatewayId() const { return gatewayId_; }
|
||||
const std::u16string& GetEmail() const { return email_; }
|
||||
const uint32_t GetInboxLimit() const { return inboxLimit_; }
|
||||
const std::u16string& GetStatusMessage() const { return statusMessage_; }
|
||||
const bool IsOnline() const { return isOnline_; }
|
||||
|
||||
void AddFriend(ChatAvatar* avatar, const std::u16string& comment = u"");
|
||||
void RemoveFriend(const ChatAvatar* avatar);
|
||||
void UpdateFriendComment(const ChatAvatar* avatar, const std::u16string& comment);
|
||||
bool IsFriend(const ChatAvatar* avatar);
|
||||
|
||||
const std::vector<FriendContact> GetFriendList() const { return friendList_; }
|
||||
|
||||
void AddIgnore(ChatAvatar* avatar);
|
||||
void RemoveIgnore(const ChatAvatar* avatar);
|
||||
bool IsIgnored(const ChatAvatar* avatar);
|
||||
|
||||
const std::vector<IgnoreContact> GetIgnoreList() const { return ignoreList_; }
|
||||
|
||||
private:
|
||||
friend class ChatAvatarService;
|
||||
|
||||
ChatAvatarService* avatarService_;
|
||||
|
||||
uint32_t avatarId_ = 0;
|
||||
uint32_t userId_ = 0;
|
||||
std::u16string name_ = u"";
|
||||
std::u16string address_ = u"";
|
||||
uint32_t attributes_ = 0;
|
||||
std::u16string loginLocation_ = u"";
|
||||
std::u16string server_ = u"";
|
||||
std::u16string gateway_ = u"";
|
||||
uint32_t serverId_ = 0;
|
||||
uint32_t gatewayId_ = 0;
|
||||
std::u16string email_ = u"";
|
||||
uint32_t inboxLimit_ = 0;
|
||||
std::u16string statusMessage_ = u"";
|
||||
bool isOnline_ = false;
|
||||
|
||||
std::vector<FriendContact> friendList_;
|
||||
std::vector<IgnoreContact> ignoreList_;
|
||||
|
||||
std::vector<ChatRoom*> rooms_;
|
||||
};
|
||||
|
||||
template <typename StreamT>
|
||||
void write(StreamT& ar, const ChatAvatar* data) {
|
||||
write(ar, data->GetAvatarId());
|
||||
write(ar, data->GetUserId());
|
||||
write(ar, data->GetName());
|
||||
write(ar, data->GetAddress());
|
||||
write(ar, data->GetAttributes());
|
||||
write(ar, data->GetLoginLocation());
|
||||
write(ar, data->GetServer());
|
||||
write(ar, data->GetGateway());
|
||||
write(ar, data->GetServerId());
|
||||
write(ar, data->GetGatewayId());
|
||||
}
|
||||
|
||||
|
||||
template <typename StreamT>
|
||||
void write(StreamT& ar, const FriendContact& data) {
|
||||
write(ar, data.frnd->GetName());
|
||||
write(ar, data.frnd->GetAddress());
|
||||
write(ar, data.comment);
|
||||
write(ar, static_cast<short>(data.frnd->IsOnline() ? 1 : 0));
|
||||
}
|
||||
|
||||
template <typename StreamT>
|
||||
void write(StreamT& ar, const IgnoreContact& data) {
|
||||
write(ar, data.ignored->GetName());
|
||||
write(ar, data.ignored->GetAddress());
|
||||
}
|
||||
@@ -0,0 +1,488 @@
|
||||
#include "ChatAvatarService.hpp"
|
||||
#include "ChatAvatar.hpp"
|
||||
#include "SQLite3.hpp"
|
||||
#include "StringUtils.hpp"
|
||||
|
||||
#include <easylogging++.h>
|
||||
|
||||
ChatAvatarService::ChatAvatarService(sqlite3* db)
|
||||
: db_{db} {}
|
||||
|
||||
ChatAvatarService::~ChatAvatarService() {}
|
||||
|
||||
ChatAvatar* ChatAvatarService::GetAvatar(const std::u16string& name, const std::u16string& address) {
|
||||
ChatAvatar* avatar = GetCachedAvatar(name, address);
|
||||
|
||||
if (!avatar) {
|
||||
auto loadedAvatar = LoadStoredAvatar(name, address);
|
||||
if (loadedAvatar != nullptr) {
|
||||
avatar = loadedAvatar.get();
|
||||
avatarCache_.emplace_back(std::move(loadedAvatar));
|
||||
|
||||
LoadFriendList(avatar);
|
||||
LoadIgnoreList(avatar);
|
||||
}
|
||||
}
|
||||
|
||||
return avatar;
|
||||
}
|
||||
|
||||
ChatAvatar* ChatAvatarService::GetAvatar(uint32_t avatarId) {
|
||||
ChatAvatar* avatar = GetCachedAvatar(avatarId);
|
||||
|
||||
if (!avatar) {
|
||||
auto loadedAvatar = LoadStoredAvatar(avatarId);
|
||||
if (loadedAvatar != nullptr) {
|
||||
avatar = loadedAvatar.get();
|
||||
avatarCache_.emplace_back(std::move(loadedAvatar));
|
||||
|
||||
LoadFriendList(avatar);
|
||||
LoadIgnoreList(avatar);
|
||||
}
|
||||
}
|
||||
|
||||
return avatar;
|
||||
}
|
||||
|
||||
ChatAvatar* ChatAvatarService::CreateAvatar(const std::u16string& name, const std::u16string& address,
|
||||
uint32_t userId, uint32_t loginAttributes, const std::u16string& loginLocation) {
|
||||
auto tmp
|
||||
= std::make_unique<ChatAvatar>(this, name, address, userId, loginAttributes, loginLocation);
|
||||
auto avatar = tmp.get();
|
||||
|
||||
InsertAvatar(avatar);
|
||||
|
||||
avatarCache_.emplace_back(std::move(tmp));
|
||||
|
||||
return avatar;
|
||||
}
|
||||
|
||||
void ChatAvatarService::DestroyAvatar(ChatAvatar* avatar) {
|
||||
DeleteAvatar(avatar);
|
||||
LogoutAvatar(avatar);
|
||||
RemoveCachedAvatar(avatar->GetAvatarId());
|
||||
}
|
||||
|
||||
void ChatAvatarService::LoginAvatar(ChatAvatar* avatar) {
|
||||
avatar->isOnline_ = true;
|
||||
|
||||
if (!IsOnline(avatar)) {
|
||||
onlineAvatars_.push_back(avatar);
|
||||
}
|
||||
}
|
||||
|
||||
void ChatAvatarService::LogoutAvatar(ChatAvatar* avatar) {
|
||||
avatar->isOnline_ = false;
|
||||
|
||||
onlineAvatars_.erase(std::remove_if(
|
||||
std::begin(onlineAvatars_), std::end(onlineAvatars_), [avatar](auto onlineAvatar) {
|
||||
return onlineAvatar->GetAvatarId() == avatar->GetAvatarId();
|
||||
}));
|
||||
}
|
||||
|
||||
void ChatAvatarService::PersistAvatar(const ChatAvatar* avatar) { UpdateAvatar(avatar); }
|
||||
|
||||
void ChatAvatarService::PersistFriend(
|
||||
uint32_t srcAvatarId, uint32_t destAvatarId, const std::u16string& comment) {
|
||||
sqlite3_stmt* stmt;
|
||||
char sql[] = "INSERT INTO friend (avatar_id, friend_avatar_id, comment) VALUES (@avatar_id, "
|
||||
"@friend_avatar_id, @comment)";
|
||||
|
||||
auto result = sqlite3_prepare_v2(db_, sql, -1, &stmt, 0);
|
||||
if (result != SQLITE_OK) {
|
||||
throw SQLite3Exception{result, sqlite3_errmsg(db_)};
|
||||
}
|
||||
|
||||
int avatarIdIdx = sqlite3_bind_parameter_index(stmt, "@avatar_id");
|
||||
int friendAvatarIdIdx = sqlite3_bind_parameter_index(stmt, "@friend_avatar_id");
|
||||
int commentIdx = sqlite3_bind_parameter_index(stmt, "@comment");
|
||||
|
||||
std::string commentStr = FromWideString(comment);
|
||||
|
||||
sqlite3_bind_int(stmt, avatarIdIdx, srcAvatarId);
|
||||
sqlite3_bind_int(stmt, friendAvatarIdIdx, destAvatarId);
|
||||
sqlite3_bind_text(stmt, commentIdx, commentStr.c_str(), -1, 0);
|
||||
|
||||
result = sqlite3_step(stmt);
|
||||
if (result != SQLITE_DONE) {
|
||||
throw SQLite3Exception{result, sqlite3_errmsg(db_)};
|
||||
}
|
||||
}
|
||||
|
||||
void ChatAvatarService::PersistIgnore(uint32_t srcAvatarId, uint32_t destAvatarId) {
|
||||
sqlite3_stmt* stmt;
|
||||
char sql[] = "INSERT INTO ignore (avatar_id, ignore_avatar_id, comment) VALUES (@avatar_id, "
|
||||
"@ignore_avatar_id)";
|
||||
|
||||
auto result = sqlite3_prepare_v2(db_, sql, -1, &stmt, 0);
|
||||
if (result != SQLITE_OK) {
|
||||
throw SQLite3Exception{result, sqlite3_errmsg(db_)};
|
||||
}
|
||||
|
||||
int avatarIdIdx = sqlite3_bind_parameter_index(stmt, "@avatar_id");
|
||||
int ignoreAvatarIdIdx = sqlite3_bind_parameter_index(stmt, "@ignore_avatar_id");
|
||||
|
||||
sqlite3_bind_int(stmt, avatarIdIdx, srcAvatarId);
|
||||
sqlite3_bind_int(stmt, ignoreAvatarIdIdx, destAvatarId);
|
||||
|
||||
result = sqlite3_step(stmt);
|
||||
if (result != SQLITE_DONE) {
|
||||
throw SQLite3Exception{result, sqlite3_errmsg(db_)};
|
||||
}
|
||||
}
|
||||
|
||||
void ChatAvatarService::RemoveFriend(uint32_t srcAvatarId, uint32_t destAvatarId) {
|
||||
sqlite3_stmt* stmt;
|
||||
|
||||
char sql[] = "DELETE FROM friend WHERE avatar_id = @avatar_id AND friend_avatar_id = "
|
||||
"@friend_avatar_id";
|
||||
|
||||
auto result = sqlite3_prepare_v2(db_, sql, -1, &stmt, 0);
|
||||
if (result != SQLITE_OK) {
|
||||
throw SQLite3Exception{result, sqlite3_errmsg(db_)};
|
||||
}
|
||||
|
||||
int avatarIdIdx = sqlite3_bind_parameter_index(stmt, "@avatar_id");
|
||||
int friendAvatarIdIdx = sqlite3_bind_parameter_index(stmt, "@friend_avatar_id");
|
||||
|
||||
sqlite3_bind_int(stmt, avatarIdIdx, srcAvatarId);
|
||||
sqlite3_bind_int(stmt, friendAvatarIdIdx, destAvatarId);
|
||||
|
||||
result = sqlite3_step(stmt);
|
||||
if (result != SQLITE_DONE) {
|
||||
throw SQLite3Exception{result, sqlite3_errmsg(db_)};
|
||||
}
|
||||
}
|
||||
|
||||
void ChatAvatarService::RemoveIgnore(uint32_t srcAvatarId, uint32_t destAvatarId) {
|
||||
sqlite3_stmt* stmt;
|
||||
|
||||
char sql[] = "DELETE FROM ignore WHERE avatar_id = @avatar_id AND ignore_avatar_id = "
|
||||
"@ignore_avatar_id";
|
||||
|
||||
auto result = sqlite3_prepare_v2(db_, sql, -1, &stmt, 0);
|
||||
if (result != SQLITE_OK) {
|
||||
throw SQLite3Exception{result, sqlite3_errmsg(db_)};
|
||||
}
|
||||
|
||||
int avatarIdIdx = sqlite3_bind_parameter_index(stmt, "@avatar_id");
|
||||
int ignoreAvatarIdIdx = sqlite3_bind_parameter_index(stmt, "@ignore_avatar_id");
|
||||
|
||||
sqlite3_bind_int(stmt, avatarIdIdx, srcAvatarId);
|
||||
sqlite3_bind_int(stmt, ignoreAvatarIdIdx, destAvatarId);
|
||||
|
||||
result = sqlite3_step(stmt);
|
||||
if (result != SQLITE_DONE) {
|
||||
throw SQLite3Exception{result, sqlite3_errmsg(db_)};
|
||||
}
|
||||
}
|
||||
|
||||
void ChatAvatarService::UpdateFriendComment(
|
||||
uint32_t srcAvatarId, uint32_t destAvatarId, const std::u16string& comment) {
|
||||
sqlite3_stmt* stmt;
|
||||
char sql[] = "UDPATE friend SET comment = @comment WHERE avatar_id = @avatar_id AND "
|
||||
"friend_avatar_id = @friend_avatar_id";
|
||||
|
||||
auto result = sqlite3_prepare_v2(db_, sql, -1, &stmt, 0);
|
||||
if (result != SQLITE_OK) {
|
||||
throw SQLite3Exception{result, sqlite3_errmsg(db_)};
|
||||
}
|
||||
|
||||
int commentIdx = sqlite3_bind_parameter_index(stmt, "@comment");
|
||||
int avatarIdIdx = sqlite3_bind_parameter_index(stmt, "@avatar_id");
|
||||
int friendAvatarIdIdx = sqlite3_bind_parameter_index(stmt, "@friend_avatar_id");
|
||||
|
||||
std::string commentStr = FromWideString(comment);
|
||||
|
||||
sqlite3_bind_text(stmt, commentIdx, commentStr.c_str(), -1, 0);
|
||||
sqlite3_bind_int(stmt, avatarIdIdx, srcAvatarId);
|
||||
sqlite3_bind_int(stmt, friendAvatarIdIdx, destAvatarId);
|
||||
|
||||
result = sqlite3_step(stmt);
|
||||
if (result != SQLITE_DONE) {
|
||||
throw SQLite3Exception{result, sqlite3_errmsg(db_)};
|
||||
}
|
||||
}
|
||||
|
||||
ChatAvatar* ChatAvatarService::GetCachedAvatar(
|
||||
const std::u16string& name, const std::u16string& address) {
|
||||
ChatAvatar* avatar = nullptr;
|
||||
|
||||
// First look for the avatar in the cache
|
||||
auto find_iter = std::find_if(
|
||||
std::begin(avatarCache_), std::end(avatarCache_), [name, address](const auto& avatar) {
|
||||
return avatar->name_.compare(name) == 0 && avatar->address_.compare(address) == 0;
|
||||
});
|
||||
|
||||
if (find_iter != std::end(avatarCache_)) {
|
||||
avatar = find_iter->get();
|
||||
}
|
||||
|
||||
return avatar;
|
||||
}
|
||||
|
||||
ChatAvatar* ChatAvatarService::GetCachedAvatar(uint32_t avatarId) {
|
||||
ChatAvatar* avatar = nullptr;
|
||||
|
||||
// First look for the avatar in the cache
|
||||
auto find_iter = std::find_if(std::begin(avatarCache_), std::end(avatarCache_),
|
||||
[avatarId](const auto& avatar) { return avatar->avatarId_ == avatarId; });
|
||||
|
||||
if (find_iter != std::end(avatarCache_)) {
|
||||
avatar = find_iter->get();
|
||||
}
|
||||
|
||||
return avatar;
|
||||
}
|
||||
|
||||
void ChatAvatarService::RemoveCachedAvatar(uint32_t avatarId) {
|
||||
auto remove_iter = std::remove_if(std::begin(avatarCache_), std::end(avatarCache_),
|
||||
[avatarId](const auto& avatar) { return avatar->avatarId_ == avatarId; });
|
||||
|
||||
if (remove_iter != std::end(avatarCache_)) {
|
||||
avatarCache_.erase(remove_iter);
|
||||
}
|
||||
}
|
||||
|
||||
void ChatAvatarService::RemoveAsFriendOrIgnoreFromAll(const ChatAvatar* avatar) {
|
||||
for (auto& cachedAvatar : avatarCache_) {
|
||||
if (cachedAvatar->IsFriend(avatar)) {
|
||||
cachedAvatar->RemoveFriend(avatar);
|
||||
}
|
||||
|
||||
if (cachedAvatar->IsIgnored(avatar)) {
|
||||
cachedAvatar->RemoveIgnore(avatar);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::unique_ptr<ChatAvatar> ChatAvatarService::LoadStoredAvatar(
|
||||
const std::u16string& name, const std::u16string& address) {
|
||||
std::unique_ptr<ChatAvatar> avatar{nullptr};
|
||||
|
||||
sqlite3_stmt* stmt;
|
||||
|
||||
char sql[] = "SELECT id, user_id, name, address, attributes FROM avatar WHERE name = @name AND "
|
||||
"address = @address";
|
||||
|
||||
auto result = sqlite3_prepare_v2(db_, sql, -1, &stmt, 0);
|
||||
if (result != SQLITE_OK) {
|
||||
throw SQLite3Exception{result, sqlite3_errmsg(db_)};
|
||||
}
|
||||
|
||||
std::string nameStr = FromWideString(name);
|
||||
std::string addressStr = FromWideString(address);
|
||||
|
||||
int nameIdx = sqlite3_bind_parameter_index(stmt, "@name");
|
||||
int addressIdx = sqlite3_bind_parameter_index(stmt, "@address");
|
||||
|
||||
sqlite3_bind_text(stmt, nameIdx, nameStr.c_str(), -1, 0);
|
||||
sqlite3_bind_text(stmt, addressIdx, addressStr.c_str(), -1, 0);
|
||||
|
||||
if (sqlite3_step(stmt) == SQLITE_ROW) {
|
||||
avatar = std::make_unique<ChatAvatar>(this);
|
||||
avatar->avatarId_ = sqlite3_column_int(stmt, 0);
|
||||
avatar->userId_ = sqlite3_column_int(stmt, 1);
|
||||
|
||||
auto tmp = std::string(reinterpret_cast<const char*>(sqlite3_column_text(stmt, 2)));
|
||||
avatar->name_ = std::u16string{std::begin(tmp), std::end(tmp)};
|
||||
|
||||
tmp = std::string(reinterpret_cast<const char*>(sqlite3_column_text(stmt, 3)));
|
||||
avatar->address_ = std::u16string(std::begin(tmp), std::end(tmp));
|
||||
|
||||
avatar->attributes_ = sqlite3_column_int(stmt, 4);
|
||||
}
|
||||
|
||||
sqlite3_finalize(stmt);
|
||||
|
||||
return avatar;
|
||||
}
|
||||
|
||||
std::unique_ptr<ChatAvatar> ChatAvatarService::LoadStoredAvatar(uint32_t avatarId) {
|
||||
std::unique_ptr<ChatAvatar> avatar{nullptr};
|
||||
|
||||
sqlite3_stmt* stmt;
|
||||
|
||||
char sql[] = "SELECT id, user_id, name, address, attributes FROM avatar WHERE id = @avatar_id";
|
||||
|
||||
auto result = sqlite3_prepare_v2(db_, sql, -1, &stmt, 0);
|
||||
if (result != SQLITE_OK) {
|
||||
throw SQLite3Exception{result, sqlite3_errmsg(db_)};
|
||||
}
|
||||
|
||||
int avatarIdIdx = sqlite3_bind_parameter_index(stmt, "@avatar_id");
|
||||
|
||||
sqlite3_bind_int(stmt, avatarIdIdx, avatarId);
|
||||
|
||||
if (sqlite3_step(stmt) == SQLITE_ROW) {
|
||||
avatar = std::make_unique<ChatAvatar>(this);
|
||||
avatar->avatarId_ = sqlite3_column_int(stmt, 0);
|
||||
avatar->userId_ = sqlite3_column_int(stmt, 1);
|
||||
|
||||
auto tmp = std::string(reinterpret_cast<const char*>(sqlite3_column_text(stmt, 2)));
|
||||
avatar->name_ = std::u16string{std::begin(tmp), std::end(tmp)};
|
||||
|
||||
tmp = std::string(reinterpret_cast<const char*>(sqlite3_column_text(stmt, 3)));
|
||||
avatar->address_ = std::u16string(std::begin(tmp), std::end(tmp));
|
||||
|
||||
avatar->attributes_ = sqlite3_column_int(stmt, 4);
|
||||
}
|
||||
|
||||
sqlite3_finalize(stmt);
|
||||
|
||||
return avatar;
|
||||
}
|
||||
|
||||
void ChatAvatarService::InsertAvatar(ChatAvatar* avatar) {
|
||||
CHECK_NOTNULL(avatar);
|
||||
sqlite3_stmt* stmt;
|
||||
|
||||
char sql[] = "INSERT INTO avatar (user_id, name, address, attributes) VALUES (@user_id, @name, "
|
||||
"@address, @attributes)";
|
||||
|
||||
auto result = sqlite3_prepare_v2(db_, sql, -1, &stmt, 0);
|
||||
if (result != SQLITE_OK) {
|
||||
throw SQLite3Exception{result, sqlite3_errmsg(db_)};
|
||||
}
|
||||
|
||||
std::string nameStr = FromWideString(avatar->name_);
|
||||
std::string addressStr = FromWideString(avatar->address_);
|
||||
|
||||
int userIdIdx = sqlite3_bind_parameter_index(stmt, "@user_id");
|
||||
int nameIdx = sqlite3_bind_parameter_index(stmt, "@name");
|
||||
int addressIdx = sqlite3_bind_parameter_index(stmt, "@address");
|
||||
int attributesIdx = sqlite3_bind_parameter_index(stmt, "@attributes");
|
||||
|
||||
sqlite3_bind_int(stmt, userIdIdx, avatar->userId_);
|
||||
sqlite3_bind_text(stmt, nameIdx, nameStr.c_str(), -1, 0);
|
||||
sqlite3_bind_text(stmt, addressIdx, addressStr.c_str(), -1, 0);
|
||||
sqlite3_bind_int(stmt, attributesIdx, avatar->attributes_);
|
||||
|
||||
result = sqlite3_step(stmt);
|
||||
if (result != SQLITE_DONE) {
|
||||
throw SQLite3Exception{result, sqlite3_errmsg(db_)};
|
||||
}
|
||||
|
||||
avatar->avatarId_ = static_cast<uint32_t>(sqlite3_last_insert_rowid(db_));
|
||||
|
||||
sqlite3_finalize(stmt);
|
||||
}
|
||||
|
||||
void ChatAvatarService::UpdateAvatar(const ChatAvatar* avatar) {
|
||||
CHECK_NOTNULL(avatar);
|
||||
sqlite3_stmt* stmt;
|
||||
|
||||
char sql[] = "UPDATE avatar SET user_id = @user_id, name = @name, address = @address, "
|
||||
"attributes = @attributes "
|
||||
"WHERE id = @avatar_id";
|
||||
|
||||
auto result = sqlite3_prepare_v2(db_, sql, -1, &stmt, 0);
|
||||
if (result != SQLITE_OK) {
|
||||
throw SQLite3Exception{result, sqlite3_errmsg(db_)};
|
||||
}
|
||||
|
||||
std::string nameStr = FromWideString(avatar->name_);
|
||||
std::string addressStr = FromWideString(avatar->address_);
|
||||
|
||||
int userIdIdx = sqlite3_bind_parameter_index(stmt, "@user_id");
|
||||
int nameIdx = sqlite3_bind_parameter_index(stmt, "@name");
|
||||
int addressIdx = sqlite3_bind_parameter_index(stmt, "@address");
|
||||
int attributesIdx = sqlite3_bind_parameter_index(stmt, "@attributes");
|
||||
int avatarIdIdx = sqlite3_bind_parameter_index(stmt, "@avatar_id");
|
||||
|
||||
sqlite3_bind_int(stmt, userIdIdx, avatar->userId_);
|
||||
sqlite3_bind_text(stmt, nameIdx, nameStr.c_str(), -1, 0);
|
||||
sqlite3_bind_text(stmt, addressIdx, addressStr.c_str(), -1, 0);
|
||||
sqlite3_bind_int(stmt, attributesIdx, avatar->attributes_);
|
||||
sqlite3_bind_int(stmt, avatarIdIdx, avatar->avatarId_);
|
||||
|
||||
result = sqlite3_step(stmt);
|
||||
if (result != SQLITE_DONE) {
|
||||
throw SQLite3Exception{result, sqlite3_errmsg(db_)};
|
||||
}
|
||||
|
||||
sqlite3_finalize(stmt);
|
||||
}
|
||||
|
||||
void ChatAvatarService::DeleteAvatar(ChatAvatar* avatar) {
|
||||
CHECK_NOTNULL(avatar);
|
||||
sqlite3_stmt* stmt;
|
||||
|
||||
char sql[] = "DELETE FROM avatar WHERE id = @avatar_id";
|
||||
|
||||
auto result = sqlite3_prepare_v2(db_, sql, -1, &stmt, 0);
|
||||
if (result != SQLITE_OK) {
|
||||
throw SQLite3Exception{result, sqlite3_errmsg(db_)};
|
||||
}
|
||||
|
||||
int avatarIdIdx = sqlite3_bind_parameter_index(stmt, "@avatar_id");
|
||||
|
||||
sqlite3_bind_int(stmt, avatarIdIdx, avatar->avatarId_);
|
||||
|
||||
result = sqlite3_step(stmt);
|
||||
if (result != SQLITE_DONE) {
|
||||
throw SQLite3Exception{result, sqlite3_errmsg(db_)};
|
||||
}
|
||||
|
||||
sqlite3_finalize(stmt);
|
||||
}
|
||||
|
||||
void ChatAvatarService::LoadFriendList(ChatAvatar* avatar) {
|
||||
sqlite3_stmt* stmt;
|
||||
|
||||
char sql[] = "SELECT friend_avatar_id, comment FROM friend WHERE avatar_id = @avatar_id";
|
||||
|
||||
auto result = sqlite3_prepare_v2(db_, sql, -1, &stmt, 0);
|
||||
if (result != SQLITE_OK) {
|
||||
throw SQLite3Exception{result, sqlite3_errmsg(db_)};
|
||||
}
|
||||
|
||||
int avatarIdIdx = sqlite3_bind_parameter_index(stmt, "@avatar_id");
|
||||
|
||||
sqlite3_bind_int(stmt, avatarIdIdx, avatar->avatarId_);
|
||||
|
||||
uint32_t tmpFriendId;
|
||||
std::string tmpComment;
|
||||
while (sqlite3_step(stmt) == SQLITE_ROW) {
|
||||
tmpFriendId = sqlite3_column_int(stmt, 0);
|
||||
tmpComment = reinterpret_cast<const char*>(sqlite3_column_text(stmt, 1));
|
||||
|
||||
auto friendAvatar = GetAvatar(tmpFriendId);
|
||||
|
||||
avatar->friendList_.emplace_back(friendAvatar, ToWideString(tmpComment));
|
||||
}
|
||||
}
|
||||
|
||||
void ChatAvatarService::LoadIgnoreList(ChatAvatar* avatar) {
|
||||
sqlite3_stmt* stmt;
|
||||
|
||||
char sql[] = "SELECT ignore_avatar_id FROM ignore WHERE avatar_id = @avatar_id";
|
||||
|
||||
auto result = sqlite3_prepare_v2(db_, sql, -1, &stmt, 0);
|
||||
if (result != SQLITE_OK) {
|
||||
throw SQLite3Exception{result, sqlite3_errmsg(db_)};
|
||||
}
|
||||
|
||||
int avatarIdIdx = sqlite3_bind_parameter_index(stmt, "@avatar_id");
|
||||
|
||||
sqlite3_bind_int(stmt, avatarIdIdx, avatar->avatarId_);
|
||||
|
||||
uint32_t tmpIgnoreId;
|
||||
while (sqlite3_step(stmt) == SQLITE_ROW) {
|
||||
tmpIgnoreId = sqlite3_column_int(stmt, 0);
|
||||
|
||||
auto ignoreAvatar = GetAvatar(tmpIgnoreId);
|
||||
|
||||
avatar->ignoreList_.emplace_back(ignoreAvatar);
|
||||
}
|
||||
}
|
||||
|
||||
bool ChatAvatarService::IsOnline(const ChatAvatar * avatar) const {
|
||||
for (auto onlineAvatar : onlineAvatars_) {
|
||||
if (onlineAvatar->GetAvatarId() == avatar->GetAvatarId()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "ChatAvatar.hpp"
|
||||
#include "ChatEnums.hpp"
|
||||
|
||||
#include <boost/optional.hpp>
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
|
||||
struct sqlite3;
|
||||
|
||||
class ChatAvatarService {
|
||||
public:
|
||||
explicit ChatAvatarService(sqlite3* db);
|
||||
~ChatAvatarService();
|
||||
|
||||
ChatAvatar* GetAvatar(const std::u16string& name, const std::u16string& address);
|
||||
ChatAvatar* GetAvatar(uint32_t avatarId);
|
||||
|
||||
ChatAvatar* CreateAvatar(const std::u16string& name,
|
||||
const std::u16string& address, uint32_t userId, uint32_t loginAttributes,
|
||||
const std::u16string& loginLocation);
|
||||
|
||||
void DestroyAvatar(ChatAvatar* avatar);
|
||||
|
||||
void LoginAvatar(ChatAvatar* avatar);
|
||||
void LogoutAvatar(ChatAvatar* avatar);
|
||||
|
||||
void PersistAvatar(const ChatAvatar* avatar);
|
||||
void PersistFriend(uint32_t srcAvatarId, uint32_t destAvatarId, const std::u16string& comment);
|
||||
void PersistIgnore(uint32_t srcAvatarId, uint32_t destAvatarId);
|
||||
|
||||
void RemoveFriend(uint32_t srcAvatarId, uint32_t destAvatarId);
|
||||
void RemoveIgnore(uint32_t srcAvatarId, uint32_t destAvatarId);
|
||||
|
||||
void UpdateFriendComment(uint32_t srcAvatarId, uint32_t destAvatarId, const std::u16string& comment);
|
||||
|
||||
const std::vector<ChatAvatar*>& GetOnlineAvatars() const { return onlineAvatars_; }
|
||||
|
||||
private:
|
||||
ChatAvatar* GetCachedAvatar(const std::u16string& name, const std::u16string& address);
|
||||
ChatAvatar* GetCachedAvatar(uint32_t avatarId);
|
||||
|
||||
void RemoveCachedAvatar(uint32_t avatarId);
|
||||
void RemoveAsFriendOrIgnoreFromAll(const ChatAvatar* avatar);
|
||||
|
||||
std::unique_ptr<ChatAvatar> LoadStoredAvatar(const std::u16string& name, const std::u16string& address);
|
||||
std::unique_ptr<ChatAvatar> LoadStoredAvatar(uint32_t avatarId);
|
||||
|
||||
void InsertAvatar(ChatAvatar* avatar);
|
||||
void UpdateAvatar(const ChatAvatar* avatar);
|
||||
void DeleteAvatar(ChatAvatar* avatar);
|
||||
|
||||
void LoadFriendList(ChatAvatar* avatar);
|
||||
void LoadIgnoreList(ChatAvatar* avatar);
|
||||
|
||||
bool IsOnline(const ChatAvatar* avatar) const;
|
||||
|
||||
std::vector<std::unique_ptr<ChatAvatar>> avatarCache_;
|
||||
std::vector<ChatAvatar*> onlineAvatars_;
|
||||
sqlite3* db_;
|
||||
};
|
||||
@@ -0,0 +1,154 @@
|
||||
#include "ChatEnums.hpp"
|
||||
|
||||
const char* ToString(ChatResultCode code) {
|
||||
switch (code) {
|
||||
case ChatResultCode::SUCCESS:
|
||||
return "SUCCESS";
|
||||
case ChatResultCode::TIMEOUT:
|
||||
return "TIMEOUT";
|
||||
case ChatResultCode::DUPLICATELOGIN:
|
||||
return "DUPLICATELOGIN";
|
||||
case ChatResultCode::SRCAVATARDOESNTEXIST:
|
||||
return "SRCAVATARDOESNTEXIST";
|
||||
case ChatResultCode::DESTAVATARDOESNTEXIST:
|
||||
return "DESTAVATARDOESNTEXIST";
|
||||
case ChatResultCode::ADDRESSDOESNTEXIST:
|
||||
return "ADDRESSDOESNTEXIST";
|
||||
case ChatResultCode::ADDRESSNOTROOM:
|
||||
return "ADDRESSNOTROOM";
|
||||
case ChatResultCode::ADDRESSNOTAID:
|
||||
return "ADDRESSNOTAID";
|
||||
case ChatResultCode::FRIENDNOTFOUND:
|
||||
return "FRIENDNOTFOUND";
|
||||
case ChatResultCode::ROOM_UNKNOWNFAILURE:
|
||||
return "ROOM_UNKNOWNFAILURE";
|
||||
case ChatResultCode::ROOM_SRCNOTINROOM:
|
||||
return "ROOM_SRCNOTINROOM";
|
||||
case ChatResultCode::ROOM_DESTNOTINROOM:
|
||||
return "ROOM_DESTNOTINROOM";
|
||||
case ChatResultCode::ROOM_BANNEDAVATAR:
|
||||
return "ROOM_BANNEDAVATAR";
|
||||
case ChatResultCode::ROOM_PRIVATEROOM:
|
||||
return "ROOM_PRIVATEROOM";
|
||||
case ChatResultCode::ROOM_MODERATEDROOM:
|
||||
return "ROOM_MODERATEDROOM";
|
||||
case ChatResultCode::ROOM_NOTINROOM:
|
||||
return "ROOM_NOTINROOM";
|
||||
case ChatResultCode::ROOM_NOPRIVILEGES:
|
||||
return "ROOM_NOPRIVILEGES";
|
||||
case ChatResultCode::DATABASE:
|
||||
return "DATABASE";
|
||||
case ChatResultCode::CANNOTGETAVATARID:
|
||||
return "CANNOTGETAVATARID";
|
||||
case ChatResultCode::CANNOTGETNODEID:
|
||||
return "CANNOTGETNODEID";
|
||||
case ChatResultCode::CANNOTGETPMSGID:
|
||||
return "CANNOTGETPMSGID";
|
||||
case ChatResultCode::PMSGNOTFOUND:
|
||||
return "PMSGNOTFOUND";
|
||||
case ChatResultCode::ROOMMAXAVATARSREACHED:
|
||||
return "ROOMMAXAVATARSREACHED";
|
||||
case ChatResultCode::IGNORING:
|
||||
return "IGNORING";
|
||||
case ChatResultCode::ROOM_ALREADYEXISTS:
|
||||
return "ROOM_ALREADYEXISTS";
|
||||
case ChatResultCode::NOTHINGTOCONFIRM:
|
||||
return "NOTHINGTOCONFIRM";
|
||||
case ChatResultCode::DUPLICATEFRIEND:
|
||||
return "DUPLICATEFRIEND";
|
||||
case ChatResultCode::IGNORENOTFOUND:
|
||||
return "IGNORENOTFOUND";
|
||||
case ChatResultCode::DUPLICATEIGNORE:
|
||||
return "DUPLICATEIGNORE";
|
||||
case ChatResultCode::DBFAIL:
|
||||
return "DBFAIL";
|
||||
case ChatResultCode::ROOM_DESTAVATARNOTMODERATOR:
|
||||
return "ROOM_DESTAVATARNOTMODERATOR";
|
||||
case ChatResultCode::ROOM_DESTAVATARNOTINVITED:
|
||||
return "ROOM_DESTAVATARNOTINVITED";
|
||||
case ChatResultCode::ROOM_DESTAVATARNOTBANNED:
|
||||
return "ROOM_DESTAVATARNOTBANNED";
|
||||
case ChatResultCode::ROOM_DUPLICATEBAN:
|
||||
return "ROOM_DUPLICATEBAN";
|
||||
case ChatResultCode::ROOM_DUPLICATEMODERATOR:
|
||||
return "ROOM_DUPLICATEMODERATOR";
|
||||
case ChatResultCode::ROOM_DUPLICATEINVITE:
|
||||
return "ROOM_DUPLICATEINVITE";
|
||||
case ChatResultCode::ROOM_ALREADYINROOM:
|
||||
return "ROOM_ALREADYINROOM";
|
||||
case ChatResultCode::ROOM_PARENTNONPERSISTENT:
|
||||
return "ROOM_PARENTNONPERSISTENT";
|
||||
case ChatResultCode::ROOM_PARENTBADNODETYPE:
|
||||
return "ROOM_PARENTBADNODETYPE";
|
||||
case ChatResultCode::NOFANCLUBHANDLE:
|
||||
return "NOFANCLUBHANDLE";
|
||||
case ChatResultCode::AIDALREADYEXISTS:
|
||||
return "AIDALREADYEXISTS";
|
||||
case ChatResultCode::UIDALREADYEXISTS:
|
||||
return "UIDALREADYEXISTS";
|
||||
case ChatResultCode::WRONGCHATSERVERFORREQUEST:
|
||||
return "WRONGCHATSERVERFORREQUEST";
|
||||
case ChatResultCode::SUCCESSBADDATA:
|
||||
return "SUCCESSBADDATA";
|
||||
case ChatResultCode::NULLNAMELOGIN:
|
||||
return "NULLNAMELOGIN";
|
||||
case ChatResultCode::SERVER_IDENTITY_EMPTY:
|
||||
return "SERVER_IDENTITY_EMPTY";
|
||||
case ChatResultCode::SERVER_IDENTITY_TAKEN:
|
||||
return "SERVER_IDENTITY_TAKEN";
|
||||
case ChatResultCode::REMOTESERVERDOWN:
|
||||
return "REMOTESERVERDOWN";
|
||||
case ChatResultCode::NODEIDCONFLICT:
|
||||
return "NODEIDCONFLICT";
|
||||
case ChatResultCode::INVALIDNODENAME:
|
||||
return "INVALIDNODENAME";
|
||||
case ChatResultCode::INSUFFICIENTGMPRIVS:
|
||||
return "INSUFFICIENTGMPRIVS";
|
||||
case ChatResultCode::SNOOPALREADYADDED:
|
||||
return "SNOOPALREADYADDED";
|
||||
case ChatResultCode::NOTSNOOPING:
|
||||
return "NOTSNOOPING";
|
||||
case ChatResultCode::ROOM_DESTAVATARNOTTEMPORARYMODERATOR:
|
||||
return "ROOM_DESTAVATARNOTTEMPORARYMODERATOR";
|
||||
case ChatResultCode::ROOM_DESTAVATARNOTVOICE:
|
||||
return "ROOM_DESTAVATARNOTVOICE";
|
||||
case ChatResultCode::ROOM_DUPLICATETEMPORARYMODERATOR:
|
||||
return "ROOM_DUPLICATETEMPORARYMODERATOR";
|
||||
case ChatResultCode::ROOM_DUPLICATEVOICE:
|
||||
return "ROOM_DUPLICATEVOICE";
|
||||
case ChatResultCode::AVATARMUSTBELOGGEDOUT:
|
||||
return "AVATARMUSTBELOGGEDOUT";
|
||||
case ChatResultCode::NOTHINGTODO:
|
||||
return "NOTHINGTODO";
|
||||
case ChatResultCode::TRANSFERNAMENULL:
|
||||
return "TRANSFERNAMENULL";
|
||||
case ChatResultCode::TRANSFERUSERIDZERO:
|
||||
return "TRANSFERUSERIDZERO";
|
||||
case ChatResultCode::TRANSFERADDRESSNULL:
|
||||
return "TRANSFERADDRESSNULL";
|
||||
case ChatResultCode::OUTOFIDS:
|
||||
return "OUTOFIDS";
|
||||
case ChatResultCode::ROOM_LOCALROOM:
|
||||
return "ROOM_LOCALROOM";
|
||||
case ChatResultCode::ROOM_GAMEROOM:
|
||||
return "ROOM_GAMEROOM";
|
||||
case ChatResultCode::ROOM_DESTAVATARNOTENTERING:
|
||||
return "ROOM_DESTAVATARNOTENTERING";
|
||||
case ChatResultCode::INSUFFICIENTPRIORITY:
|
||||
return "INSUFFICIENTPRIORITY";
|
||||
case ChatResultCode::ROOM_WAITINGFORENTRY:
|
||||
return "ROOM_WAITINGFORENTRY";
|
||||
case ChatResultCode::INBOXLIMITEXCEEDED:
|
||||
return "INBOXLIMITEXCEEDED";
|
||||
case ChatResultCode::DUPLICATEDESTINATION:
|
||||
return "DUPLICATEDESTINATION";
|
||||
case ChatResultCode::CATEGORYLIMITEXCEEDED:
|
||||
return "CATEGORYLIMITEXCEEDED";
|
||||
case ChatResultCode::MESSAGE_FILTER_FAILURE:
|
||||
return "MESSAGE_FILTER_FAILURE";
|
||||
case ChatResultCode::INVALID_INPUT:
|
||||
return "INVALID_INPUT";
|
||||
};
|
||||
|
||||
return "";
|
||||
}
|
||||
@@ -0,0 +1,252 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
|
||||
enum class ChatRequestType : uint16_t {
|
||||
LOGINAVATAR = 0,
|
||||
LOGOUTAVATAR,
|
||||
DESTROYAVATAR,
|
||||
GETAVATAR,
|
||||
CREATEROOM,
|
||||
DESTROYROOM, // 5
|
||||
SENDINSTANTMESSAGE,
|
||||
SENDROOMMESSAGE,
|
||||
SENDBROADCASTMESSAGE,
|
||||
ADDFRIEND,
|
||||
REMOVEFRIEND, // 10
|
||||
FRIENDSTATUS,
|
||||
ADDIGNORE,
|
||||
REMOVEIGNORE,
|
||||
ENTERROOM,
|
||||
LEAVEROOM, // 15
|
||||
ADDMODERATOR,
|
||||
REMOVEMODERATOR,
|
||||
ADDBAN,
|
||||
REMOVEBAN,
|
||||
ADDINVITE, // 20
|
||||
REMOVEINVITE,
|
||||
KICKAVATAR,
|
||||
SETROOMPARAMS,
|
||||
GETROOM,
|
||||
GETROOMSUMMARIES, // 25
|
||||
SENDPERSISTENTMESSAGE,
|
||||
GETPERSISTENTHEADERS,
|
||||
GETPERSISTENTMESSAGE,
|
||||
UPDATEPERSISTENTMESSAGE,
|
||||
UNREGISTERROOM, // 30
|
||||
IGNORESTATUS,
|
||||
FAILOVER_RELOGINAVATAR,
|
||||
FAILOVER_RECREATEROOM,
|
||||
CONFIRMFRIEND,
|
||||
GETAVATARKEYWORDS, // 35
|
||||
SETAVATARKEYWORDS,
|
||||
SEARCHAVATARKEYWORDS,
|
||||
GETFANCLUBHANDLE,
|
||||
UPDATEPERSISTENTMESSAGES,
|
||||
FINDAVATARBYUID, // 40
|
||||
CHANGEROOMOWNER,
|
||||
SETAPIVERSION,
|
||||
ADDTEMPORARYMODERATOR,
|
||||
REMOVETEMPORARYMODERATOR,
|
||||
GRANTVOICE, // 45
|
||||
REVOKEVOICE,
|
||||
SETAVATARATTRIBUTES,
|
||||
ADDSNOOPAVATAR,
|
||||
REMOVESNOOPAVATAR,
|
||||
ADDSNOOPROOM, // 50
|
||||
REMOVESNOOPROOM,
|
||||
GETSNOOPLIST,
|
||||
PARTIALPERSISTENTHEADERS,
|
||||
COUNTPERSISTENTMESSAGES,
|
||||
PURGEPERSISTENTMESSAGES, // 55
|
||||
SETFRIENDCOMMENT,
|
||||
TRANSFERAVATAR,
|
||||
CHANGEPERSISTENTFOLDER,
|
||||
ALLOWROOMENTRY,
|
||||
SETAVATAREMAIL, // 60
|
||||
SETAVATARINBOXLIMIT,
|
||||
SENDMULTIPLEPERSISTENTMESSAGES,
|
||||
GETMULTIPLEPERSISTENTMESSAGES,
|
||||
ALTERPERISTENTMESSAGE,
|
||||
GETANYAVATAR, // 65
|
||||
TEMPORARYAVATAR,
|
||||
AVATARLIST,
|
||||
SETAVATARSTATUSMESSAGE,
|
||||
CONFIRMFRIEND_RECIPROCATE,
|
||||
ADDFRIEND_RECIPROCATE, // 70
|
||||
REMOVEFRIEND_RECIPROCATE,
|
||||
FILTERMESSAGE,
|
||||
FILTERMESSAGE_EX,
|
||||
REGISTRAR_GETCHATSERVER = 20001,
|
||||
};
|
||||
|
||||
enum class ChatResponseType : uint16_t {
|
||||
LOGINAVATAR = 0,
|
||||
LOGOUTAVATAR,
|
||||
DESTROYAVATAR,
|
||||
GETAVATAR,
|
||||
CREATEROOM,
|
||||
DESTROYROOM,
|
||||
SENDINSTANTMESSAGE,
|
||||
SENDROOMMESSAGE,
|
||||
SENDBROADCASTMESSAGE,
|
||||
ADDFRIEND,
|
||||
REMOVEFRIEND,
|
||||
FRIENDSTATUS,
|
||||
ADDIGNORE,
|
||||
REMOVEIGNORE,
|
||||
ENTERROOM,
|
||||
LEAVEROOM,
|
||||
ADDMODERATOR,
|
||||
REMOVEMODERATOR,
|
||||
ADDBAN,
|
||||
REMOVEBAN,
|
||||
ADDINVITE,
|
||||
REMOVEINVITE,
|
||||
KICKAVATAR,
|
||||
SETROOMPARAMS,
|
||||
GETROOM,
|
||||
GETROOMSUMMARIES,
|
||||
SENDPERSISTENTMESSAGE,
|
||||
GETPERSISTENTHEADERS,
|
||||
GETPERSISTENTMESSAGE,
|
||||
UPDATEPERSISTENTMESSAGE,
|
||||
UNREGISTERROOM,
|
||||
IGNORESTATUS,
|
||||
FAILOVER_RELOGINAVATAR,
|
||||
FAILOVER_RECREATEROOM,
|
||||
CONFIRMFRIEND,
|
||||
GETAVATARKEYWORDS,
|
||||
SETAVATARKEYWORDS,
|
||||
SEARCHAVATARKEYWORDS,
|
||||
GETFANCLUBHANDLE,
|
||||
UPDATEPERSISTENTMESSAGES,
|
||||
FINDAVATARBYUID,
|
||||
CHANGEROOMOWNER,
|
||||
SETAPIVERSION,
|
||||
ADDTEMPORARYMODERATOR,
|
||||
REMOVETEMPORARYMODERATOR,
|
||||
GRANTVOICE,
|
||||
REVOKEVOICE,
|
||||
SETAVATARATTRIBUTES,
|
||||
ADDSNOOPAVATAR,
|
||||
REMOVESNOOPAVATAR,
|
||||
ADDSNOOPROOM,
|
||||
REMOVESNOOPROOM,
|
||||
GETSNOOPLIST,
|
||||
PARTIALPERSISTENTHEADERS,
|
||||
COUNTPERSISTENTMESSAGES,
|
||||
PURGEPERSISTENTMESSAGES,
|
||||
SETFRIENDCOMMENT,
|
||||
TRANSFERAVATAR,
|
||||
CHANGEPERSISTENTFOLDER,
|
||||
ALLOWROOMENTRY,
|
||||
SETAVATAREMAIL,
|
||||
SETAVATARINBOXLIMIT,
|
||||
SENDMULTIPLEPERSISTENTMESSAGES,
|
||||
GETMULTIPLEPERSISTENTMESSAGES,
|
||||
ALTERPERSISTENTMESSAGE,
|
||||
GETANYAVATAR,
|
||||
TEMPORARYAVATAR,
|
||||
AVATARLIST,
|
||||
SETSTATUSMESSAGE,
|
||||
CONFIRMFRIEND_RECIPROCATE,
|
||||
ADDFRIEND_RECIPROCATE,
|
||||
REMOVEFRIEND_RECIPROCATE,
|
||||
FILTERMESSAGE,
|
||||
FILTERMESSAGE_EX,
|
||||
|
||||
REGISTRAR_GETCHATSERVER = 20001,
|
||||
};
|
||||
|
||||
enum class ChatResultCode : uint32_t {
|
||||
SUCCESS = 0,
|
||||
TIMEOUT = 1,
|
||||
DUPLICATELOGIN,
|
||||
SRCAVATARDOESNTEXIST,
|
||||
DESTAVATARDOESNTEXIST,
|
||||
ADDRESSDOESNTEXIST, // 5
|
||||
ADDRESSNOTROOM,
|
||||
ADDRESSNOTAID,
|
||||
FRIENDNOTFOUND,
|
||||
ROOM_UNKNOWNFAILURE,
|
||||
ROOM_SRCNOTINROOM, // 10
|
||||
ROOM_DESTNOTINROOM,
|
||||
ROOM_BANNEDAVATAR,
|
||||
ROOM_PRIVATEROOM,
|
||||
ROOM_MODERATEDROOM,
|
||||
ROOM_NOTINROOM, // 15
|
||||
ROOM_NOPRIVILEGES,
|
||||
DATABASE,
|
||||
CANNOTGETAVATARID,
|
||||
CANNOTGETNODEID,
|
||||
CANNOTGETPMSGID, // 20
|
||||
PMSGNOTFOUND,
|
||||
ROOMMAXAVATARSREACHED,
|
||||
IGNORING,
|
||||
ROOM_ALREADYEXISTS,
|
||||
NOTHINGTOCONFIRM, // 25
|
||||
DUPLICATEFRIEND,
|
||||
IGNORENOTFOUND,
|
||||
DUPLICATEIGNORE,
|
||||
DBFAIL,
|
||||
ROOM_DESTAVATARNOTMODERATOR, // 30
|
||||
ROOM_DESTAVATARNOTINVITED,
|
||||
ROOM_DESTAVATARNOTBANNED,
|
||||
ROOM_DUPLICATEBAN,
|
||||
ROOM_DUPLICATEMODERATOR,
|
||||
ROOM_DUPLICATEINVITE, // 35
|
||||
ROOM_ALREADYINROOM,
|
||||
ROOM_PARENTNONPERSISTENT,
|
||||
ROOM_PARENTBADNODETYPE,
|
||||
NOFANCLUBHANDLE,
|
||||
AIDALREADYEXISTS, // 40
|
||||
UIDALREADYEXISTS,
|
||||
WRONGCHATSERVERFORREQUEST,
|
||||
SUCCESSBADDATA,
|
||||
NULLNAMELOGIN,
|
||||
SERVER_IDENTITY_EMPTY, // 45
|
||||
SERVER_IDENTITY_TAKEN,
|
||||
REMOTESERVERDOWN,
|
||||
NODEIDCONFLICT,
|
||||
INVALIDNODENAME,
|
||||
INSUFFICIENTGMPRIVS, // 50
|
||||
SNOOPALREADYADDED,
|
||||
NOTSNOOPING,
|
||||
ROOM_DESTAVATARNOTTEMPORARYMODERATOR,
|
||||
ROOM_DESTAVATARNOTVOICE,
|
||||
ROOM_DUPLICATETEMPORARYMODERATOR, // 55
|
||||
ROOM_DUPLICATEVOICE,
|
||||
AVATARMUSTBELOGGEDOUT,
|
||||
NOTHINGTODO,
|
||||
TRANSFERNAMENULL,
|
||||
TRANSFERUSERIDZERO, // 60
|
||||
TRANSFERADDRESSNULL,
|
||||
OUTOFIDS,
|
||||
ROOM_LOCALROOM,
|
||||
ROOM_GAMEROOM,
|
||||
ROOM_DESTAVATARNOTENTERING, // 65
|
||||
INSUFFICIENTPRIORITY,
|
||||
ROOM_WAITINGFORENTRY,
|
||||
INBOXLIMITEXCEEDED,
|
||||
DUPLICATEDESTINATION,
|
||||
CATEGORYLIMITEXCEEDED, // 70
|
||||
MESSAGE_FILTER_FAILURE,
|
||||
INVALID_INPUT,
|
||||
};
|
||||
|
||||
struct ChatResultException {
|
||||
ChatResultCode code;
|
||||
std::string message;
|
||||
|
||||
explicit ChatResultException(const ChatResultCode result)
|
||||
: code{result} {}
|
||||
|
||||
ChatResultException(const ChatResultCode result, char const * text)
|
||||
: code{result}
|
||||
, message{text} {}
|
||||
};
|
||||
|
||||
const char* ToString(ChatResultCode code);
|
||||
@@ -0,0 +1,307 @@
|
||||
|
||||
#include "ChatRoom.hpp"
|
||||
#include "ChatAvatar.hpp"
|
||||
#include "ChatRoomService.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
inline unsigned IS_SET(unsigned var, unsigned bit) { return (var & bit); }
|
||||
|
||||
ChatRoom::ChatRoom(ChatRoomService* roomService, uint32_t roomId, const ChatAvatar* creator,
|
||||
const std::u16string& roomName, const std::u16string& roomTopic, const std::u16string& roomPassword,
|
||||
uint32_t roomAttributes, uint32_t maxRoomSize, const std::u16string& roomAddress,
|
||||
const std::u16string& srcAddress)
|
||||
: roomService_{roomService}
|
||||
, roomId_{roomId}
|
||||
, creatorName_{creator->GetName()}
|
||||
, creatorAddress_{creator->GetAddress()}
|
||||
, roomName_{roomName}
|
||||
, roomTopic_{roomTopic}
|
||||
, roomPassword_{roomPassword}
|
||||
, roomAddress_{roomAddress + u"+" + roomName}
|
||||
, creatorId_{creator->GetAvatarId()}
|
||||
, roomAttributes_{roomAttributes}
|
||||
, maxRoomSize_{maxRoomSize} {
|
||||
administrators_.push_back(creator);
|
||||
moderators_.push_back(creator);
|
||||
}
|
||||
|
||||
bool ChatRoom::IsPrivate() const {
|
||||
return (roomAttributes_ & static_cast<uint32_t>(RoomAttributes::PRIVATE)) != 0;
|
||||
}
|
||||
|
||||
bool ChatRoom::IsModerated() const {
|
||||
return (roomAttributes_ & static_cast<uint32_t>(RoomAttributes::MODERATED)) != 0;
|
||||
}
|
||||
|
||||
bool ChatRoom::IsPersistent() const {
|
||||
return (roomAttributes_ & static_cast<uint32_t>(RoomAttributes::PERSISTENT)) != 0;
|
||||
}
|
||||
|
||||
bool ChatRoom::IsLocalWorld() const {
|
||||
return (roomAttributes_ & static_cast<uint32_t>(RoomAttributes::LOCAL_WORLD)) != 0;
|
||||
}
|
||||
|
||||
bool ChatRoom::IsLocalGame() const {
|
||||
return (roomAttributes_ & static_cast<uint32_t>(RoomAttributes::LOCAL_GAME)) != 0;
|
||||
}
|
||||
|
||||
void ChatRoom::EnterRoom(ChatAvatar* avatar, const std::u16string& password) {
|
||||
if (roomPassword_.length() > 0 && roomPassword_.compare(password) != 0) {
|
||||
throw ChatResultException{ChatResultCode::ROOM_PRIVATEROOM};
|
||||
}
|
||||
|
||||
if (IsBanned(avatar->GetAvatarId())) {
|
||||
throw ChatResultException{ChatResultCode::ROOM_BANNEDAVATAR};
|
||||
}
|
||||
|
||||
if (IsInRoom(avatar)) {
|
||||
throw ChatResultException{ChatResultCode::ROOM_ALREADYINROOM};
|
||||
}
|
||||
|
||||
if (IsPrivate() && !IsCreator(avatar->GetAvatarId()) && !IsInvited(avatar->GetAvatarId())) {
|
||||
throw ChatResultException{ChatResultCode::ROOM_PRIVATEROOM};
|
||||
}
|
||||
|
||||
avatars_.push_back(avatar);
|
||||
}
|
||||
|
||||
bool ChatRoom::IsInRoom(ChatAvatar* avatar) const { return IsInRoom(avatar->GetAvatarId()); }
|
||||
|
||||
bool ChatRoom::IsInRoom(uint32_t avatarId) const {
|
||||
return std::find_if(std::begin(avatars_), std::end(avatars_),
|
||||
[avatarId](ChatAvatar* roomAvatar) { return roomAvatar->GetAvatarId() == avatarId; })
|
||||
!= std::end(avatars_);
|
||||
}
|
||||
|
||||
void ChatRoom::LeaveRoom(ChatAvatar* avatar) {
|
||||
auto avatarsIter = std::remove_if(std::begin(avatars_), std::end(avatars_),
|
||||
[avatar](auto roomAvatar) { return roomAvatar->GetAvatarId() == avatar->GetAvatarId(); });
|
||||
|
||||
if (avatarsIter != std::end(avatars_)) {
|
||||
avatars_.erase(avatarsIter);
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<uint32_t> ChatRoom::GetAvatarIds(const ChatAvatar * srcAvatar) const {
|
||||
std::vector<uint32_t> avatarIds;
|
||||
|
||||
for (auto roomAvatar : avatars_) {
|
||||
if (!roomAvatar->IsIgnored(srcAvatar)) {
|
||||
avatarIds.push_back(roomAvatar->GetAvatarId());
|
||||
}
|
||||
}
|
||||
|
||||
return avatarIds;
|
||||
}
|
||||
|
||||
std::vector<std::u16string> ChatRoom::GetConnectedAddresses() const {
|
||||
std::vector<std::u16string> connectedAddresses;
|
||||
|
||||
std::u16string address;
|
||||
for (auto avatar : avatars_) {
|
||||
address = avatar->GetAddress();
|
||||
if (connectedAddresses.empty()
|
||||
|| std::none_of(std::begin(connectedAddresses), std::end(connectedAddresses),
|
||||
[&address](const auto& connectedAddress) {
|
||||
return connectedAddress.compare(address) == 0;
|
||||
})) {
|
||||
connectedAddresses.push_back(address);
|
||||
}
|
||||
}
|
||||
|
||||
return connectedAddresses;
|
||||
}
|
||||
|
||||
std::vector<std::u16string> ChatRoom::GetRemoteAddresses() const {
|
||||
std::vector<std::u16string> connectedAddresses;
|
||||
|
||||
std::u16string address;
|
||||
for (auto avatar : avatars_) {
|
||||
address = avatar->GetAddress();
|
||||
if (creatorAddress_.compare(address) != 0 && (connectedAddresses.empty()
|
||||
|| std::none_of(std::begin(connectedAddresses), std::end(connectedAddresses),
|
||||
[&address](const auto& connectedAddress) {
|
||||
return connectedAddress.compare(address) == 0;
|
||||
}))) {
|
||||
connectedAddresses.push_back(address);
|
||||
}
|
||||
}
|
||||
|
||||
return connectedAddresses;
|
||||
}
|
||||
|
||||
bool ChatRoom::IsCreator(uint32_t avatarId) const { return avatarId == creatorId_; }
|
||||
|
||||
bool ChatRoom::IsModerator(uint32_t avatarId) const {
|
||||
if (moderators_.empty())
|
||||
return false;
|
||||
|
||||
auto find_iter = std::find_if(std::begin(moderators_), std::end(moderators_),
|
||||
[avatarId](const auto& moderator) { return moderator->GetAvatarId() == avatarId; });
|
||||
|
||||
return find_iter != std::end(moderators_);
|
||||
}
|
||||
|
||||
bool ChatRoom::IsAdministrator(uint32_t avatarId) const {
|
||||
if (administrators_.empty())
|
||||
return false;
|
||||
|
||||
auto find_iter = std::find_if(std::begin(administrators_), std::end(administrators_),
|
||||
[avatarId](const auto& administrator) { return administrator->GetAvatarId() == avatarId; });
|
||||
|
||||
return find_iter != std::end(administrators_);
|
||||
}
|
||||
|
||||
bool ChatRoom::IsBanned(uint32_t avatarId) const {
|
||||
if (banned_.empty())
|
||||
return false;
|
||||
|
||||
auto find_iter = std::find_if(std::begin(banned_), std::end(banned_),
|
||||
[avatarId](const auto& banned) { return banned->GetAvatarId() == avatarId; });
|
||||
|
||||
return find_iter != std::end(banned_);
|
||||
}
|
||||
|
||||
bool ChatRoom::IsInvited(uint32_t avatarId) const {
|
||||
if (invited_.empty())
|
||||
return false;
|
||||
|
||||
auto find_iter = std::find_if(std::begin(invited_), std::end(invited_),
|
||||
[avatarId](const auto& invited) { return invited->GetAvatarId() == avatarId; });
|
||||
|
||||
return find_iter != std::end(invited_);
|
||||
}
|
||||
|
||||
void ChatRoom::KickAvatar(uint32_t srcAvatarId, ChatAvatar* destAvatar) {
|
||||
if (!IsModerator(srcAvatarId)) {
|
||||
throw ChatResultException{ChatResultCode::ROOM_NOPRIVILEGES};
|
||||
}
|
||||
|
||||
if (!IsInRoom(destAvatar)) {
|
||||
throw ChatResultException{ChatResultCode::ROOM_NOTINROOM};
|
||||
}
|
||||
|
||||
LeaveRoom(destAvatar);
|
||||
}
|
||||
|
||||
void ChatRoom::AddAdministrator(uint32_t srcAvatarId, ChatAvatar* administrator) {
|
||||
if (!IsCreator(srcAvatarId)) {
|
||||
throw ChatResultException{ChatResultCode::ROOM_NOPRIVILEGES};
|
||||
}
|
||||
|
||||
if (!IsAdministrator(administrator->GetAvatarId())) {
|
||||
administrators_.push_back(administrator);
|
||||
|
||||
if (IsPersistent()) {
|
||||
roomService_->PersistBanned(administrator->GetAvatarId(), roomId_);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ChatRoom::AddModerator(uint32_t srcAvatarId, ChatAvatar* moderator) {
|
||||
if (!IsCreator(srcAvatarId)) {
|
||||
throw ChatResultException{ChatResultCode::ROOM_NOPRIVILEGES};
|
||||
}
|
||||
|
||||
if (IsModerator(moderator->GetAvatarId())) {
|
||||
throw ChatResultException{ChatResultCode::ROOM_DUPLICATEMODERATOR};
|
||||
}
|
||||
|
||||
moderators_.push_back(moderator);
|
||||
|
||||
if (IsPersistent()) {
|
||||
roomService_->PersistBanned(moderator->GetAvatarId(), roomId_);
|
||||
}
|
||||
}
|
||||
|
||||
void ChatRoom::AddBanned(uint32_t srcAvatarId, ChatAvatar* banned) {
|
||||
if (!IsModerator(srcAvatarId)) {
|
||||
throw ChatResultException{ChatResultCode::ROOM_NOPRIVILEGES};
|
||||
}
|
||||
|
||||
if (IsBanned(banned->GetAvatarId())) {
|
||||
throw ChatResultException{ChatResultCode::ROOM_DUPLICATEBAN};
|
||||
}
|
||||
|
||||
banned_.push_back(banned);
|
||||
|
||||
if (IsPersistent()) {
|
||||
roomService_->PersistBanned(banned->GetAvatarId(), roomId_);
|
||||
}
|
||||
}
|
||||
|
||||
void ChatRoom::AddInvite(uint32_t srcAvatarId, ChatAvatar* invited) {
|
||||
if (!IsModerator(srcAvatarId)) {
|
||||
throw ChatResultException{ChatResultCode::ROOM_NOPRIVILEGES};
|
||||
}
|
||||
|
||||
if (IsInvited(invited->GetAvatarId())) {
|
||||
throw ChatResultException{ChatResultCode::ROOM_DUPLICATEINVITE};
|
||||
}
|
||||
|
||||
invited_.push_back(invited);
|
||||
}
|
||||
|
||||
void ChatRoom::RemoveAdministrator(uint32_t srcAvatarId, uint32_t avatarId) {
|
||||
if (!IsCreator(srcAvatarId)) {
|
||||
throw ChatResultException{ChatResultCode::ROOM_NOPRIVILEGES};
|
||||
}
|
||||
|
||||
if (administrators_.empty())
|
||||
return;
|
||||
|
||||
administrators_.erase(std::remove_if(std::begin(administrators_), std::end(administrators_),
|
||||
[avatarId](auto administrator) { return administrator->GetAvatarId() == avatarId; }));
|
||||
|
||||
if (IsPersistent()) {
|
||||
roomService_->DeleteAdministrator(avatarId, roomId_);
|
||||
}
|
||||
}
|
||||
|
||||
void ChatRoom::RemoveModerator(uint32_t srcAvatarId, uint32_t avatarId) {
|
||||
if (!IsCreator(srcAvatarId)) {
|
||||
throw ChatResultException{ChatResultCode::ROOM_NOPRIVILEGES};
|
||||
}
|
||||
|
||||
if (moderators_.empty() || !IsModerator(avatarId)) {
|
||||
throw ChatResultException{ChatResultCode::ROOM_DESTAVATARNOTMODERATOR};
|
||||
}
|
||||
|
||||
moderators_.erase(std::remove_if(std::begin(moderators_), std::end(moderators_),
|
||||
[avatarId](auto moderator) { return moderator->GetAvatarId() == avatarId; }));
|
||||
|
||||
if (IsPersistent()) {
|
||||
roomService_->DeleteModerator(avatarId, roomId_);
|
||||
}
|
||||
}
|
||||
|
||||
void ChatRoom::RemoveBanned(uint32_t srcAvatarId, uint32_t avatarId) {
|
||||
if (!IsModerator(srcAvatarId)) {
|
||||
throw ChatResultException{ChatResultCode::ROOM_NOPRIVILEGES};
|
||||
}
|
||||
|
||||
if (banned_.empty() || !IsBanned(avatarId)) {
|
||||
throw ChatResultException{ChatResultCode::ROOM_DESTAVATARNOTBANNED};
|
||||
}
|
||||
|
||||
banned_.erase(std::remove_if(std::begin(banned_), std::end(banned_),
|
||||
[avatarId](auto banned) { return banned->GetAvatarId() == avatarId; }));
|
||||
|
||||
if (IsPersistent()) {
|
||||
roomService_->DeleteBanned(avatarId, roomId_);
|
||||
}
|
||||
}
|
||||
|
||||
void ChatRoom::RemoveInvite(uint32_t srcAvatarId, uint32_t avatarId) {
|
||||
if (!IsModerator(srcAvatarId)) {
|
||||
throw ChatResultException{ChatResultCode::ROOM_NOPRIVILEGES};
|
||||
}
|
||||
|
||||
if (invited_.empty() || !IsInvited(avatarId)) {
|
||||
throw ChatResultException{ChatResultCode::ROOM_DESTAVATARNOTINVITED};
|
||||
}
|
||||
|
||||
invited_.erase(std::remove_if(std::begin(invited_), std::end(invited_),
|
||||
[avatarId](auto invited) { return invited->GetAvatarId() == avatarId; }));
|
||||
}
|
||||
@@ -0,0 +1,170 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "ChatEnums.hpp"
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
class ChatAvatar;
|
||||
class ChatRoomService;
|
||||
|
||||
enum class RoomAttributes : uint32_t {
|
||||
PRIVATE = 1 << 0,
|
||||
MODERATED = 1 << 1,
|
||||
PERSISTENT = 1 << 2,
|
||||
LOCAL_WORLD = 1 << 4,
|
||||
LOCAL_GAME = 1 << 5
|
||||
};
|
||||
|
||||
class ChatRoom {
|
||||
public:
|
||||
ChatRoom() = default;
|
||||
ChatRoom(ChatRoomService* roomService, uint32_t roomId, const ChatAvatar* creator,
|
||||
const std::u16string& roomName, const std::u16string& roomTopic, const std::u16string& roomPassword,
|
||||
uint32_t roomAttributes, uint32_t maxRoomSize, const std::u16string& roomAddress,
|
||||
const std::u16string& srcAddress);
|
||||
|
||||
bool IsPrivate() const;
|
||||
bool IsModerated() const;
|
||||
bool IsPersistent() const;
|
||||
bool IsLocalWorld() const;
|
||||
bool IsLocalGame() const;
|
||||
|
||||
void EnterRoom(ChatAvatar* avatar, const std::u16string& password);
|
||||
bool IsInRoom(ChatAvatar* avatar) const;
|
||||
bool IsInRoom(uint32_t avatarId) const;
|
||||
void LeaveRoom(ChatAvatar* avatar);
|
||||
|
||||
uint32_t GetCreatorId() const { return creatorId_; }
|
||||
const std::u16string& GetCreatorName() const { return creatorName_; }
|
||||
const std::u16string& GetCreatorAddress() const { return creatorAddress_; }
|
||||
const std::u16string& GetRoomName() const { return roomName_; }
|
||||
const std::u16string& GetRoomAddress() const { return roomAddress_; }
|
||||
const std::u16string& GetRoomTopic() const { return roomTopic_; }
|
||||
const std::u16string& GetRoomPassword() const { return roomPassword_; }
|
||||
const std::u16string& GetRoomPrefix() const { return roomPrefix_; }
|
||||
uint32_t GetRoomAttributes() const { return roomAttributes_; }
|
||||
uint32_t GetCurrentRoomSize() const { return avatars_.size(); }
|
||||
uint32_t GetMaxRoomSize() const { return maxRoomSize_; }
|
||||
uint32_t GetRoomId() const { return roomId_; }
|
||||
uint32_t GetCreateTime() const { return createTime_; }
|
||||
uint32_t GetNodeLevel() const { return nodeLevel_; }
|
||||
|
||||
const std::vector<ChatAvatar*> GetAvatars() const { return avatars_; }
|
||||
/** Returns a list of id's in the room that are not ignoring the srcAvatar.
|
||||
*/
|
||||
std::vector<uint32_t> GetAvatarIds(const ChatAvatar* srcAvatar) const;
|
||||
const std::vector<const ChatAvatar*> GetAdminstrators() const { return administrators_; }
|
||||
const std::vector<const ChatAvatar*> GetModerators() const { return moderators_; }
|
||||
const std::vector<const ChatAvatar*> GetTempModerators() const { return tempModerators_; }
|
||||
const std::vector<const ChatAvatar*> GetBanned() const { return banned_; }
|
||||
const std::vector<const ChatAvatar*> GetInvited() const { return invited_; }
|
||||
const std::vector<const ChatAvatar*> GetVoice() const { return voice_; }
|
||||
|
||||
/* Returns the addresses of the different game servers currently with avatars
|
||||
* connected to this room.
|
||||
*/
|
||||
std::vector<std::u16string> GetConnectedAddresses() const;
|
||||
std::vector<std::u16string> GetRemoteAddresses() const;
|
||||
|
||||
bool IsCreator(uint32_t avatarId) const;
|
||||
bool IsModerator(uint32_t avatarId) const;
|
||||
bool IsAdministrator(uint32_t avatarId) const;
|
||||
bool IsBanned(uint32_t avatarId) const;
|
||||
bool IsInvited(uint32_t avatarId) const;
|
||||
|
||||
void KickAvatar(uint32_t srcAvatarId, ChatAvatar* destAvatar);
|
||||
|
||||
void AddAdministrator(uint32_t srcAvatarId, ChatAvatar* administrator);
|
||||
void AddModerator(uint32_t srcAvatarId, ChatAvatar* moderator);
|
||||
void AddBanned(uint32_t srcAvatarId, ChatAvatar* banned);
|
||||
void AddInvite(uint32_t srcAvatarId, ChatAvatar* invited);
|
||||
|
||||
void RemoveAdministrator(uint32_t srcAvatarId, uint32_t avatarId);
|
||||
void RemoveModerator(uint32_t srcAvatarId, uint32_t avatarId);
|
||||
void RemoveBanned(uint32_t srcAvatarId, uint32_t avatarId);
|
||||
void RemoveInvite(uint32_t srcAvatarId, uint32_t avatarId);
|
||||
|
||||
uint32_t GetNextMessageId() { return roomMessageId_++; }
|
||||
|
||||
private:
|
||||
friend class ChatRoomService;
|
||||
ChatRoomService* roomService_;
|
||||
std::u16string creatorName_;
|
||||
std::u16string creatorAddress_;
|
||||
std::u16string roomName_;
|
||||
std::u16string roomTopic_;
|
||||
std::u16string roomPassword_;
|
||||
std::u16string roomPrefix_ = u"";
|
||||
std::u16string roomAddress_;
|
||||
|
||||
uint32_t creatorId_;
|
||||
uint32_t roomAttributes_;
|
||||
uint32_t maxRoomSize_;
|
||||
uint32_t roomId_ = 0;
|
||||
uint32_t createTime_ = 0;
|
||||
uint32_t nodeLevel_ = 0;
|
||||
uint32_t roomMessageId_ = 1;
|
||||
int32_t dbId_ = -1;
|
||||
|
||||
std::vector<ChatAvatar*> avatars_;
|
||||
std::vector<const ChatAvatar*> administrators_;
|
||||
std::vector<const ChatAvatar*> moderators_;
|
||||
std::vector<const ChatAvatar*> tempModerators_;
|
||||
std::vector<const ChatAvatar*> banned_;
|
||||
std::vector<const ChatAvatar*> invited_;
|
||||
std::vector<const ChatAvatar*> voice_;
|
||||
};
|
||||
|
||||
template <typename StreamT>
|
||||
void write(StreamT& ar, const ChatRoom& data) {
|
||||
write(ar, data.GetCreatorName());
|
||||
write(ar, data.GetCreatorAddress());
|
||||
write(ar, data.GetCreatorId());
|
||||
write(ar, data.GetRoomName());
|
||||
write(ar, data.GetRoomTopic());
|
||||
write(ar, data.GetRoomPrefix());
|
||||
write(ar, data.GetRoomAddress());
|
||||
write(ar, data.GetRoomPassword());
|
||||
write(ar, data.GetRoomAttributes());
|
||||
write(ar, data.GetMaxRoomSize());
|
||||
write(ar, data.GetRoomId());
|
||||
write(ar, data.GetCreateTime());
|
||||
write(ar, data.GetNodeLevel());
|
||||
|
||||
auto& avatars = data.GetAvatars();
|
||||
write(ar, static_cast<uint32_t>(avatars.size()));
|
||||
for (auto& avatar : avatars)
|
||||
write(ar, avatar);
|
||||
|
||||
auto& administrators = data.GetAdminstrators();
|
||||
write(ar, static_cast<uint32_t>(administrators.size()));
|
||||
for (auto& avatar : administrators)
|
||||
write(ar, avatar);
|
||||
|
||||
auto& moderators = data.GetModerators();
|
||||
write(ar, static_cast<uint32_t>(moderators.size()));
|
||||
for (auto& avatar : moderators)
|
||||
write(ar, avatar);
|
||||
|
||||
auto& tempModerators = data.GetTempModerators();
|
||||
write(ar, static_cast<uint32_t>(tempModerators.size()));
|
||||
for (auto& avatar : tempModerators)
|
||||
write(ar, avatar);
|
||||
|
||||
auto& banned = data.GetBanned();
|
||||
write(ar, static_cast<uint32_t>(banned.size()));
|
||||
for (auto& avatar : banned)
|
||||
write(ar, avatar);
|
||||
|
||||
auto& invited = data.GetInvited();
|
||||
write(ar, static_cast<uint32_t>(invited.size()));
|
||||
for (auto& avatar : invited)
|
||||
write(ar, avatar);
|
||||
|
||||
auto& voice = data.GetVoice();
|
||||
write(ar, static_cast<uint32_t>(voice.size()));
|
||||
for (auto& avatar : voice)
|
||||
write(ar, avatar);
|
||||
}
|
||||
@@ -0,0 +1,419 @@
|
||||
#include "ChatRoomService.hpp"
|
||||
#include "ChatAvatarService.hpp"
|
||||
#include "SQLite3.hpp"
|
||||
#include "StreamUtils.hpp"
|
||||
#include "StringUtils.hpp"
|
||||
|
||||
#include "easylogging++.h"
|
||||
|
||||
ChatRoomService::ChatRoomService(ChatAvatarService* avatarService, sqlite3* db)
|
||||
: avatarService_{avatarService}
|
||||
, db_{db} {}
|
||||
|
||||
ChatRoomService::~ChatRoomService() {}
|
||||
|
||||
void ChatRoomService::LoadRoomsFromStorage(const std::u16string& baseAddress) {
|
||||
rooms_.clear();
|
||||
|
||||
sqlite3_stmt* stmt;
|
||||
|
||||
char sql[] = "SELECT id, creator_id, creator_name, creator_address, room_name, room_topic, "
|
||||
"room_password, room_prefix, room_address, room_attributes, room_max_size, "
|
||||
"room_message_id, created_at, node_level FROM room WHERE room_address LIKE @baseAddress||'%'";
|
||||
|
||||
if (sqlite3_prepare_v2(db_, sql, -1, &stmt, 0) != SQLITE_OK) {
|
||||
throw std::runtime_error("Error preparing SQL statement");
|
||||
}
|
||||
|
||||
int baseAddressIdx = sqlite3_bind_parameter_index(stmt, "@baseAddress");
|
||||
|
||||
auto baseAddressStr = FromWideString(baseAddress);
|
||||
LOG(INFO) << "Loading rooms for base address: " << baseAddressStr;
|
||||
sqlite3_bind_text(stmt, baseAddressIdx, baseAddressStr.c_str(), -1, 0);
|
||||
|
||||
while (sqlite3_step(stmt) == SQLITE_ROW) {
|
||||
auto room = std::make_unique<ChatRoom>();
|
||||
std::string tmp;
|
||||
room->roomId_ = nextRoomId_++;
|
||||
room->dbId_ = sqlite3_column_int(stmt, 0);
|
||||
room->creatorId_ = sqlite3_column_int(stmt, 1);
|
||||
|
||||
tmp = std::string(reinterpret_cast<const char*>(sqlite3_column_text(stmt, 2)));
|
||||
room->creatorName_ = std::u16string{std::begin(tmp), std::end(tmp)};
|
||||
|
||||
tmp = std::string(reinterpret_cast<const char*>(sqlite3_column_text(stmt, 3)));
|
||||
room->creatorAddress_ = std::u16string{std::begin(tmp), std::end(tmp)};
|
||||
|
||||
tmp = std::string(reinterpret_cast<const char*>(sqlite3_column_text(stmt, 4)));
|
||||
room->roomName_ = std::u16string{std::begin(tmp), std::end(tmp)};
|
||||
|
||||
tmp = std::string(reinterpret_cast<const char*>(sqlite3_column_text(stmt, 5)));
|
||||
room->roomTopic_ = std::u16string{std::begin(tmp), std::end(tmp)};
|
||||
|
||||
tmp = std::string(reinterpret_cast<const char*>(sqlite3_column_text(stmt, 6)));
|
||||
room->roomPassword_ = std::u16string{std::begin(tmp), std::end(tmp)};
|
||||
|
||||
tmp = std::string(reinterpret_cast<const char*>(sqlite3_column_text(stmt, 7)));
|
||||
room->roomPrefix_ = std::u16string{std::begin(tmp), std::end(tmp)};
|
||||
|
||||
tmp = std::string(reinterpret_cast<const char*>(sqlite3_column_text(stmt, 8)));
|
||||
room->roomAddress_ = std::u16string{std::begin(tmp), std::end(tmp)};
|
||||
|
||||
room->roomAttributes_ = sqlite3_column_int(stmt, 9);
|
||||
room->maxRoomSize_ = sqlite3_column_int(stmt, 10);
|
||||
room->roomMessageId_ = sqlite3_column_int(stmt, 11);
|
||||
room->createTime_ = sqlite3_column_int(stmt, 12);
|
||||
room->nodeLevel_ = sqlite3_column_int(stmt, 13);
|
||||
|
||||
if (!RoomExists(room->GetRoomAddress())) {
|
||||
rooms_.emplace_back(std::move(room));
|
||||
}
|
||||
}
|
||||
|
||||
LOG(INFO) << "Rooms currently loaded: " << rooms_.size();
|
||||
}
|
||||
|
||||
ChatRoom* ChatRoomService::CreateRoom(const ChatAvatar* creator,
|
||||
const std::u16string& roomName, const std::u16string& roomTopic, const std::u16string& roomPassword,
|
||||
uint32_t roomAttributes, uint32_t maxRoomSize, const std::u16string& roomAddress,
|
||||
const std::u16string& srcAddress) {
|
||||
ChatRoom* roomPtr = nullptr;
|
||||
|
||||
if (RoomExists(roomAddress + u"+" + roomName)) {
|
||||
throw ChatResultException(ChatResultCode::ROOM_ALREADYEXISTS, "ChatRoom already exists");
|
||||
}
|
||||
|
||||
LOG(INFO) << "Creating room " << FromWideString(roomName) << "@" << FromWideString(roomAddress) << " with attributes "
|
||||
<< roomAttributes;
|
||||
|
||||
rooms_.emplace_back(std::make_unique<ChatRoom>(this, nextRoomId_++, creator, roomName,
|
||||
roomTopic, roomPassword, roomAttributes, maxRoomSize, roomAddress, srcAddress));
|
||||
roomPtr = rooms_.back().get();
|
||||
|
||||
if (roomPtr->IsPersistent()) {
|
||||
PersistNewRoom(*roomPtr);
|
||||
}
|
||||
|
||||
return roomPtr;
|
||||
}
|
||||
|
||||
void ChatRoomService::DestroyRoom(ChatRoom* room) {
|
||||
if (room->IsPersistent()) {
|
||||
DeleteRoom(room);
|
||||
}
|
||||
|
||||
rooms_.erase(std::remove_if(std::begin(rooms_), std::end(rooms_),
|
||||
[room](const auto& trackedRoom) { return trackedRoom->GetRoomId() == room->GetRoomId(); }));
|
||||
}
|
||||
|
||||
ChatResultCode ChatRoomService::PersistNewRoom(ChatRoom& room) {
|
||||
ChatResultCode result = ChatResultCode::SUCCESS;
|
||||
sqlite3_stmt* stmt;
|
||||
|
||||
char sql[] = "INSERT INTO room (creator_id, creator_name, creator_address, room_name, "
|
||||
"room_topic, room_password, room_prefix, room_address, room_attributes, "
|
||||
"room_max_size, room_message_id, created_at, node_level) VALUES (@creator_id, "
|
||||
"@creator_name, @creator_address, @room_name, @room_topic, @room_password, "
|
||||
"@room_prefix, @room_address, @room_attributes, @room_max_size, @room_message_id, "
|
||||
"@created_at, @node_level)";
|
||||
|
||||
if (sqlite3_prepare_v2(db_, sql, -1, &stmt, 0) != SQLITE_OK) {
|
||||
result = ChatResultCode::DBFAIL;
|
||||
} else {
|
||||
int creatorIdIdx = sqlite3_bind_parameter_index(stmt, "@creator_id");
|
||||
int creatorNameIdx = sqlite3_bind_parameter_index(stmt, "@creator_name");
|
||||
int creatorAddressIdx = sqlite3_bind_parameter_index(stmt, "@creator_address");
|
||||
int roomNameIdx = sqlite3_bind_parameter_index(stmt, "@room_name");
|
||||
int roomTopicIdx = sqlite3_bind_parameter_index(stmt, "@room_topic");
|
||||
int roomPasswordIdx = sqlite3_bind_parameter_index(stmt, "@room_password");
|
||||
int roomPrefixIdx = sqlite3_bind_parameter_index(stmt, "@room_prefix");
|
||||
int roomAddressIdx = sqlite3_bind_parameter_index(stmt, "@room_address");
|
||||
int roomAttributesIdx = sqlite3_bind_parameter_index(stmt, "@room_attributes");
|
||||
int roomMaxSizeIdx = sqlite3_bind_parameter_index(stmt, "@room_max_size");
|
||||
int roomMessageIdIdx = sqlite3_bind_parameter_index(stmt, "@room_message_id");
|
||||
int createdAtIdx = sqlite3_bind_parameter_index(stmt, "@created_at");
|
||||
int nodeLevelIdx = sqlite3_bind_parameter_index(stmt, "@node_level");
|
||||
|
||||
sqlite3_bind_int(stmt, creatorIdIdx, room.creatorId_);
|
||||
|
||||
auto creatorName = FromWideString(room.creatorName_);
|
||||
sqlite3_bind_text(stmt, creatorNameIdx, creatorName.c_str(), -1, 0);
|
||||
|
||||
auto creatorAddress = FromWideString(room.creatorAddress_);
|
||||
sqlite3_bind_text(stmt, creatorAddressIdx, creatorAddress.c_str(), -1, 0);
|
||||
|
||||
auto roomName = FromWideString(room.roomName_);
|
||||
sqlite3_bind_text(stmt, roomNameIdx, roomName.c_str(), -1, 0);
|
||||
|
||||
auto roomTopic = FromWideString(room.roomTopic_);
|
||||
sqlite3_bind_text(stmt, roomTopicIdx, roomTopic.c_str(), -1, 0);
|
||||
|
||||
auto roomPassword = FromWideString(room.roomPassword_);
|
||||
sqlite3_bind_text(stmt, roomPasswordIdx, roomPassword.c_str(), -1, 0);
|
||||
|
||||
auto roomPrefix = FromWideString(room.roomPrefix_);
|
||||
sqlite3_bind_text(stmt, roomPrefixIdx, roomPrefix.c_str(), -1, 0);
|
||||
|
||||
auto roomAddress = FromWideString(room.roomAddress_);
|
||||
sqlite3_bind_text(stmt, roomAddressIdx, roomAddress.c_str(), -1, 0);
|
||||
|
||||
sqlite3_bind_int(stmt, roomAttributesIdx, room.roomAttributes_);
|
||||
sqlite3_bind_int(stmt, roomMaxSizeIdx, room.maxRoomSize_);
|
||||
sqlite3_bind_int(stmt, roomMessageIdIdx, room.roomMessageId_);
|
||||
sqlite3_bind_int(stmt, createdAtIdx, room.createTime_);
|
||||
sqlite3_bind_int(stmt, nodeLevelIdx, room.nodeLevel_);
|
||||
|
||||
if (sqlite3_step(stmt) != SQLITE_DONE) {
|
||||
result = ChatResultCode::DBFAIL;
|
||||
} else {
|
||||
room.dbId_ = static_cast<uint32_t>(sqlite3_last_insert_rowid(db_));
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
std::vector<ChatRoom*> ChatRoomService::GetRoomSummaries(
|
||||
const std::u16string& startNode, const std::u16string& filter) {
|
||||
std::vector<ChatRoom*> rooms;
|
||||
|
||||
for (auto& room : rooms_) {
|
||||
auto& roomAddress = room->GetRoomAddress();
|
||||
if (roomAddress.compare(0, startNode.length(), startNode) == 0) {
|
||||
if (!room->IsPrivate()) {
|
||||
rooms.push_back(room.get());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return rooms;
|
||||
}
|
||||
|
||||
bool ChatRoomService::RoomExists(const std::u16string& roomAddress) const {
|
||||
return std::find_if(std::begin(rooms_), std::end(rooms_), [roomAddress](auto& room) {
|
||||
return roomAddress.compare(room->GetRoomAddress()) == 0;
|
||||
}) != std::end(rooms_);
|
||||
}
|
||||
|
||||
ChatRoom* ChatRoomService::GetRoom(const std::u16string& roomAddress) {
|
||||
ChatRoom* room = nullptr;
|
||||
|
||||
auto find_iter = std::find_if(std::begin(rooms_), std::end(rooms_),
|
||||
[roomAddress](auto& room) { return roomAddress.compare(room->GetRoomAddress()) == 0; });
|
||||
|
||||
if (find_iter != std::end(rooms_)) {
|
||||
room = find_iter->get();
|
||||
}
|
||||
|
||||
return room;
|
||||
}
|
||||
|
||||
std::vector<ChatRoom*> ChatRoomService::GetJoinedRooms(const ChatAvatar * avatar) {
|
||||
std::vector<ChatRoom*> rooms;
|
||||
|
||||
for (auto& room : rooms_) {
|
||||
if (room->IsInRoom(avatar->GetAvatarId())) {
|
||||
rooms.push_back(room.get());
|
||||
}
|
||||
}
|
||||
|
||||
return rooms;
|
||||
}
|
||||
|
||||
void ChatRoomService::DeleteRoom(ChatRoom* room) {
|
||||
sqlite3_stmt* stmt;
|
||||
char sql[] = "DELETE FROM room WHERE id = @id";
|
||||
|
||||
auto result = sqlite3_prepare_v2(db_, sql, -1, &stmt, 0);
|
||||
if (result != SQLITE_OK) {
|
||||
throw SQLite3Exception{result, sqlite3_errmsg(db_)};
|
||||
}
|
||||
|
||||
int idIdx = sqlite3_bind_parameter_index(stmt, "@id");
|
||||
sqlite3_bind_int(stmt, idIdx, room->dbId_);
|
||||
|
||||
result = sqlite3_step(stmt);
|
||||
if (result != SQLITE_DONE) {
|
||||
throw SQLite3Exception{result, sqlite3_errmsg(db_)};
|
||||
}
|
||||
}
|
||||
|
||||
void ChatRoomService::LoadModerators(ChatRoom * room) {
|
||||
sqlite3_stmt* stmt;
|
||||
char sql[] = "SELECT moderator_avatar_id FROM room_moderator WHERE room_id = @room_id";
|
||||
|
||||
auto result = sqlite3_prepare_v2(db_, sql, -1, &stmt, 0);
|
||||
if (result != SQLITE_OK) {
|
||||
throw SQLite3Exception{result, sqlite3_errmsg(db_)};
|
||||
}
|
||||
|
||||
int roomIdIdx = sqlite3_bind_parameter_index(stmt, "@room_id");
|
||||
sqlite3_bind_int(stmt, roomIdIdx, room->GetRoomId());
|
||||
|
||||
while (sqlite3_step(stmt) == SQLITE_ROW) {
|
||||
uint32_t moderatorId = sqlite3_column_int(stmt, 0);
|
||||
room->moderators_.push_back(avatarService_->GetAvatar(moderatorId));
|
||||
}
|
||||
}
|
||||
|
||||
void ChatRoomService::PersistModerator(uint32_t moderatorId, uint32_t roomId) {
|
||||
sqlite3_stmt* stmt;
|
||||
char sql[] = "INSERT OR IGNORE INTO room_moderator (moderator_avatar_id, room_id) VALUES (@moderator_avatar_id, @room_id)";
|
||||
|
||||
auto result = sqlite3_prepare_v2(db_, sql, -1, &stmt, 0);
|
||||
if (result != SQLITE_OK) {
|
||||
throw SQLite3Exception{result, sqlite3_errmsg(db_)};
|
||||
}
|
||||
|
||||
int moderatorAvatarIdIdx = sqlite3_bind_parameter_index(stmt, "@moderator_avatar_id");
|
||||
int roomIdIdx = sqlite3_bind_parameter_index(stmt, "@room_id");
|
||||
|
||||
sqlite3_bind_int(stmt, moderatorAvatarIdIdx, moderatorId);
|
||||
sqlite3_bind_int(stmt, roomIdIdx, roomId);
|
||||
|
||||
result = sqlite3_step(stmt);
|
||||
if (result != SQLITE_DONE) {
|
||||
throw SQLite3Exception{result, sqlite3_errmsg(db_)};
|
||||
}
|
||||
}
|
||||
|
||||
void ChatRoomService::DeleteModerator(uint32_t moderatorId, uint32_t roomId) {
|
||||
sqlite3_stmt* stmt;
|
||||
char sql[] = "DELETE FROM room_moderator WHERE moderator_avatar_id = @moderator_avatar_id AND room_id = @room_id";
|
||||
|
||||
auto result = sqlite3_prepare_v2(db_, sql, -1, &stmt, 0);
|
||||
if (result != SQLITE_OK) {
|
||||
throw SQLite3Exception{result, sqlite3_errmsg(db_)};
|
||||
}
|
||||
|
||||
int moderatorAvatarIdIdx = sqlite3_bind_parameter_index(stmt, "@moderator_avatar_id");
|
||||
int roomIdIdx = sqlite3_bind_parameter_index(stmt, "@room_id");
|
||||
|
||||
sqlite3_bind_int(stmt, moderatorAvatarIdIdx, moderatorId);
|
||||
sqlite3_bind_int(stmt, roomIdIdx, roomId);
|
||||
|
||||
result = sqlite3_step(stmt);
|
||||
if (result != SQLITE_DONE) {
|
||||
throw SQLite3Exception{result, sqlite3_errmsg(db_)};
|
||||
}
|
||||
}
|
||||
|
||||
void ChatRoomService::LoadAdministrators(ChatRoom * room) {
|
||||
sqlite3_stmt* stmt;
|
||||
char sql[] = "SELECT administrator_avatar_id FROM room_administrator WHERE room_id = @room_id";
|
||||
|
||||
auto result = sqlite3_prepare_v2(db_, sql, -1, &stmt, 0);
|
||||
if (result != SQLITE_OK) {
|
||||
throw SQLite3Exception{result, sqlite3_errmsg(db_)};
|
||||
}
|
||||
|
||||
int roomIdIdx = sqlite3_bind_parameter_index(stmt, "@room_id");
|
||||
sqlite3_bind_int(stmt, roomIdIdx, room->GetRoomId());
|
||||
|
||||
while (sqlite3_step(stmt) == SQLITE_ROW) {
|
||||
uint32_t administratorId = sqlite3_column_int(stmt, 0);
|
||||
room->administrators_.push_back(avatarService_->GetAvatar(administratorId));
|
||||
}
|
||||
}
|
||||
|
||||
void ChatRoomService::PersistAdministrator(uint32_t administratorId, uint32_t roomId) {
|
||||
sqlite3_stmt* stmt;
|
||||
char sql[] = "INSERT OR IGNORE INTO room_administrator (administrator_avatar_id, room_id) VALUES (@administrator_avatar_id, @room_id)";
|
||||
|
||||
auto result = sqlite3_prepare_v2(db_, sql, -1, &stmt, 0);
|
||||
if (result != SQLITE_OK) {
|
||||
throw SQLite3Exception{result, sqlite3_errmsg(db_)};
|
||||
}
|
||||
|
||||
int administratorAvatarIdIdx = sqlite3_bind_parameter_index(stmt, "@administrator_avatar_id");
|
||||
int roomIdIdx = sqlite3_bind_parameter_index(stmt, "@room_id");
|
||||
|
||||
sqlite3_bind_int(stmt, administratorAvatarIdIdx, administratorId);
|
||||
sqlite3_bind_int(stmt, roomIdIdx, roomId);
|
||||
|
||||
result = sqlite3_step(stmt);
|
||||
if (result != SQLITE_DONE) {
|
||||
throw SQLite3Exception{result, sqlite3_errmsg(db_)};
|
||||
}
|
||||
}
|
||||
|
||||
void ChatRoomService::DeleteAdministrator(uint32_t administratorId, uint32_t roomId) {
|
||||
sqlite3_stmt* stmt;
|
||||
char sql[] = "DELETE FROM room_administrator WHERE administrator_avatar_id = @administrator_avatar_id AND room_id = @room_id";
|
||||
|
||||
auto result = sqlite3_prepare_v2(db_, sql, -1, &stmt, 0);
|
||||
if (result != SQLITE_OK) {
|
||||
throw SQLite3Exception{result, sqlite3_errmsg(db_)};
|
||||
}
|
||||
|
||||
int administratorAvatarIdIdx = sqlite3_bind_parameter_index(stmt, "@administrator_avatar_id");
|
||||
int roomIdIdx = sqlite3_bind_parameter_index(stmt, "@room_id");
|
||||
|
||||
sqlite3_bind_int(stmt, administratorAvatarIdIdx, administratorId);
|
||||
sqlite3_bind_int(stmt, roomIdIdx, roomId);
|
||||
|
||||
result = sqlite3_step(stmt);
|
||||
if (result != SQLITE_DONE) {
|
||||
throw SQLite3Exception{result, sqlite3_errmsg(db_)};
|
||||
}
|
||||
}
|
||||
|
||||
void ChatRoomService::LoadBanned(ChatRoom * room) {
|
||||
sqlite3_stmt* stmt;
|
||||
char sql[] = "SELECT banned_avatar_id FROM room_ban WHERE room_id = @room_id";
|
||||
|
||||
auto result = sqlite3_prepare_v2(db_, sql, -1, &stmt, 0);
|
||||
if (result != SQLITE_OK) {
|
||||
throw SQLite3Exception{result, sqlite3_errmsg(db_)};
|
||||
}
|
||||
|
||||
int roomIdIdx = sqlite3_bind_parameter_index(stmt, "@room_id");
|
||||
sqlite3_bind_int(stmt, roomIdIdx, room->GetRoomId());
|
||||
|
||||
while (sqlite3_step(stmt) == SQLITE_ROW) {
|
||||
uint32_t bannedId = sqlite3_column_int(stmt, 0);
|
||||
room->banned_.push_back(avatarService_->GetAvatar(bannedId));
|
||||
}
|
||||
}
|
||||
|
||||
void ChatRoomService::PersistBanned(uint32_t bannedId, uint32_t roomId) {
|
||||
sqlite3_stmt* stmt;
|
||||
char sql[] = "INSERT OR IGNORE INTO room_ban (banned_avatar_id, room_id) VALUES (@banned_avatar_id, @room_id)";
|
||||
|
||||
auto result = sqlite3_prepare_v2(db_, sql, -1, &stmt, 0);
|
||||
if (result != SQLITE_OK) {
|
||||
throw SQLite3Exception{result, sqlite3_errmsg(db_)};
|
||||
}
|
||||
|
||||
int bannedAvatarIdIdx = sqlite3_bind_parameter_index(stmt, "@moderator_avatar_id");
|
||||
int roomIdIdx = sqlite3_bind_parameter_index(stmt, "@room_id");
|
||||
|
||||
sqlite3_bind_int(stmt, bannedAvatarIdIdx, bannedId);
|
||||
sqlite3_bind_int(stmt, roomIdIdx, roomId);
|
||||
|
||||
result = sqlite3_step(stmt);
|
||||
if (result != SQLITE_DONE) {
|
||||
throw SQLite3Exception{result, sqlite3_errmsg(db_)};
|
||||
}
|
||||
}
|
||||
|
||||
void ChatRoomService::DeleteBanned(uint32_t bannedId, uint32_t roomId) {
|
||||
sqlite3_stmt* stmt;
|
||||
char sql[] = "DELETE FROM room_ban WHERE banned_avatar_id = @banned_avatar_id AND room_id = @room_id";
|
||||
|
||||
auto result = sqlite3_prepare_v2(db_, sql, -1, &stmt, 0);
|
||||
if (result != SQLITE_OK) {
|
||||
throw SQLite3Exception{result, sqlite3_errmsg(db_)};
|
||||
}
|
||||
|
||||
int bannedAvatarIdIdx = sqlite3_bind_parameter_index(stmt, "@banned_avatar_id");
|
||||
int roomIdIdx = sqlite3_bind_parameter_index(stmt, "@room_id");
|
||||
|
||||
sqlite3_bind_int(stmt, bannedAvatarIdIdx, bannedId);
|
||||
sqlite3_bind_int(stmt, roomIdIdx, roomId);
|
||||
|
||||
result = sqlite3_step(stmt);
|
||||
if (result != SQLITE_DONE) {
|
||||
throw SQLite3Exception{result, sqlite3_errmsg(db_)};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "ChatEnums.hpp"
|
||||
#include "ChatRoom.hpp"
|
||||
|
||||
#include <boost/optional.hpp>
|
||||
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
#include <set>
|
||||
#include <vector>
|
||||
|
||||
struct sqlite3;
|
||||
|
||||
class ChatAvatarService;
|
||||
|
||||
class ChatRoomService {
|
||||
public:
|
||||
ChatRoomService(ChatAvatarService* avatarService, sqlite3* db);
|
||||
~ChatRoomService();
|
||||
|
||||
void LoadRoomsFromStorage(const std::u16string& baseAddress);
|
||||
|
||||
ChatRoom* CreateRoom(const ChatAvatar* creator,
|
||||
const std::u16string& roomName, const std::u16string& roomTopic,
|
||||
const std::u16string& roomPassword, uint32_t roomAttributes, uint32_t maxRoomSize,
|
||||
const std::u16string& roomAddress, const std::u16string& srcAddress);
|
||||
|
||||
void DestroyRoom(ChatRoom* room);
|
||||
|
||||
ChatResultCode PersistNewRoom(ChatRoom& avatar);
|
||||
|
||||
std::vector<ChatRoom*> GetRoomSummaries(
|
||||
const std::u16string& startNode, const std::u16string& filter = u"");
|
||||
|
||||
bool RoomExists(const std::u16string& roomAddress) const;
|
||||
ChatRoom* GetRoom(const std::u16string& roomAddress);
|
||||
|
||||
std::vector<ChatRoom*> GetJoinedRooms(const ChatAvatar* avatar);
|
||||
|
||||
private:
|
||||
friend class ChatRoom;
|
||||
void DeleteRoom(ChatRoom* room);
|
||||
void LoadModerators(ChatRoom* room);
|
||||
void PersistModerator(uint32_t moderatorId, uint32_t roomId);
|
||||
void DeleteModerator(uint32_t moderatorId, uint32_t roomId);
|
||||
void LoadAdministrators(ChatRoom* room);
|
||||
void PersistAdministrator(uint32_t administratorId, uint32_t roomId);
|
||||
void DeleteAdministrator(uint32_t administratorId, uint32_t roomId);
|
||||
void LoadBanned(ChatRoom* room);
|
||||
void PersistBanned(uint32_t bannedId, uint32_t roomId);
|
||||
void DeleteBanned(uint32_t bannedId, uint32_t roomId);
|
||||
|
||||
uint32_t nextRoomId_ = 0;
|
||||
std::vector<std::unique_ptr<ChatRoom>> rooms_;
|
||||
ChatAvatarService* avatarService_;
|
||||
sqlite3* db_;
|
||||
};
|
||||
@@ -0,0 +1,38 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Serialization.hpp"
|
||||
|
||||
#include <string>
|
||||
|
||||
class ChatAvatar;
|
||||
|
||||
struct FriendContact {
|
||||
FriendContact(const ChatAvatar* frnd_, const std::wstring& comment_)
|
||||
: frnd{frnd_}
|
||||
, comment{comment_} {}
|
||||
|
||||
const ChatAvatar* frnd;
|
||||
std::wstring comment = L"";
|
||||
};
|
||||
|
||||
template <typename StreamT>
|
||||
void write(StreamT& ar, const FriendContact& data) {
|
||||
write(ar, data.frnd->GetName());
|
||||
write(ar, data.frnd->GetAddress());
|
||||
write(ar, data.comment);
|
||||
write(ar, static_cast<short>(data.frnd->IsOnline() ? 1 : 0));
|
||||
}
|
||||
|
||||
struct IgnoreContact {
|
||||
IgnoreContact(const ChatAvatar* ignored_)
|
||||
: ignored{ignored_} {}
|
||||
|
||||
const ChatAvatar* ignored;
|
||||
};
|
||||
|
||||
template <typename StreamT>
|
||||
void write(StreamT& ar, const IgnoreContact& data) {
|
||||
write(ar, data.ignored->GetName());
|
||||
write(ar, data.ignored->GetAddress());
|
||||
}
|
||||
@@ -0,0 +1,245 @@
|
||||
|
||||
#include "GatewayClient.hpp"
|
||||
|
||||
#include "ChatAvatarService.hpp"
|
||||
#include "ChatEnums.hpp"
|
||||
#include "ChatRoomService.hpp"
|
||||
#include "GatewayNode.hpp"
|
||||
#include "Message.hpp"
|
||||
#include "PersistentMessageService.hpp"
|
||||
#include "SQLite3.hpp"
|
||||
#include "StationChatConfig.hpp"
|
||||
#include "UdpLibrary.hpp"
|
||||
|
||||
#include "protocol/AddBan.hpp"
|
||||
#include "protocol/AddFriend.hpp"
|
||||
#include "protocol/AddIgnore.hpp"
|
||||
#include "protocol/AddInvite.hpp"
|
||||
#include "protocol/AddModerator.hpp"
|
||||
#include "protocol/CreateRoom.hpp"
|
||||
#include "protocol/DestroyRoom.hpp"
|
||||
#include "protocol/EnterRoom.hpp"
|
||||
#include "protocol/FailoverReLoginAvatar.hpp"
|
||||
#include "protocol/FriendStatus.hpp"
|
||||
#include "protocol/GetAnyAvatar.hpp"
|
||||
#include "protocol/GetPersistentHeaders.hpp"
|
||||
#include "protocol/GetPersistentMessage.hpp"
|
||||
#include "protocol/GetRoom.hpp"
|
||||
#include "protocol/GetRoomSummaries.hpp"
|
||||
#include "protocol/IgnoreStatus.hpp"
|
||||
#include "protocol/KickAvatar.hpp"
|
||||
#include "protocol/LeaveRoom.hpp"
|
||||
#include "protocol/LoginAvatar.hpp"
|
||||
#include "protocol/LogoutAvatar.hpp"
|
||||
#include "protocol/RemoveBan.hpp"
|
||||
#include "protocol/RemoveFriend.hpp"
|
||||
#include "protocol/RemoveIgnore.hpp"
|
||||
#include "protocol/RemoveInvite.hpp"
|
||||
#include "protocol/RemoveModerator.hpp"
|
||||
#include "protocol/SendInstantMessage.hpp"
|
||||
#include "protocol/SendPersistentMessage.hpp"
|
||||
#include "protocol/SendRoomMessage.hpp"
|
||||
#include "protocol/SetApiVersion.hpp"
|
||||
#include "protocol/SetAvatarAttributes.hpp"
|
||||
#include "protocol/UpdatePersistentMessage.hpp"
|
||||
|
||||
#include "easylogging++.h"
|
||||
|
||||
GatewayClient::GatewayClient(UdpConnection* connection, GatewayNode* node)
|
||||
: NodeClient(connection)
|
||||
, node_{node}
|
||||
, avatarService_{node->GetAvatarService()}
|
||||
, roomService_{node->GetRoomService()}
|
||||
, messageService_{node->GetMessageService()} {
|
||||
connection->SetHandler(this);
|
||||
}
|
||||
|
||||
GatewayClient::~GatewayClient() {}
|
||||
|
||||
void GatewayClient::OnIncoming(std::istringstream& istream) {
|
||||
ChatRequestType request_type = ::read<ChatRequestType>(istream);
|
||||
|
||||
switch (request_type) {
|
||||
case ChatRequestType::LOGINAVATAR:
|
||||
HandleIncomingMessage<LoginAvatar>(istream);
|
||||
break;
|
||||
case ChatRequestType::LOGOUTAVATAR:
|
||||
HandleIncomingMessage<LogoutAvatar>(istream);
|
||||
break;
|
||||
case ChatRequestType::CREATEROOM:
|
||||
HandleIncomingMessage<CreateRoom>(istream);
|
||||
break;
|
||||
case ChatRequestType::DESTROYROOM:
|
||||
HandleIncomingMessage<DestroyRoom>(istream);
|
||||
break;
|
||||
case ChatRequestType::SENDINSTANTMESSAGE:
|
||||
HandleIncomingMessage<SendInstantMessage>(istream);
|
||||
break;
|
||||
case ChatRequestType::SENDROOMMESSAGE:
|
||||
HandleIncomingMessage<SendRoomMessage>(istream);
|
||||
break;
|
||||
case ChatRequestType::ADDFRIEND:
|
||||
HandleIncomingMessage<AddFriend>(istream);
|
||||
break;
|
||||
case ChatRequestType::REMOVEFRIEND:
|
||||
HandleIncomingMessage<RemoveFriend>(istream);
|
||||
break;
|
||||
case ChatRequestType::FRIENDSTATUS:
|
||||
HandleIncomingMessage<FriendStatus>(istream);
|
||||
break;
|
||||
case ChatRequestType::ADDIGNORE:
|
||||
HandleIncomingMessage<AddIgnore>(istream);
|
||||
break;
|
||||
case ChatRequestType::REMOVEIGNORE:
|
||||
HandleIncomingMessage<RemoveIgnore>(istream);
|
||||
break;
|
||||
case ChatRequestType::ENTERROOM:
|
||||
HandleIncomingMessage<EnterRoom>(istream);
|
||||
break;
|
||||
case ChatRequestType::LEAVEROOM:
|
||||
HandleIncomingMessage<LeaveRoom>(istream);
|
||||
break;
|
||||
case ChatRequestType::ADDMODERATOR:
|
||||
HandleIncomingMessage<AddModerator>(istream);
|
||||
break;
|
||||
case ChatRequestType::REMOVEMODERATOR:
|
||||
HandleIncomingMessage<RemoveModerator>(istream);
|
||||
break;
|
||||
case ChatRequestType::ADDBAN:
|
||||
HandleIncomingMessage<AddBan>(istream);
|
||||
break;
|
||||
case ChatRequestType::REMOVEBAN:
|
||||
HandleIncomingMessage<RemoveBan>(istream);
|
||||
break;
|
||||
case ChatRequestType::ADDINVITE:
|
||||
HandleIncomingMessage<AddInvite>(istream);
|
||||
break;
|
||||
case ChatRequestType::REMOVEINVITE:
|
||||
HandleIncomingMessage<RemoveInvite>(istream);
|
||||
break;
|
||||
case ChatRequestType::KICKAVATAR:
|
||||
HandleIncomingMessage<KickAvatar>(istream);
|
||||
break;
|
||||
case ChatRequestType::GETROOM:
|
||||
HandleIncomingMessage<GetRoom>(istream);
|
||||
break;
|
||||
case ChatRequestType::GETROOMSUMMARIES:
|
||||
HandleIncomingMessage<GetRoomSummaries>(istream);
|
||||
break;
|
||||
case ChatRequestType::SENDPERSISTENTMESSAGE:
|
||||
HandleIncomingMessage<SendPersistentMessage>(istream);
|
||||
break;
|
||||
case ChatRequestType::GETPERSISTENTHEADERS:
|
||||
HandleIncomingMessage<GetPersistentHeaders>(istream);
|
||||
break;
|
||||
case ChatRequestType::GETPERSISTENTMESSAGE:
|
||||
HandleIncomingMessage<GetPersistentMessage>(istream);
|
||||
break;
|
||||
case ChatRequestType::UPDATEPERSISTENTMESSAGE:
|
||||
HandleIncomingMessage<UpdatePersistentMessage>(istream);
|
||||
break;
|
||||
case ChatRequestType::IGNORESTATUS:
|
||||
HandleIncomingMessage<IgnoreStatus>(istream);
|
||||
break;
|
||||
case ChatRequestType::FAILOVER_RELOGINAVATAR:
|
||||
HandleIncomingMessage<FailoverReLoginAvatar>(istream);
|
||||
break;
|
||||
case ChatRequestType::SETAPIVERSION:
|
||||
HandleIncomingMessage<SetApiVersion>(istream);
|
||||
break;
|
||||
case ChatRequestType::SETAVATARATTRIBUTES:
|
||||
HandleIncomingMessage<SetAvatarAttributes>(istream);
|
||||
break;
|
||||
case ChatRequestType::GETANYAVATAR:
|
||||
HandleIncomingMessage<GetAnyAvatar>(istream);
|
||||
break;
|
||||
default:
|
||||
LOG(INFO) << "Unknown request type received: " << static_cast<uint16_t>(request_type);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void GatewayClient::SendFriendLoginUpdate(
|
||||
const ChatAvatar* srcAvatar, const ChatAvatar* destAvatar) {
|
||||
node_->SendTo(
|
||||
srcAvatar->GetAddress(), MFriendLogin{destAvatar, destAvatar->GetAddress(),
|
||||
srcAvatar->GetAvatarId(), destAvatar->GetStatusMessage()});
|
||||
}
|
||||
|
||||
void GatewayClient::SendFriendLoginUpdates(const ChatAvatar* avatar) {
|
||||
auto as = node_->GetAvatarService();
|
||||
auto& onlineAvatars = as->GetOnlineAvatars();
|
||||
for (auto onlineAvatar : onlineAvatars) {
|
||||
if (onlineAvatar->IsFriend(avatar)) {
|
||||
SendFriendLoginUpdate(onlineAvatar, avatar);
|
||||
}
|
||||
}
|
||||
|
||||
for (auto& contact : avatar->GetFriendList()) {
|
||||
if (contact.frnd->IsOnline()) {
|
||||
Send(MFriendLogin{contact.frnd, contact.frnd->GetAddress(), avatar->GetAvatarId(),
|
||||
contact.frnd->GetStatusMessage()});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GatewayClient::SendFriendLogoutUpdates(const ChatAvatar* avatar) {
|
||||
auto& onlineAvatars = avatarService_->GetOnlineAvatars();
|
||||
for (auto onlineAvatar : onlineAvatars) {
|
||||
if (onlineAvatar->IsFriend(avatar)) {
|
||||
node_->SendTo(onlineAvatar->GetAddress(),
|
||||
MFriendLogout{avatar, avatar->GetAddress(), onlineAvatar->GetAvatarId()});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GatewayClient::SendDestroyRoomUpdate(
|
||||
const ChatAvatar* srcAvatar, uint32_t roomId, std::vector<std::u16string> targets) {
|
||||
for (auto& address : targets) {
|
||||
node_->SendTo(address, MDestroyRoom{srcAvatar, roomId});
|
||||
}
|
||||
}
|
||||
|
||||
void GatewayClient::SendInstantMessageUpdate(const ChatAvatar* srcAvatar,
|
||||
const ChatAvatar* destAvatar, const std::u16string& message, const std::u16string& oob) {
|
||||
node_->SendTo(destAvatar->GetAddress(),
|
||||
MInstantMessage{srcAvatar, destAvatar->GetAvatarId(), message, oob});
|
||||
}
|
||||
|
||||
void GatewayClient::SendRoomMessageUpdate(const ChatAvatar* srcAvatar, const ChatRoom* room,
|
||||
uint32_t messageId, const std::u16string& message, const std::u16string& oob) {
|
||||
auto connectedAddresses = room->GetConnectedAddresses();
|
||||
for (auto& address : connectedAddresses) {
|
||||
node_->SendTo(address, MRoomMessage{srcAvatar, room->GetRoomId(), room->GetAvatarIds(srcAvatar),
|
||||
message, oob, messageId});
|
||||
}
|
||||
}
|
||||
|
||||
void GatewayClient::SendEnterRoomUpdate(const ChatAvatar* srcAvatar, const ChatRoom* room) {
|
||||
for (const auto& address : room->GetConnectedAddresses()) {
|
||||
node_->SendTo(address, MEnterRoom{srcAvatar, room->GetRoomId()});
|
||||
}
|
||||
}
|
||||
|
||||
void GatewayClient::SendLeaveRoomUpdate(
|
||||
const std::vector<std::u16string>& addresses, uint32_t srcAvatarId, uint32_t roomId) {
|
||||
for (const auto& address : addresses) {
|
||||
node_->SendTo(address, MLeaveRoom{srcAvatarId, roomId});
|
||||
}
|
||||
}
|
||||
|
||||
void GatewayClient::SendPersistentMessageUpdate(
|
||||
const ChatAvatar* destAvatar, const PersistentHeader& header) {
|
||||
if (destAvatar) {
|
||||
node_->SendTo(
|
||||
destAvatar->GetAddress(), MPersistentMessage{destAvatar->GetAvatarId(), header});
|
||||
}
|
||||
}
|
||||
|
||||
void GatewayClient::SendKickAvatarUpdate(const std::vector<std::u16string>& addresses,
|
||||
const ChatAvatar* srcAvatar, const ChatAvatar* destAvatar, const ChatRoom* room) {
|
||||
for (const auto& address : addresses) {
|
||||
node_->SendTo(address,
|
||||
MKickAvatar{srcAvatar, destAvatar, room->GetRoomName(), room->GetRoomAddress()});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "ChatEnums.hpp"
|
||||
#include "NodeClient.hpp"
|
||||
#include "SQLite3.hpp"
|
||||
#include "easylogging++.h"
|
||||
|
||||
class ChatAvatar;
|
||||
class ChatAvatarService;
|
||||
class ChatRoom;
|
||||
class ChatRoomService;
|
||||
class GatewayNode;
|
||||
class PersistentMessageService;
|
||||
class UdpConnection;
|
||||
|
||||
struct PersistentHeader;
|
||||
|
||||
struct ReqSetAvatarAttributes;
|
||||
struct ReqGetAnyAvatar;
|
||||
|
||||
class GatewayClient : public NodeClient {
|
||||
public:
|
||||
GatewayClient(UdpConnection* connection, GatewayNode* node);
|
||||
virtual ~GatewayClient();
|
||||
|
||||
GatewayNode* GetNode() { return node_; }
|
||||
|
||||
void SendFriendLoginUpdate(const ChatAvatar* srcAvatar, const ChatAvatar* destAvatar);
|
||||
void SendFriendLoginUpdates(const ChatAvatar* avatar);
|
||||
void SendFriendLogoutUpdates(const ChatAvatar* avatar);
|
||||
void SendDestroyRoomUpdate(const ChatAvatar* srcAvatar, uint32_t roomId, std::vector<std::u16string> targets);
|
||||
void SendInstantMessageUpdate(const ChatAvatar* srcAvatar, const ChatAvatar* destAvatar, const std::u16string& message, const std::u16string& oob);
|
||||
void SendRoomMessageUpdate(const ChatAvatar* srcAvatar, const ChatRoom* room, uint32_t messageId, const std::u16string& message, const std::u16string& oob);
|
||||
void SendEnterRoomUpdate(const ChatAvatar* srcAvatar, const ChatRoom* room);
|
||||
void SendLeaveRoomUpdate(const std::vector<std::u16string>& addresses, uint32_t srcAvatarId, uint32_t roomId);
|
||||
void SendPersistentMessageUpdate(const ChatAvatar* destAvatar, const PersistentHeader& header);
|
||||
void SendKickAvatarUpdate(const std::vector<std::u16string>& addresses, const ChatAvatar* srcAvatar, const ChatAvatar* destAvatar, const ChatRoom* room);
|
||||
|
||||
private:
|
||||
void OnIncoming(std::istringstream& istream) override;
|
||||
|
||||
template<typename HandlerT, typename StreamT>
|
||||
void HandleIncomingMessage(StreamT& istream) {
|
||||
typedef typename HandlerT::RequestType RequestT;
|
||||
typedef typename HandlerT::ResponseType ResponseT;
|
||||
|
||||
RequestT request;
|
||||
read(istream, request);
|
||||
ResponseT response(request.track);
|
||||
|
||||
try {
|
||||
HandlerT(this, request, response);
|
||||
} catch (const ChatResultException& e) {
|
||||
response.result = e.code;
|
||||
LOG(ERROR) << "ChatAPI Result Exception: [" << ToString(e.code) << "] " << e.message;
|
||||
} catch (const SQLite3Exception& e) {
|
||||
response.result = ChatResultCode::DATABASE;
|
||||
LOG(ERROR) << "Database Error: [" << e.code << "] " << e.message;
|
||||
}
|
||||
|
||||
Send(response);
|
||||
}
|
||||
|
||||
GatewayNode* node_;
|
||||
ChatAvatarService* avatarService_;
|
||||
ChatRoomService* roomService_;
|
||||
PersistentMessageService* messageService_;
|
||||
};
|
||||
@@ -0,0 +1,39 @@
|
||||
|
||||
#include "GatewayNode.hpp"
|
||||
|
||||
#include "ChatAvatarService.hpp"
|
||||
#include "ChatRoomService.hpp"
|
||||
#include "PersistentMessageService.hpp"
|
||||
#include "StationChatConfig.hpp"
|
||||
|
||||
#include <sqlite3.h>
|
||||
|
||||
GatewayNode::GatewayNode(StationChatConfig& config)
|
||||
: Node(this, config.gatewayAddress, config.gatewayPort)
|
||||
, config_{config} {
|
||||
if (sqlite3_open(config.chatDatabasePath.c_str(), &db_) != SQLITE_OK) {
|
||||
throw std::runtime_error("Can't open database: " + std::string{sqlite3_errmsg(db_)});
|
||||
}
|
||||
|
||||
avatarService_ = std::make_unique<ChatAvatarService>(db_);
|
||||
roomService_ = std::make_unique<ChatRoomService>(avatarService_.get(), db_);
|
||||
messageService_ = std::make_unique<PersistentMessageService>(db_);
|
||||
}
|
||||
|
||||
GatewayNode::~GatewayNode() { sqlite3_close(db_); }
|
||||
|
||||
ChatAvatarService* GatewayNode::GetAvatarService() { return avatarService_.get(); }
|
||||
|
||||
ChatRoomService* GatewayNode::GetRoomService() { return roomService_.get(); }
|
||||
|
||||
PersistentMessageService* GatewayNode::GetMessageService() {
|
||||
return messageService_.get();
|
||||
}
|
||||
|
||||
StationChatConfig& GatewayNode::GetConfig() { return config_; }
|
||||
|
||||
void GatewayNode::RegisterClientAddress(const std::u16string & address, GatewayClient * client) {
|
||||
clientAddressMap_[address] = client;
|
||||
}
|
||||
|
||||
void GatewayNode::OnTick() {}
|
||||
@@ -0,0 +1,45 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Node.hpp"
|
||||
#include "GatewayClient.hpp"
|
||||
|
||||
#include <map>
|
||||
#include <memory>
|
||||
|
||||
class ChatAvatarService;
|
||||
class ChatRoomService;
|
||||
class PersistentMessageService;
|
||||
struct StationChatConfig;
|
||||
struct sqlite3;
|
||||
|
||||
class GatewayNode : public Node<GatewayNode, GatewayClient> {
|
||||
public:
|
||||
explicit GatewayNode(StationChatConfig& config);
|
||||
~GatewayNode();
|
||||
|
||||
ChatAvatarService* GetAvatarService();
|
||||
ChatRoomService* GetRoomService();
|
||||
PersistentMessageService* GetMessageService();
|
||||
StationChatConfig& GetConfig();
|
||||
|
||||
void RegisterClientAddress(const std::u16string& address, GatewayClient* client);
|
||||
|
||||
template<typename MessageT>
|
||||
void SendTo(const std::u16string& address, const MessageT& message) {
|
||||
auto find_iter = clientAddressMap_.find(address);
|
||||
if (find_iter != std::end(clientAddressMap_)) {
|
||||
find_iter->second->Send(message);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
void OnTick() override;
|
||||
|
||||
std::unique_ptr<ChatAvatarService> avatarService_;
|
||||
std::unique_ptr<ChatRoomService> roomService_;
|
||||
std::unique_ptr<PersistentMessageService> messageService_;
|
||||
std::map<std::u16string, GatewayClient*> clientAddressMap_;
|
||||
StationChatConfig& config_;
|
||||
sqlite3* db_;
|
||||
};
|
||||
@@ -0,0 +1,298 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "ChatAvatar.hpp"
|
||||
#include "PersistentMessage.hpp"
|
||||
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
|
||||
enum class ChatMessageType : uint16_t {
|
||||
// ChatAvatar message types
|
||||
INSTANTMESSAGE = 0, // 0
|
||||
ROOMMESSAGE,
|
||||
BROADCASTMESSAGE,
|
||||
FRIENDLOGIN,
|
||||
FRIENDLOGOUT,
|
||||
KICKROOM, // 5
|
||||
|
||||
// ChatRoom message types
|
||||
ADDMODERATORROOM,
|
||||
REMOVEMODERATORROOM,
|
||||
REMOVEMODERATORAVATAR,
|
||||
ADDBANROOM,
|
||||
REMOVEBANROOM, // 10
|
||||
REMOVEBANAVATAR,
|
||||
ADDINVITEROOM,
|
||||
ADDINVITEAVATAR,
|
||||
REMOVEINVITEROOM,
|
||||
REMOVEINVITEAVATAR, // 15
|
||||
ENTERROOM,
|
||||
LEAVEROOM,
|
||||
DESTROYROOM,
|
||||
SETROOMPARAMS,
|
||||
PERSISTENTMESSAGE, // 20
|
||||
FORCEDLOGOUT,
|
||||
UNREGISTERROOMREADY,
|
||||
KICKAVATAR,
|
||||
ADDMODERATORAVATAR,
|
||||
ADDBANAVATAR, // 25
|
||||
ADDADMIN,
|
||||
REMOVEADMIN,
|
||||
FRIENDCONFIRMREQUEST,
|
||||
FRIENDCONFIRMRESPONSE,
|
||||
CHANGEROOMOWNER, // 30
|
||||
FORCEROOMFAILOVER,
|
||||
ADDTEMPORARYMODERATORROOM,
|
||||
ADDTEMPORARYMODERATORAVATAR,
|
||||
REMOVETEMPORARYMODERATORROOM,
|
||||
REMOVETEMPORARYMODERATORAVATAR, // 35
|
||||
GRANTVOICEROOM,
|
||||
GRANTVOICEAVATAR,
|
||||
REVOKEVOICEROOM,
|
||||
REVOKEVOICEAVATAR,
|
||||
SNOOP, // 40
|
||||
UIDLIST,
|
||||
REQUESTROOMENTRY,
|
||||
DELAYEDROOMENTRY,
|
||||
DENIEDROOMENTRY,
|
||||
FRIENDSTATUS, // 45
|
||||
FRIENDCONFIRMRECIPROCATE_REQUEST,
|
||||
FRIENDCONFIRMRECIPROCATE_RESPONSE,
|
||||
FILTERMESSAGE,
|
||||
FAILOVER_AVATAR_LIST,
|
||||
NOTIFY_FRIENDS_LIST_CHANGE, // 50
|
||||
NOTIFY_FRIEND_IS_REMOVED
|
||||
};
|
||||
|
||||
/** Begin INSTANTMESSAGE */
|
||||
|
||||
struct MInstantMessage {
|
||||
MInstantMessage(const ChatAvatar* srcAvatar_, uint32_t destAvatarId_,
|
||||
const std::u16string& message_, const std::u16string& oob_)
|
||||
: srcAvatar{srcAvatar_}
|
||||
, destAvatarId{destAvatarId_}
|
||||
, message{message_}
|
||||
, oob{oob_} {}
|
||||
|
||||
const ChatMessageType type = ChatMessageType::INSTANTMESSAGE;
|
||||
const uint32_t track = 0;
|
||||
const ChatAvatar* srcAvatar;
|
||||
uint32_t destAvatarId;
|
||||
std::u16string message;
|
||||
std::u16string oob;
|
||||
};
|
||||
|
||||
template <typename StreamT>
|
||||
void write(StreamT& ar, const MInstantMessage& data) {
|
||||
write(ar, data.type);
|
||||
write(ar, data.track);
|
||||
write(ar, data.srcAvatar);
|
||||
write(ar, data.destAvatarId);
|
||||
write(ar, data.message);
|
||||
write(ar, data.oob);
|
||||
}
|
||||
|
||||
/** Begin ROOMMESSAGE */
|
||||
|
||||
struct MRoomMessage {
|
||||
MRoomMessage(const ChatAvatar* srcAvatar_, uint32_t roomId_, std::vector<uint32_t> destList_,
|
||||
const std::u16string& message_, const std::u16string& oob_, uint32_t messageId_)
|
||||
: srcAvatar{srcAvatar_}
|
||||
, roomId{roomId_}
|
||||
, destList{destList_}
|
||||
, message{message_}
|
||||
, oob{oob_}
|
||||
, messageId{messageId_} {}
|
||||
|
||||
const ChatMessageType type = ChatMessageType::ROOMMESSAGE;
|
||||
const uint32_t track = 0;
|
||||
const ChatAvatar* srcAvatar;
|
||||
uint32_t roomId;
|
||||
std::vector<uint32_t> destList; // list of destination avatars to see the message
|
||||
std::u16string message;
|
||||
std::u16string oob;
|
||||
uint32_t messageId = 0;
|
||||
};
|
||||
|
||||
template <typename StreamT>
|
||||
void write(StreamT& ar, const MRoomMessage& data) {
|
||||
write(ar, data.type);
|
||||
write(ar, data.track);
|
||||
write(ar, data.srcAvatar);
|
||||
write(ar, data.roomId);
|
||||
|
||||
write(ar, static_cast<uint32_t>(data.destList.size()));
|
||||
for (auto destAvatarId : data.destList) {
|
||||
write(ar, destAvatarId);
|
||||
}
|
||||
|
||||
write(ar, data.message);
|
||||
write(ar, data.oob);
|
||||
write(ar, data.messageId);
|
||||
}
|
||||
|
||||
/** Begin FRIENDLOGIN */
|
||||
|
||||
struct MFriendLogin {
|
||||
MFriendLogin(const ChatAvatar* avatar_, const std::u16string& friendAddress_,
|
||||
uint32_t destAvatarId_, const std::u16string& friendStatus_)
|
||||
: avatar{avatar_}
|
||||
, friendAddress{friendAddress_}
|
||||
, destAvatarId{destAvatarId_}
|
||||
, friendStatus{friendStatus_} {}
|
||||
|
||||
const ChatMessageType type = ChatMessageType::FRIENDLOGIN;
|
||||
const uint32_t track = 0;
|
||||
const ChatAvatar* avatar;
|
||||
std::u16string friendAddress;
|
||||
uint32_t destAvatarId;
|
||||
std::u16string friendStatus;
|
||||
};
|
||||
|
||||
template <typename StreamT>
|
||||
void write(StreamT& ar, const MFriendLogin& data) {
|
||||
write(ar, data.type);
|
||||
write(ar, data.track);
|
||||
write(ar, data.avatar);
|
||||
write(ar, data.friendAddress);
|
||||
write(ar, data.destAvatarId);
|
||||
write(ar, data.friendStatus);
|
||||
}
|
||||
|
||||
/** Begin FRIENDLOGOUT */
|
||||
|
||||
struct MFriendLogout {
|
||||
MFriendLogout(
|
||||
const ChatAvatar* avatar_, const std::u16string& friendAddress_, uint32_t destAvatarId_)
|
||||
: avatar{avatar_}
|
||||
, friendAddress{friendAddress_}
|
||||
, destAvatarId{destAvatarId_} {}
|
||||
|
||||
const ChatMessageType type = ChatMessageType::FRIENDLOGOUT;
|
||||
const uint32_t track = 0;
|
||||
const ChatAvatar* avatar;
|
||||
uint32_t destAvatarId;
|
||||
std::u16string friendAddress;
|
||||
};
|
||||
|
||||
template <typename StreamT>
|
||||
void write(StreamT& ar, const MFriendLogout& data) {
|
||||
write(ar, data.type);
|
||||
write(ar, data.track);
|
||||
write(ar, data.avatar);
|
||||
write(ar, data.friendAddress);
|
||||
write(ar, data.destAvatarId);
|
||||
}
|
||||
|
||||
/** Begin ENTERROOM */
|
||||
|
||||
struct MEnterRoom {
|
||||
MEnterRoom(const ChatAvatar* srcAvatar_, uint32_t roomId_)
|
||||
: srcAvatar{srcAvatar_}
|
||||
, roomId{roomId_} {}
|
||||
|
||||
const ChatMessageType type = ChatMessageType::ENTERROOM;
|
||||
const uint32_t track = 0;
|
||||
const ChatAvatar* srcAvatar;
|
||||
uint32_t roomId;
|
||||
};
|
||||
|
||||
template <typename StreamT>
|
||||
void write(StreamT& ar, const MEnterRoom& data) {
|
||||
write(ar, data.type);
|
||||
write(ar, data.track);
|
||||
write(ar, data.srcAvatar);
|
||||
write(ar, data.roomId);
|
||||
}
|
||||
|
||||
/** Begin LEAVEROOM */
|
||||
|
||||
struct MLeaveRoom {
|
||||
MLeaveRoom(uint32_t avatarId_, uint32_t roomId_)
|
||||
: avatarId{avatarId_}
|
||||
, roomId{roomId_} {}
|
||||
|
||||
const ChatMessageType type = ChatMessageType::LEAVEROOM;
|
||||
const uint32_t track = 0;
|
||||
uint32_t avatarId;
|
||||
uint32_t roomId;
|
||||
};
|
||||
|
||||
template <typename StreamT>
|
||||
void write(StreamT& ar, const MLeaveRoom& data) {
|
||||
write(ar, data.type);
|
||||
write(ar, data.track);
|
||||
write(ar, data.avatarId);
|
||||
write(ar, data.roomId);
|
||||
}
|
||||
|
||||
/** Begin DESTROYROOM */
|
||||
|
||||
struct MDestroyRoom {
|
||||
MDestroyRoom(const ChatAvatar* srcAvatar_, uint32_t roomId_)
|
||||
: srcAvatar{srcAvatar_}
|
||||
, roomId{roomId_} {}
|
||||
|
||||
const ChatMessageType type = ChatMessageType::DESTROYROOM;
|
||||
const uint32_t track = 0;
|
||||
const ChatAvatar* srcAvatar;
|
||||
uint32_t roomId;
|
||||
};
|
||||
|
||||
template <typename StreamT>
|
||||
void write(StreamT& ar, const MDestroyRoom& data) {
|
||||
write(ar, data.type);
|
||||
write(ar, data.track);
|
||||
write(ar, data.srcAvatar);
|
||||
write(ar, data.roomId);
|
||||
}
|
||||
|
||||
/** Begin PERSISTENTMESSAGE */
|
||||
|
||||
struct MPersistentMessage {
|
||||
MPersistentMessage(uint32_t destAvatarId_, PersistentHeader header_)
|
||||
: destAvatarId{destAvatarId_}
|
||||
, header{header_} {}
|
||||
|
||||
const ChatMessageType type = ChatMessageType::PERSISTENTMESSAGE;
|
||||
const uint32_t track = 0;
|
||||
uint32_t destAvatarId;
|
||||
PersistentHeader header;
|
||||
};
|
||||
|
||||
template <typename StreamT>
|
||||
void write(StreamT& ar, const MPersistentMessage& data) {
|
||||
write(ar, data.type);
|
||||
write(ar, data.track);
|
||||
write(ar, data.destAvatarId);
|
||||
write(ar, data.header);
|
||||
}
|
||||
|
||||
/** Begin KICKAVATAR */
|
||||
|
||||
struct MKickAvatar {
|
||||
MKickAvatar(const ChatAvatar* srcAvatar_, const ChatAvatar* destAvatar_,
|
||||
const std::u16string& roomName_, const std::u16string& roomAddress_)
|
||||
: srcAvatar{srcAvatar_}
|
||||
, destAvatar{destAvatar_}
|
||||
, roomName{roomName_}
|
||||
, roomAddress{roomAddress_} {}
|
||||
|
||||
const ChatMessageType type = ChatMessageType::KICKAVATAR;
|
||||
const uint32_t track = 0;
|
||||
const ChatAvatar* srcAvatar;
|
||||
const ChatAvatar* destAvatar;
|
||||
std::u16string roomName;
|
||||
std::u16string roomAddress;
|
||||
};
|
||||
|
||||
template <typename StreamT>
|
||||
void write(StreamT& ar, const MKickAvatar& data) {
|
||||
write(ar, data.type);
|
||||
write(ar, data.track);
|
||||
write(ar, data.srcAvatar);
|
||||
write(ar, data.destAvatar);
|
||||
write(ar, data.roomName);
|
||||
write(ar, data.roomAddress);
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
|
||||
enum class PersistentState : uint32_t {
|
||||
NEW = 1,
|
||||
UNREAD,
|
||||
READ,
|
||||
TRASH,
|
||||
DELETED
|
||||
};
|
||||
|
||||
struct PersistentHeader {
|
||||
uint32_t messageId = 0;
|
||||
uint32_t avatarId;
|
||||
std::u16string fromName;
|
||||
std::u16string fromAddress;
|
||||
std::u16string subject;
|
||||
uint32_t sentTime = 0;
|
||||
PersistentState status = PersistentState::NEW;
|
||||
std::u16string folder = u"";
|
||||
std::u16string category = u"";
|
||||
};
|
||||
|
||||
struct PersistentMessage {
|
||||
PersistentHeader header;
|
||||
std::u16string message;
|
||||
std::u16string oob;
|
||||
};
|
||||
|
||||
|
||||
template <typename StreamT>
|
||||
void write(StreamT& ar, const PersistentHeader& data) {
|
||||
write(ar, data.messageId);
|
||||
write(ar, data.avatarId);
|
||||
write(ar, data.fromName);
|
||||
write(ar, data.fromAddress);
|
||||
write(ar, data.subject);
|
||||
write(ar, data.sentTime);
|
||||
write(ar, data.status);
|
||||
}
|
||||
|
||||
|
||||
template <typename StreamT>
|
||||
void write(StreamT& ar, const PersistentMessage& data) {
|
||||
write(ar, data.header);
|
||||
write(ar, data.message);
|
||||
write(ar, data.oob);
|
||||
}
|
||||
@@ -0,0 +1,210 @@
|
||||
#include "PersistentMessageService.hpp"
|
||||
|
||||
#include "SQLite3.hpp"
|
||||
#include "StringUtils.hpp"
|
||||
|
||||
|
||||
PersistentMessageService::PersistentMessageService(sqlite3* db)
|
||||
: db_{db} {}
|
||||
|
||||
PersistentMessageService::~PersistentMessageService() {}
|
||||
|
||||
void PersistentMessageService::StoreMessage(PersistentMessage& message) {
|
||||
sqlite3_stmt* stmt;
|
||||
|
||||
char sql[] = "INSERT INTO persistent_message (avatar_id, from_name, from_address, subject, "
|
||||
"sent_time, status, "
|
||||
"folder, category, message, oob) VALUES (@avatar_id, @from_name, @from_address, "
|
||||
"@subject, @sent_time, @status, @folder, @category, @message, @oob)";
|
||||
|
||||
auto result = sqlite3_prepare_v2(db_, sql, -1, &stmt, 0);
|
||||
if (result != SQLITE_OK) {
|
||||
throw SQLite3Exception{result, sqlite3_errmsg(db_)};
|
||||
}
|
||||
|
||||
int avatarIdIdx = sqlite3_bind_parameter_index(stmt, "@avatar_id");
|
||||
int fromNameIdx = sqlite3_bind_parameter_index(stmt, "@from_name");
|
||||
int fromAddressIdx = sqlite3_bind_parameter_index(stmt, "@from_address");
|
||||
int subjectIdx = sqlite3_bind_parameter_index(stmt, "@subject");
|
||||
int sentTimeIdx = sqlite3_bind_parameter_index(stmt, "@sent_time");
|
||||
int statusIdx = sqlite3_bind_parameter_index(stmt, "@status");
|
||||
int folderIdx = sqlite3_bind_parameter_index(stmt, "@folder");
|
||||
int categoryIdx = sqlite3_bind_parameter_index(stmt, "@category");
|
||||
int messageIdx = sqlite3_bind_parameter_index(stmt, "@message");
|
||||
int oobIdx = sqlite3_bind_parameter_index(stmt, "@oob");
|
||||
|
||||
sqlite3_bind_int(stmt, avatarIdIdx, message.header.avatarId);
|
||||
|
||||
std::string fromName = FromWideString(message.header.fromName);
|
||||
sqlite3_bind_text(stmt, fromNameIdx, fromName.c_str(), -1, 0);
|
||||
|
||||
std::string fromAddress = FromWideString(message.header.fromAddress);
|
||||
sqlite3_bind_text(stmt, fromAddressIdx, fromAddress.c_str(), -1, 0);
|
||||
|
||||
std::string subject = FromWideString(message.header.subject);
|
||||
sqlite3_bind_text(stmt, subjectIdx, subject.c_str(), -1, 0);
|
||||
|
||||
sqlite3_bind_int(stmt, sentTimeIdx, message.header.sentTime);
|
||||
sqlite3_bind_int(stmt, statusIdx, static_cast<uint32_t>(message.header.status));
|
||||
|
||||
std::string folder = FromWideString(message.header.folder);
|
||||
sqlite3_bind_text(stmt, folderIdx, folder.c_str(), -1, 0);
|
||||
|
||||
std::string category = FromWideString(message.header.category);
|
||||
sqlite3_bind_text(stmt, categoryIdx, category.c_str(), -1, 0);
|
||||
|
||||
std::string msg = FromWideString(message.message);
|
||||
sqlite3_bind_text(stmt, messageIdx, msg.c_str(), -1, 0);
|
||||
|
||||
sqlite3_bind_blob(stmt, oobIdx, reinterpret_cast<const uint8_t*>(message.oob.data()), message.oob.size() * 2, SQLITE_STATIC);
|
||||
|
||||
result = sqlite3_step(stmt);
|
||||
if (result != SQLITE_DONE) {
|
||||
throw SQLite3Exception{result, sqlite3_errmsg(db_)};
|
||||
}
|
||||
|
||||
message.header.messageId = static_cast<uint32_t>(sqlite3_last_insert_rowid(db_));
|
||||
}
|
||||
|
||||
std::vector<PersistentHeader> PersistentMessageService::GetMessageHeaders(uint32_t avatarId) {
|
||||
std::vector<PersistentHeader> headers;
|
||||
sqlite3_stmt* stmt;
|
||||
|
||||
char sql[] = "SELECT id, avatar_id, from_name, from_address, subject, sent_time, status, "
|
||||
"folder, category, message, oob FROM persistent_message WHERE avatar_id = "
|
||||
"@avatar_id AND status IN (1, 2, 3)";
|
||||
|
||||
auto result = sqlite3_prepare_v2(db_, sql, -1, &stmt, 0);
|
||||
if (result != SQLITE_OK) {
|
||||
throw SQLite3Exception{result, sqlite3_errmsg(db_)};
|
||||
}
|
||||
|
||||
int avatarIdIdx = sqlite3_bind_parameter_index(stmt, "@avatar_id");
|
||||
|
||||
sqlite3_bind_int(stmt, avatarIdIdx, avatarId);
|
||||
|
||||
while (sqlite3_step(stmt) == SQLITE_ROW) {
|
||||
PersistentHeader header;
|
||||
|
||||
header.messageId = sqlite3_column_int(stmt, 0);
|
||||
header.avatarId = sqlite3_column_int(stmt, 1);
|
||||
|
||||
auto tmp = std::string(reinterpret_cast<const char*>(sqlite3_column_text(stmt, 2)));
|
||||
header.fromName = std::u16string(std::begin(tmp), std::end(tmp));
|
||||
|
||||
tmp = std::string(reinterpret_cast<const char*>(sqlite3_column_text(stmt, 3)));
|
||||
header.fromAddress = std::u16string(std::begin(tmp), std::end(tmp));
|
||||
|
||||
tmp = std::string(reinterpret_cast<const char*>(sqlite3_column_text(stmt, 4)));
|
||||
header.subject = std::u16string(std::begin(tmp), std::end(tmp));
|
||||
|
||||
header.sentTime = sqlite3_column_int(stmt, 5);
|
||||
header.status = static_cast<PersistentState>(sqlite3_column_int(stmt, 6));
|
||||
|
||||
tmp = std::string(reinterpret_cast<const char*>(sqlite3_column_text(stmt, 7)));
|
||||
header.folder = std::u16string(std::begin(tmp), std::end(tmp));
|
||||
|
||||
tmp = std::string(reinterpret_cast<const char*>(sqlite3_column_text(stmt, 8)));
|
||||
header.category = std::u16string(std::begin(tmp), std::end(tmp));
|
||||
|
||||
headers.push_back(std::move(header));
|
||||
}
|
||||
|
||||
return headers;
|
||||
}
|
||||
|
||||
PersistentMessage PersistentMessageService::GetPersistentMessage(
|
||||
uint32_t avatarId, uint32_t messageId) {
|
||||
sqlite3_stmt* stmt;
|
||||
|
||||
char sql[] = "SELECT id, avatar_id, from_name, from_address, subject, sent_time, status, "
|
||||
"folder, category, message, oob FROM persistent_message WHERE id = @message_id "
|
||||
"AND avatar_id = @avatar_id";
|
||||
|
||||
auto result = sqlite3_prepare_v2(db_, sql, -1, &stmt, 0);
|
||||
if (result != SQLITE_OK) {
|
||||
throw SQLite3Exception{result, sqlite3_errmsg(db_)};
|
||||
}
|
||||
|
||||
int messageIdIdx = sqlite3_bind_parameter_index(stmt, "@message_id");
|
||||
int avatarIdIdx = sqlite3_bind_parameter_index(stmt, "@avatar_id");
|
||||
|
||||
sqlite3_bind_int(stmt, messageIdIdx, messageId);
|
||||
sqlite3_bind_int(stmt, avatarIdIdx, avatarId);
|
||||
|
||||
if (sqlite3_step(stmt) != SQLITE_ROW) {
|
||||
throw ChatResultException{ChatResultCode::PMSGNOTFOUND};
|
||||
}
|
||||
|
||||
std::string tmp;
|
||||
|
||||
PersistentMessage message;
|
||||
message.header.messageId = messageId;
|
||||
message.header.avatarId = avatarId;
|
||||
|
||||
tmp = std::string(reinterpret_cast<const char*>(sqlite3_column_text(stmt, 2)));
|
||||
message.header.fromName = std::u16string(std::begin(tmp), std::end(tmp));
|
||||
|
||||
tmp = std::string(reinterpret_cast<const char*>(sqlite3_column_text(stmt, 3)));
|
||||
message.header.fromAddress = std::u16string(std::begin(tmp), std::end(tmp));
|
||||
|
||||
tmp = std::string(reinterpret_cast<const char*>(sqlite3_column_text(stmt, 4)));
|
||||
message.header.subject = std::u16string(std::begin(tmp), std::end(tmp));
|
||||
|
||||
message.header.sentTime = sqlite3_column_int(stmt, 5);
|
||||
message.header.status = static_cast<PersistentState>(sqlite3_column_int(stmt, 6));
|
||||
|
||||
tmp = std::string(reinterpret_cast<const char*>(sqlite3_column_text(stmt, 7)));
|
||||
message.header.folder = std::u16string(std::begin(tmp), std::end(tmp));
|
||||
|
||||
tmp = std::string(reinterpret_cast<const char*>(sqlite3_column_text(stmt, 8)));
|
||||
message.header.category = std::u16string(std::begin(tmp), std::end(tmp));
|
||||
|
||||
tmp = std::string(reinterpret_cast<const char*>(sqlite3_column_text(stmt, 9)));
|
||||
message.message = std::u16string(std::begin(tmp), std::end(tmp));
|
||||
|
||||
int size = sqlite3_column_bytes(stmt, 10);
|
||||
const uint8_t* data = reinterpret_cast<const uint8_t*>(sqlite3_column_blob(stmt, 10));
|
||||
|
||||
message.oob.resize(size / 2);
|
||||
for (int i = 0; i < size/2; ++i) {
|
||||
message.oob[i] = *reinterpret_cast<const uint16_t*>(data + i*2);
|
||||
}
|
||||
|
||||
sqlite3_finalize(stmt);
|
||||
|
||||
if (message.header.status == PersistentState::NEW) {
|
||||
UpdateMessageStatus(
|
||||
message.header.avatarId, message.header.messageId, PersistentState::READ);
|
||||
}
|
||||
|
||||
return message;
|
||||
}
|
||||
|
||||
void PersistentMessageService::UpdateMessageStatus(
|
||||
uint32_t avatarId, uint32_t messageId, PersistentState status) {
|
||||
sqlite3_stmt* stmt;
|
||||
|
||||
char sql[] = "UPDATE persistent_message SET status = @status WHERE id = @message_id AND "
|
||||
"avatar_id = @avatar_id";
|
||||
|
||||
auto result = sqlite3_prepare_v2(db_, sql, -1, &stmt, 0);
|
||||
if (result != SQLITE_OK) {
|
||||
throw SQLite3Exception{result, sqlite3_errmsg(db_)};
|
||||
}
|
||||
|
||||
int statusIdx = sqlite3_bind_parameter_index(stmt, "@status");
|
||||
int messageIdIdx = sqlite3_bind_parameter_index(stmt, "@message_id");
|
||||
int avatarIdIdx = sqlite3_bind_parameter_index(stmt, "@avatar_id");
|
||||
|
||||
sqlite3_bind_int(stmt, statusIdx, static_cast<uint32_t>(status));
|
||||
sqlite3_bind_int(stmt, messageIdIdx, messageId);
|
||||
sqlite3_bind_int(stmt, avatarIdIdx, avatarId);
|
||||
|
||||
result = sqlite3_step(stmt);
|
||||
if (result != SQLITE_DONE) {
|
||||
throw SQLite3Exception{result, sqlite3_errmsg(db_)};
|
||||
}
|
||||
|
||||
sqlite3_finalize(stmt);
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "ChatEnums.hpp"
|
||||
#include "PersistentMessage.hpp"
|
||||
|
||||
#include <boost/optional.hpp>
|
||||
|
||||
#include <cstdint>
|
||||
#include <vector>
|
||||
|
||||
struct sqlite3;
|
||||
|
||||
class PersistentMessageService {
|
||||
public:
|
||||
explicit PersistentMessageService(sqlite3* db);
|
||||
~PersistentMessageService();
|
||||
|
||||
void StoreMessage(PersistentMessage& message);
|
||||
|
||||
std::vector<PersistentHeader> GetMessageHeaders(uint32_t avatarId);
|
||||
|
||||
PersistentMessage GetPersistentMessage(uint32_t avatarId, uint32_t messageId);
|
||||
|
||||
void UpdateMessageStatus(
|
||||
uint32_t avatarId, uint32_t messageId, PersistentState status);
|
||||
|
||||
private:
|
||||
sqlite3* db_;
|
||||
};
|
||||
@@ -0,0 +1,45 @@
|
||||
#include "RegistrarClient.hpp"
|
||||
|
||||
#include "ChatEnums.hpp"
|
||||
#include "RegistrarNode.hpp"
|
||||
#include "Serialization.hpp"
|
||||
#include "StationChatConfig.hpp"
|
||||
#include "StringUtils.hpp"
|
||||
|
||||
#include "protocol/RegistrarGetChatServer.hpp"
|
||||
|
||||
#include "easylogging++.h"
|
||||
|
||||
RegistrarClient::RegistrarClient(UdpConnection* connection, RegistrarNode* node)
|
||||
: NodeClient(connection)
|
||||
, node_{node} {
|
||||
connection->SetHandler(this);
|
||||
}
|
||||
|
||||
RegistrarClient::~RegistrarClient() {}
|
||||
|
||||
RegistrarNode* RegistrarClient::GetNode() { return node_; }
|
||||
|
||||
void RegistrarClient::OnIncoming(std::istringstream& istream) {
|
||||
ChatRequestType request_type = ::read<ChatRequestType>(istream);
|
||||
|
||||
switch (request_type) {
|
||||
case ChatRequestType::REGISTRAR_GETCHATSERVER: {
|
||||
auto request = ::read<ReqRegistrarGetChatServer>(istream);
|
||||
RegistrarGetChatServer::ResponseType response{request.track};
|
||||
|
||||
try {
|
||||
RegistrarGetChatServer(this, request, response);
|
||||
} catch (const ChatResultException& e) {
|
||||
response.result = e.code;
|
||||
LOG(ERROR) << "ChatAPI Error: [" << static_cast<uint32_t>(e.code) << "] " << e.message;
|
||||
}
|
||||
|
||||
Send(response);
|
||||
} break;
|
||||
default:
|
||||
LOG(ERROR) << "Invalid registrar message type received: "
|
||||
<< static_cast<uint16_t>(request_type);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "NodeClient.hpp"
|
||||
|
||||
class RegistrarNode;
|
||||
class UdpConnection;
|
||||
|
||||
struct ReqRegistrarGetChatServer;
|
||||
|
||||
class RegistrarClient : public NodeClient {
|
||||
public:
|
||||
RegistrarClient(UdpConnection* connection, RegistrarNode* node);
|
||||
virtual ~RegistrarClient();
|
||||
|
||||
RegistrarNode* GetNode();
|
||||
|
||||
private:
|
||||
void OnIncoming(std::istringstream& istream) override;
|
||||
|
||||
RegistrarNode* node_;
|
||||
};
|
||||
@@ -0,0 +1,17 @@
|
||||
|
||||
#include "RegistrarNode.hpp"
|
||||
|
||||
#include "StationChatConfig.hpp"
|
||||
|
||||
RegistrarNode::RegistrarNode(StationChatConfig& config)
|
||||
: Node(this, config.registrarAddress, config.registrarPort)
|
||||
, config_{config} {}
|
||||
|
||||
RegistrarNode::~RegistrarNode() {}
|
||||
|
||||
StationChatConfig& RegistrarNode::GetConfig() {
|
||||
return config_;
|
||||
}
|
||||
|
||||
void RegistrarNode::OnTick() {}
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Node.hpp"
|
||||
#include "RegistrarClient.hpp"
|
||||
|
||||
struct StationChatConfig;
|
||||
|
||||
class RegistrarNode : public Node<RegistrarNode, RegistrarClient> {
|
||||
public:
|
||||
explicit RegistrarNode(StationChatConfig& config);
|
||||
~RegistrarNode();
|
||||
|
||||
StationChatConfig& GetConfig();
|
||||
|
||||
private:
|
||||
void OnTick() override;
|
||||
|
||||
StationChatConfig& config_;
|
||||
};
|
||||
@@ -0,0 +1,17 @@
|
||||
#include "StationChatApp.hpp"
|
||||
|
||||
#include "easylogging++.h"
|
||||
|
||||
StationChatApp::StationChatApp(StationChatConfig config)
|
||||
: config_{std::move(config)} {
|
||||
registrarNode_ = std::make_unique<RegistrarNode>(config_);
|
||||
LOG(INFO) << "Registrar listening @" << config_.registrarAddress << ":" << config_.registrarPort;
|
||||
|
||||
gatewayNode_ = std::make_unique<GatewayNode>(config_);
|
||||
LOG(INFO) << "Gateway listening @" << config_.gatewayAddress << ":" << config_.gatewayPort;
|
||||
}
|
||||
|
||||
void StationChatApp::Tick() {
|
||||
registrarNode_->Tick();
|
||||
gatewayNode_->Tick();
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "GatewayNode.hpp"
|
||||
#include "RegistrarNode.hpp"
|
||||
#include "StationChatConfig.hpp"
|
||||
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
class StationChatApp {
|
||||
public:
|
||||
explicit StationChatApp(StationChatConfig config);
|
||||
|
||||
bool IsRunning() const { return isRunning_; }
|
||||
|
||||
void Tick();
|
||||
|
||||
private:
|
||||
StationChatConfig config_;
|
||||
bool isRunning_ = true;
|
||||
std::unique_ptr<GatewayNode> gatewayNode_;
|
||||
std::unique_ptr<RegistrarNode> registrarNode_;
|
||||
};
|
||||
@@ -0,0 +1,24 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
|
||||
struct StationChatConfig {
|
||||
StationChatConfig() = default;
|
||||
StationChatConfig(const std::string& gatewayAddress_, uint16_t gatewayPort_,
|
||||
const std::string& registrarAddress_, uint16_t registrarPort_, const std::string& chatDatabasePath_)
|
||||
: gatewayAddress{gatewayAddress_}
|
||||
, gatewayPort{gatewayPort_}
|
||||
, registrarAddress{registrarAddress_}
|
||||
, registrarPort{registrarPort_}
|
||||
, chatDatabasePath{chatDatabasePath_} {}
|
||||
|
||||
const uint32_t version = 2;
|
||||
std::string gatewayAddress;
|
||||
uint16_t gatewayPort;
|
||||
std::string registrarAddress;
|
||||
uint16_t registrarPort;
|
||||
std::string chatDatabasePath;
|
||||
std::string loggerConfig;
|
||||
};
|
||||
@@ -0,0 +1,115 @@
|
||||
|
||||
|
||||
#define ELPP_DISABLE_DEFAULT_CRASH_HANDLING 1
|
||||
#define ELPP_DEFAULT_LOG_FILE "logs/swgchat.log"
|
||||
|
||||
#include "easylogging++.h"
|
||||
|
||||
#include "StationChatApp.hpp"
|
||||
|
||||
#include <boost/program_options.hpp>
|
||||
|
||||
#include <chrono>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <thread>
|
||||
|
||||
#ifdef __GNUC__
|
||||
#include <execinfo.h>
|
||||
#endif
|
||||
|
||||
INITIALIZE_EASYLOGGINGPP
|
||||
|
||||
StationChatConfig BuildConfiguration(int argc, char* argv[]);
|
||||
|
||||
#ifdef __GNUC__
|
||||
void SignalHandler(int sig);
|
||||
#endif
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
#ifdef __GNUC__
|
||||
signal(SIGSEGV, SignalHandler);
|
||||
#endif
|
||||
|
||||
auto config = BuildConfiguration(argc, argv);
|
||||
|
||||
el::Loggers::setDefaultConfigurations(config.loggerConfig, true);
|
||||
START_EASYLOGGINGPP(argc, argv);
|
||||
|
||||
StationChatApp app{config};
|
||||
|
||||
while (app.IsRunning()) {
|
||||
app.Tick();
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(1));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
StationChatConfig BuildConfiguration(int argc, char* argv[]) {
|
||||
namespace po = boost::program_options;
|
||||
StationChatConfig config;
|
||||
std::string configFile;
|
||||
|
||||
// Declare a group of options that will be
|
||||
// allowed only on command line
|
||||
po::options_description generic("Generic options");
|
||||
generic.add_options()
|
||||
("help,h", "produces help message")
|
||||
("config,c", po::value<std::string>(&configFile)->default_value("swgchat.cfg"),
|
||||
"sets path to the configuration file")
|
||||
("logger_config", po::value<std::string>(&config.loggerConfig)->default_value("logger.cfg"),
|
||||
"sets path to the logger configuration file")
|
||||
;
|
||||
|
||||
po::options_description options("Configuration");
|
||||
options.add_options()
|
||||
("gateway_address", po::value<std::string>(&config.gatewayAddress)->default_value("127.0.0.1"),
|
||||
"address for gateway connections")
|
||||
("gateway_port", po::value<uint16_t>(&config.gatewayPort)->default_value(5001),
|
||||
"port for gateway connections")
|
||||
("registrar_address", po::value<std::string>(&config.registrarAddress)->default_value("127.0.0.1"),
|
||||
"address for registrar connections")
|
||||
("registrar_port", po::value<uint16_t>(&config.registrarPort)->default_value(5000),
|
||||
"port for registrar connections")
|
||||
("database_path", po::value<std::string>(&config.chatDatabasePath)->default_value("chat.db"),
|
||||
"path to the sqlite3 database file")
|
||||
;
|
||||
|
||||
po::options_description cmdline_options;
|
||||
cmdline_options.add(generic).add(options);
|
||||
|
||||
po::options_description config_file_options;
|
||||
config_file_options.add(options);
|
||||
|
||||
po::variables_map vm;
|
||||
po::store(po::command_line_parser(argc, argv).options(cmdline_options).allow_unregistered().run(), vm);
|
||||
po::notify(vm);
|
||||
|
||||
std::ifstream ifs(configFile.c_str());
|
||||
if (!ifs) {
|
||||
throw std::runtime_error("Cannot open configuration file: " + configFile);
|
||||
}
|
||||
|
||||
po::store(po::parse_config_file(ifs, config_file_options), vm);
|
||||
po::notify(vm);
|
||||
|
||||
if (vm.count("help")) {
|
||||
std::cout << cmdline_options << "\n";
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
return config;
|
||||
}
|
||||
|
||||
#ifdef __GNUC__
|
||||
void SignalHandler(int sig) {
|
||||
const int BACKTRACE_LIMIT = 10;
|
||||
void *arr[BACKTRACE_LIMIT];
|
||||
auto size = backtrace(arr, BACKTRACE_LIMIT);
|
||||
|
||||
fprintf(stderr, "Error: signal %d:\n", sig);
|
||||
backtrace_symbols_fd(arr, size, STDERR_FILENO);
|
||||
exit(1);
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,63 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "ChatEnums.hpp"
|
||||
|
||||
class ChatAvatarService;
|
||||
class ChatRoomService;
|
||||
class GatewayClient;
|
||||
|
||||
/** Begin ADDBAN */
|
||||
|
||||
struct ReqAddBan {
|
||||
const ChatRequestType type = ChatRequestType::ADDBAN;
|
||||
uint32_t track;
|
||||
uint32_t srcAvatarId;
|
||||
std::u16string destAvatarName;
|
||||
std::u16string destAvatarAddress;
|
||||
std::u16string destRoomAddress;
|
||||
std::u16string srcAddress;
|
||||
};
|
||||
|
||||
template <typename StreamT>
|
||||
void read(StreamT& ar, ReqAddBan& data) {
|
||||
read(ar, data.track);
|
||||
read(ar, data.srcAvatarId);
|
||||
read(ar, data.destAvatarName);
|
||||
read(ar, data.destAvatarAddress);
|
||||
read(ar, data.destRoomAddress);
|
||||
read(ar, data.srcAddress);
|
||||
}
|
||||
|
||||
/** Begin ADDBAN */
|
||||
|
||||
struct ResAddBan {
|
||||
explicit ResAddBan(uint32_t track_)
|
||||
: track{track_}
|
||||
, result{ChatResultCode::SUCCESS} {}
|
||||
|
||||
const ChatResponseType type = ChatResponseType::ADDBAN;
|
||||
uint32_t track;
|
||||
ChatResultCode result;
|
||||
uint32_t destRoomId;
|
||||
};
|
||||
|
||||
template <typename StreamT>
|
||||
void write(StreamT& ar, const ResAddBan& data) {
|
||||
write(ar, data.type);
|
||||
write(ar, data.track);
|
||||
write(ar, data.result);
|
||||
write(ar, data.destRoomId);
|
||||
}
|
||||
|
||||
class AddBan {
|
||||
public:
|
||||
using RequestType = ReqAddBan;
|
||||
using ResponseType = ResAddBan;
|
||||
|
||||
AddBan(GatewayClient* client, const RequestType& request, ResponseType& response);
|
||||
|
||||
private:
|
||||
ChatAvatarService* avatarService_;
|
||||
ChatRoomService* roomService_;
|
||||
};
|
||||
@@ -0,0 +1,62 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "ChatEnums.hpp"
|
||||
|
||||
class ChatAvatarService;
|
||||
class ChatRoomService;
|
||||
class GatewayClient;
|
||||
|
||||
/** Begin ADDFRIEND */
|
||||
|
||||
struct ReqAddFriend {
|
||||
const ChatRequestType type = ChatRequestType::ADDFRIEND;
|
||||
uint32_t track;
|
||||
uint32_t srcAvatarId;
|
||||
std::u16string destName;
|
||||
std::u16string destAddress;
|
||||
std::u16string comment;
|
||||
bool confirm;
|
||||
std::u16string srcAddress;
|
||||
};
|
||||
|
||||
template <typename StreamT>
|
||||
void read(StreamT& ar, ReqAddFriend& data) {
|
||||
read(ar, data.track);
|
||||
read(ar, data.srcAvatarId);
|
||||
read(ar, data.destName);
|
||||
read(ar, data.destAddress);
|
||||
read(ar, data.comment);
|
||||
read(ar, data.confirm);
|
||||
read(ar, data.srcAddress);
|
||||
}
|
||||
|
||||
/** Begin ADDFRIEND */
|
||||
|
||||
struct ResAddFriend {
|
||||
ResAddFriend(uint32_t track_)
|
||||
: track{track_}
|
||||
, result{ChatResultCode::SUCCESS} {}
|
||||
|
||||
const ChatResponseType type = ChatResponseType::ADDFRIEND;
|
||||
uint32_t track;
|
||||
ChatResultCode result;
|
||||
};
|
||||
|
||||
template <typename StreamT>
|
||||
void write(StreamT& ar, const ResAddFriend& data) {
|
||||
write(ar, data.type);
|
||||
write(ar, data.track);
|
||||
write(ar, data.result);
|
||||
}
|
||||
|
||||
class AddFriend {
|
||||
public:
|
||||
using RequestType = ReqAddFriend;
|
||||
using ResponseType = ResAddFriend;
|
||||
|
||||
AddFriend(GatewayClient* client, const RequestType& request, ResponseType& response);
|
||||
|
||||
private:
|
||||
ChatAvatarService* avatarService_;
|
||||
};
|
||||
@@ -0,0 +1,58 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "ChatEnums.hpp"
|
||||
|
||||
class ChatAvatarService;
|
||||
class ChatRoomService;
|
||||
class GatewayClient;
|
||||
|
||||
/** Begin ADDIGNORE */
|
||||
|
||||
struct ReqAddIgnore {
|
||||
const ChatRequestType type = ChatRequestType::ADDIGNORE;
|
||||
uint32_t track;
|
||||
uint32_t srcAvatarId;
|
||||
std::u16string destName;
|
||||
std::u16string destAddress;
|
||||
std::u16string srcAddress;
|
||||
};
|
||||
|
||||
template <typename StreamT>
|
||||
void read(StreamT& ar, ReqAddIgnore& data) {
|
||||
read(ar, data.track);
|
||||
read(ar, data.srcAvatarId);
|
||||
read(ar, data.destName);
|
||||
read(ar, data.destAddress);
|
||||
read(ar, data.srcAddress);
|
||||
}
|
||||
|
||||
/** Begin ADDIGNORE */
|
||||
|
||||
struct ResAddIgnore {
|
||||
ResAddIgnore(uint32_t track_)
|
||||
: track{track_}
|
||||
, result{ChatResultCode::SUCCESS} {}
|
||||
|
||||
const ChatResponseType type = ChatResponseType::ADDIGNORE;
|
||||
uint32_t track;
|
||||
ChatResultCode result;
|
||||
};
|
||||
|
||||
template <typename StreamT>
|
||||
void write(StreamT& ar, const ResAddIgnore& data) {
|
||||
write(ar, data.type);
|
||||
write(ar, data.track);
|
||||
write(ar, data.result);
|
||||
}
|
||||
|
||||
class AddIgnore {
|
||||
public:
|
||||
using RequestType = ReqAddIgnore;
|
||||
using ResponseType = ResAddIgnore;
|
||||
|
||||
AddIgnore(GatewayClient* client, const RequestType& request, ResponseType& response);
|
||||
|
||||
private:
|
||||
ChatAvatarService* avatarService_;
|
||||
};
|
||||
@@ -0,0 +1,63 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "ChatEnums.hpp"
|
||||
|
||||
class ChatAvatarService;
|
||||
class ChatRoomService;
|
||||
class GatewayClient;
|
||||
|
||||
/** Begin ADDINVITE */
|
||||
|
||||
struct ReqAddInvite {
|
||||
const ChatRequestType type = ChatRequestType::ADDINVITE;
|
||||
uint32_t track;
|
||||
uint32_t srcAvatarId;
|
||||
std::u16string destAvatarName;
|
||||
std::u16string destAvatarAddress;
|
||||
std::u16string destRoomAddress;
|
||||
std::u16string srcAddress;
|
||||
};
|
||||
|
||||
template <typename StreamT>
|
||||
void read(StreamT& ar, ReqAddInvite& data) {
|
||||
read(ar, data.track);
|
||||
read(ar, data.srcAvatarId);
|
||||
read(ar, data.destAvatarName);
|
||||
read(ar, data.destAvatarAddress);
|
||||
read(ar, data.destRoomAddress);
|
||||
read(ar, data.srcAddress);
|
||||
}
|
||||
|
||||
/** Begin ADDINVITE */
|
||||
|
||||
struct ResAddInvite {
|
||||
explicit ResAddInvite(uint32_t track_)
|
||||
: track{track_}
|
||||
, result{ChatResultCode::SUCCESS} {}
|
||||
|
||||
const ChatResponseType type = ChatResponseType::ADDINVITE;
|
||||
uint32_t track;
|
||||
ChatResultCode result;
|
||||
uint32_t destRoomId;
|
||||
};
|
||||
|
||||
template <typename StreamT>
|
||||
void write(StreamT& ar, const ResAddInvite& data) {
|
||||
write(ar, data.type);
|
||||
write(ar, data.track);
|
||||
write(ar, data.result);
|
||||
write(ar, data.destRoomId);
|
||||
}
|
||||
|
||||
class AddInvite {
|
||||
public:
|
||||
using RequestType = ReqAddInvite;
|
||||
using ResponseType = ResAddInvite;
|
||||
|
||||
AddInvite(GatewayClient* client, const RequestType& request, ResponseType& response);
|
||||
|
||||
private:
|
||||
ChatAvatarService* avatarService_;
|
||||
ChatRoomService* roomService_;
|
||||
};
|
||||
@@ -0,0 +1,63 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "ChatEnums.hpp"
|
||||
|
||||
class ChatAvatarService;
|
||||
class ChatRoomService;
|
||||
class GatewayClient;
|
||||
|
||||
/** Begin ADDMODERATOR */
|
||||
|
||||
struct ReqAddModerator {
|
||||
const ChatRequestType type = ChatRequestType::ADDMODERATOR;
|
||||
uint32_t track;
|
||||
uint32_t srcAvatarId;
|
||||
std::u16string destAvatarName;
|
||||
std::u16string destAvatarAddress;
|
||||
std::u16string destRoomAddress;
|
||||
std::u16string srcAddress;
|
||||
};
|
||||
|
||||
template <typename StreamT>
|
||||
void read(StreamT& ar, ReqAddModerator& data) {
|
||||
read(ar, data.track);
|
||||
read(ar, data.srcAvatarId);
|
||||
read(ar, data.destAvatarName);
|
||||
read(ar, data.destAvatarAddress);
|
||||
read(ar, data.destRoomAddress);
|
||||
read(ar, data.srcAddress);
|
||||
}
|
||||
|
||||
/** Begin ADDMODERATOR */
|
||||
|
||||
struct ResAddModerator {
|
||||
ResAddModerator(uint32_t track_)
|
||||
: track{track_}
|
||||
, result{ChatResultCode::SUCCESS} {}
|
||||
|
||||
const ChatResponseType type = ChatResponseType::ADDMODERATOR;
|
||||
uint32_t track;
|
||||
ChatResultCode result;
|
||||
uint32_t destRoomId;
|
||||
};
|
||||
|
||||
template <typename StreamT>
|
||||
void write(StreamT& ar, const ResAddModerator& data) {
|
||||
write(ar, data.type);
|
||||
write(ar, data.track);
|
||||
write(ar, data.result);
|
||||
write(ar, data.destRoomId);
|
||||
}
|
||||
|
||||
class AddModerator {
|
||||
public:
|
||||
using RequestType = ReqAddModerator;
|
||||
using ResponseType = ResAddModerator;
|
||||
|
||||
AddModerator(GatewayClient* client, const RequestType& request, ResponseType& response);
|
||||
|
||||
private:
|
||||
ChatAvatarService* avatarService_;
|
||||
ChatRoomService* roomService_;
|
||||
};
|
||||
@@ -0,0 +1,83 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "ChatEnums.hpp"
|
||||
#include "ChatRoom.hpp"
|
||||
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
class ChatAvatarService;
|
||||
class ChatRoomService;
|
||||
class GatewayClient;
|
||||
|
||||
/** Begin CREATEROOM */
|
||||
|
||||
struct ReqCreateRoom {
|
||||
const ChatRequestType type = ChatRequestType::CREATEROOM;
|
||||
uint32_t track;
|
||||
uint32_t creatorId;
|
||||
std::u16string roomName;
|
||||
std::u16string roomTopic;
|
||||
std::u16string roomPassword;
|
||||
uint32_t roomAttributes;
|
||||
uint32_t roomMaxSize;
|
||||
std::u16string roomAddress;
|
||||
std::u16string srcAddress;
|
||||
};
|
||||
|
||||
template <typename StreamT>
|
||||
void read(StreamT& ar, ReqCreateRoom& data) {
|
||||
read(ar, data.track);
|
||||
read(ar, data.creatorId);
|
||||
read(ar, data.roomName);
|
||||
read(ar, data.roomTopic);
|
||||
read(ar, data.roomPassword);
|
||||
read(ar, data.roomAttributes);
|
||||
read(ar, data.roomMaxSize);
|
||||
read(ar, data.roomAddress);
|
||||
read(ar, data.srcAddress);
|
||||
}
|
||||
|
||||
/** Begin CREATEROOM */
|
||||
|
||||
struct ResCreateRoom {
|
||||
explicit ResCreateRoom(uint32_t track_)
|
||||
: track{track_}
|
||||
, result{ChatResultCode::SUCCESS} {}
|
||||
|
||||
const ChatResponseType type = ChatResponseType::CREATEROOM;
|
||||
uint32_t track;
|
||||
ChatResultCode result;
|
||||
ChatRoom* room;
|
||||
std::vector<ChatRoom*> extraRooms;
|
||||
};
|
||||
|
||||
template <typename StreamT>
|
||||
void write(StreamT& ar, const ResCreateRoom& data) {
|
||||
write(ar, data.type);
|
||||
write(ar, data.track);
|
||||
write(ar, data.result);
|
||||
|
||||
if (data.result == ChatResultCode::SUCCESS) {
|
||||
write(ar, *data.room);
|
||||
|
||||
write(ar, static_cast<uint32_t>(data.extraRooms.size()));
|
||||
for (auto room : data.extraRooms) {
|
||||
write(ar, *room);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class CreateRoom {
|
||||
public:
|
||||
using RequestType = ReqCreateRoom;
|
||||
using ResponseType = ResCreateRoom;
|
||||
|
||||
CreateRoom(GatewayClient* client, const RequestType& request, ResponseType& response);
|
||||
|
||||
private:
|
||||
ChatAvatarService* avatarService_;
|
||||
ChatRoomService* roomService_;
|
||||
};
|
||||
@@ -0,0 +1,55 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "ChatEnums.hpp"
|
||||
|
||||
class ChatAvatarService;
|
||||
class ChatRoomService;
|
||||
class GatewayClient;
|
||||
|
||||
/** Begin DESTROYAVATAR */
|
||||
|
||||
struct ReqDestroyAvatar {
|
||||
const ChatRequestType type = ChatRequestType::LOGOUTAVATAR;
|
||||
uint32_t track;
|
||||
uint32_t avatarId;
|
||||
std::u16string address;
|
||||
};
|
||||
|
||||
template <typename StreamT>
|
||||
void read(StreamT& ar, ReqDestroyAvatar& data) {
|
||||
read(ar, data.track);
|
||||
read(ar, data.avatarId);
|
||||
read(ar, data.address);
|
||||
}
|
||||
|
||||
/** Begin DESTROYAVATAR */
|
||||
|
||||
struct ResDestroyAvatar {
|
||||
explicit ResDestroyAvatar(uint32_t track_)
|
||||
: track{track_}
|
||||
, result{ChatResultCode::SUCCESS} {}
|
||||
|
||||
const ChatResponseType type = ChatResponseType::DESTROYAVATAR;
|
||||
uint32_t track;
|
||||
ChatResultCode result;
|
||||
};
|
||||
|
||||
template <typename StreamT>
|
||||
void write(StreamT& ar, const ResDestroyAvatar& data) {
|
||||
write(ar, data.type);
|
||||
write(ar, data.track);
|
||||
write(ar, data.result);
|
||||
}
|
||||
|
||||
class DestroyAvatar {
|
||||
public:
|
||||
using RequestType = ReqDestroyAvatar;
|
||||
using ResponseType = ResDestroyAvatar;
|
||||
|
||||
DestroyAvatar(GatewayClient* client, const RequestType& request, ResponseType& response);
|
||||
|
||||
private:
|
||||
ChatAvatarService* avatarService_;
|
||||
ChatRoomService* roomService_;
|
||||
};
|
||||
@@ -0,0 +1,59 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "ChatEnums.hpp"
|
||||
|
||||
class ChatAvatarService;
|
||||
class ChatRoomService;
|
||||
class GatewayClient;
|
||||
|
||||
/** Begin DESTROYROOM */
|
||||
|
||||
struct ReqDestroyRoom {
|
||||
const ChatRequestType type = ChatRequestType::DESTROYROOM;
|
||||
uint32_t track;
|
||||
uint32_t srcAvatarId;
|
||||
std::u16string roomAddress;
|
||||
std::u16string srcAddress;
|
||||
};
|
||||
|
||||
template <typename StreamT>
|
||||
void read(StreamT& ar, ReqDestroyRoom& data) {
|
||||
read(ar, data.track);
|
||||
read(ar, data.srcAvatarId);
|
||||
read(ar, data.roomAddress);
|
||||
read(ar, data.srcAddress);
|
||||
}
|
||||
|
||||
/** Begin DESTROYROOM */
|
||||
|
||||
struct ResDestroyRoom {
|
||||
explicit ResDestroyRoom(uint32_t track_)
|
||||
: track{track_}
|
||||
, result{ChatResultCode::SUCCESS} {}
|
||||
|
||||
const ChatResponseType type = ChatResponseType::DESTROYROOM;
|
||||
uint32_t track;
|
||||
ChatResultCode result;
|
||||
uint32_t roomId;
|
||||
};
|
||||
|
||||
template <typename StreamT>
|
||||
void write(StreamT& ar, const ResDestroyRoom& data) {
|
||||
write(ar, data.type);
|
||||
write(ar, data.track);
|
||||
write(ar, data.result);
|
||||
write(ar, data.roomId);
|
||||
}
|
||||
|
||||
class DestroyRoom {
|
||||
public:
|
||||
using RequestType = ReqDestroyRoom;
|
||||
using ResponseType = ResDestroyRoom;
|
||||
|
||||
DestroyRoom(GatewayClient* client, const RequestType& request, ResponseType& response);
|
||||
|
||||
private:
|
||||
ChatAvatarService* avatarService_;
|
||||
ChatRoomService* roomService_;
|
||||
};
|
||||
@@ -0,0 +1,89 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "ChatEnums.hpp"
|
||||
#include "ChatRoom.hpp"
|
||||
|
||||
class ChatAvatarService;
|
||||
class ChatRoomService;
|
||||
class GatewayClient;
|
||||
|
||||
/** Begin ENTERROOM */
|
||||
|
||||
struct ReqEnterRoom {
|
||||
const ChatRequestType type = ChatRequestType::ENTERROOM;
|
||||
uint32_t track;
|
||||
uint32_t srcAvatarId;
|
||||
std::u16string roomAddress;
|
||||
std::u16string roomPassword;
|
||||
bool passiveCreate;
|
||||
std::u16string paramRoomTopic;
|
||||
uint32_t paramRoomAttributes;
|
||||
uint32_t paramRoomMaxSize;
|
||||
bool requestingEntry;
|
||||
std::u16string srcAddress;
|
||||
};
|
||||
|
||||
template <typename StreamT>
|
||||
void read(StreamT& ar, ReqEnterRoom& data) {
|
||||
read(ar, data.track);
|
||||
read(ar, data.srcAvatarId);
|
||||
read(ar, data.roomAddress);
|
||||
read(ar, data.roomPassword);
|
||||
read(ar, data.passiveCreate);
|
||||
|
||||
if (data.passiveCreate) {
|
||||
read(ar, data.paramRoomTopic);
|
||||
read(ar, data.paramRoomAttributes);
|
||||
read(ar, data.paramRoomMaxSize);
|
||||
}
|
||||
|
||||
read(ar, data.requestingEntry);
|
||||
read(ar, data.srcAddress);
|
||||
}
|
||||
|
||||
/** Begin ENTERROOM */
|
||||
|
||||
struct ResEnterRoom {
|
||||
ResEnterRoom(uint32_t track_)
|
||||
: track{track_}
|
||||
, result{ChatResultCode::SUCCESS} {}
|
||||
|
||||
const ChatResponseType type = ChatResponseType::ENTERROOM;
|
||||
uint32_t track;
|
||||
ChatResultCode result;
|
||||
uint32_t roomId;
|
||||
bool gotRoomObj = false;
|
||||
ChatRoom* room = nullptr;
|
||||
std::vector<ChatRoom*> extraRooms;
|
||||
};
|
||||
|
||||
template <typename StreamT>
|
||||
void write(StreamT& ar, const ResEnterRoom& data) {
|
||||
write(ar, data.type);
|
||||
write(ar, data.track);
|
||||
write(ar, data.result);
|
||||
write(ar, data.roomId);
|
||||
write(ar, data.gotRoomObj);
|
||||
|
||||
if (data.gotRoomObj) {
|
||||
write(ar, *data.room);
|
||||
|
||||
write(ar, static_cast<uint32_t>(data.extraRooms.size()));
|
||||
for (auto room : data.extraRooms) {
|
||||
write(ar, *room);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class EnterRoom {
|
||||
public:
|
||||
using RequestType = ReqEnterRoom;
|
||||
using ResponseType = ResEnterRoom;
|
||||
|
||||
EnterRoom(GatewayClient* client, const RequestType& request, ResponseType& response);
|
||||
|
||||
private:
|
||||
ChatAvatarService* avatarService_;
|
||||
ChatRoomService* roomService_;
|
||||
};
|
||||
@@ -0,0 +1,64 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "ChatEnums.hpp"
|
||||
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
|
||||
class ChatAvatarService;
|
||||
class ChatRoomService;
|
||||
class GatewayClient;
|
||||
|
||||
struct ReqFailoverReLoginAvatar{
|
||||
const ChatRequestType type = ChatRequestType::FAILOVER_RELOGINAVATAR;
|
||||
uint32_t track;
|
||||
uint32_t avatarId;
|
||||
uint32_t userId;
|
||||
std::u16string name;
|
||||
std::u16string address;
|
||||
std::u16string loginLocation;
|
||||
int32_t loginPriority;
|
||||
uint32_t attributes;
|
||||
};
|
||||
|
||||
struct ResFailoverReLoginAvatar {
|
||||
ResFailoverReLoginAvatar(uint32_t track_)
|
||||
: track{track_}
|
||||
, result{ChatResultCode::SUCCESS} {}
|
||||
|
||||
const ChatResponseType type = ChatResponseType::FAILOVER_RELOGINAVATAR;
|
||||
uint32_t track;
|
||||
ChatResultCode result;
|
||||
};
|
||||
|
||||
class FailoverReLoginAvatar {
|
||||
public:
|
||||
using RequestType = ReqFailoverReLoginAvatar;
|
||||
using ResponseType = ResFailoverReLoginAvatar;
|
||||
|
||||
FailoverReLoginAvatar(GatewayClient* client, const RequestType& request, ResponseType& response);
|
||||
|
||||
private:
|
||||
ChatAvatarService* avatarService_;
|
||||
ChatRoomService* roomService_;
|
||||
};
|
||||
|
||||
template <typename StreamT>
|
||||
void read(StreamT& ar, ReqFailoverReLoginAvatar& data) {
|
||||
read(ar, data.track);
|
||||
read(ar, data.avatarId);
|
||||
read(ar, data.userId);
|
||||
read(ar, data.name);
|
||||
read(ar, data.address);
|
||||
read(ar, data.loginLocation);
|
||||
read(ar, data.loginPriority);
|
||||
read(ar, data.attributes);
|
||||
}
|
||||
|
||||
template <typename StreamT>
|
||||
void write(StreamT& ar, const ResFailoverReLoginAvatar& data) {
|
||||
write(ar, data.type);
|
||||
write(ar, data.track);
|
||||
write(ar, data.result);
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "ChatAvatar.hpp"
|
||||
#include "ChatEnums.hpp"
|
||||
|
||||
#include <string>
|
||||
|
||||
class ChatAvatarService;
|
||||
class ChatRoomService;
|
||||
class GatewayClient;
|
||||
|
||||
/** Begin FRIENDSTATUS */
|
||||
|
||||
struct ReqFriendStatus {
|
||||
const ChatRequestType type = ChatRequestType::FRIENDSTATUS;
|
||||
uint32_t track;
|
||||
uint32_t srcAvatarId;
|
||||
std::u16string srcAddress;
|
||||
};
|
||||
|
||||
template <typename StreamT>
|
||||
void read(StreamT& ar, ReqFriendStatus& data) {
|
||||
read(ar, data.track);
|
||||
read(ar, data.srcAvatarId);
|
||||
read(ar, data.srcAddress);
|
||||
}
|
||||
|
||||
/** Begin FRIENDSTATUS */
|
||||
|
||||
struct ResFriendStatus {
|
||||
ResFriendStatus(uint32_t track_)
|
||||
: track{track_}
|
||||
, result{ChatResultCode::SUCCESS} {}
|
||||
|
||||
const ChatResponseType type = ChatResponseType::FRIENDSTATUS;
|
||||
uint32_t track;
|
||||
ChatResultCode result;
|
||||
const ChatAvatar* srcAvatar;
|
||||
};
|
||||
|
||||
template <typename StreamT>
|
||||
void write(StreamT& ar, const ResFriendStatus& data) {
|
||||
write(ar, data.type);
|
||||
write(ar, data.track);
|
||||
write(ar, data.result);
|
||||
|
||||
if (data.result == ChatResultCode::SUCCESS && data.srcAvatar) {
|
||||
const auto& friends = data.srcAvatar->GetFriendList();
|
||||
|
||||
write(ar, static_cast<uint32_t>(friends.size()));
|
||||
for (auto& friendContact : friends) {
|
||||
write(ar, friendContact);
|
||||
}
|
||||
} else {
|
||||
write(ar, static_cast<uint32_t>(0));
|
||||
}
|
||||
}
|
||||
|
||||
class FriendStatus {
|
||||
public:
|
||||
using RequestType = ReqFriendStatus;
|
||||
using ResponseType = ResFriendStatus;
|
||||
|
||||
FriendStatus(GatewayClient* client, const RequestType& request, ResponseType& response);
|
||||
|
||||
private:
|
||||
ChatAvatarService* avatarService_;
|
||||
ChatRoomService* roomService_;
|
||||
};
|
||||
@@ -0,0 +1,68 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "ChatAvatar.hpp"
|
||||
#include "ChatEnums.hpp"
|
||||
|
||||
class ChatAvatarService;
|
||||
class GatewayClient;
|
||||
|
||||
/** Begin GETANYAVATAR */
|
||||
|
||||
struct ReqGetAnyAvatar {
|
||||
const ChatRequestType type = ChatRequestType::GETANYAVATAR;
|
||||
uint32_t track;
|
||||
std::u16string name;
|
||||
std::u16string address;
|
||||
};
|
||||
|
||||
template <typename StreamT>
|
||||
void read(StreamT& ar, ReqGetAnyAvatar& data) {
|
||||
read(ar, data.track);
|
||||
read(ar, data.name);
|
||||
read(ar, data.address);
|
||||
}
|
||||
|
||||
/** Begin GETANYAVATAR */
|
||||
|
||||
struct ResGetAnyAvatar {
|
||||
explicit ResGetAnyAvatar(uint32_t track_)
|
||||
: track{track_}
|
||||
, result{ChatResultCode::SUCCESS} {}
|
||||
|
||||
ResGetAnyAvatar(uint32_t track_, ChatResultCode result_, bool isOnline_,
|
||||
const ChatAvatar* avatar_)
|
||||
: track{track_}
|
||||
, result{result_}
|
||||
, isOnline{isOnline_}
|
||||
, avatar{avatar_} {}
|
||||
|
||||
const ChatResponseType type = ChatResponseType::GETANYAVATAR;
|
||||
uint32_t track;
|
||||
ChatResultCode result;
|
||||
bool isOnline;
|
||||
const ChatAvatar* avatar;
|
||||
};
|
||||
|
||||
template <typename StreamT>
|
||||
void write(StreamT& ar, const ResGetAnyAvatar& data) {
|
||||
write(ar, data.type);
|
||||
write(ar, data.track);
|
||||
write(ar, data.result);
|
||||
write(ar, data.isOnline);
|
||||
|
||||
if (data.result == ChatResultCode::SUCCESS) {
|
||||
write(ar, data.avatar);
|
||||
}
|
||||
}
|
||||
|
||||
class GetAnyAvatar {
|
||||
public:
|
||||
using RequestType = ReqGetAnyAvatar;
|
||||
using ResponseType = ResGetAnyAvatar;
|
||||
|
||||
GetAnyAvatar(GatewayClient* client, const RequestType& request, ResponseType& response);
|
||||
|
||||
private:
|
||||
ChatAvatarService* avatarService_;
|
||||
};
|
||||
@@ -0,0 +1,62 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "ChatEnums.hpp"
|
||||
#include "PersistentMessage.hpp"
|
||||
|
||||
#include <vector>
|
||||
|
||||
class PersistentMessageService;
|
||||
class GatewayClient;
|
||||
|
||||
/** Begin GETPERSISTENTHEADERS */
|
||||
|
||||
struct ReqGetPersistentHeaders {
|
||||
const ChatRequestType type = ChatRequestType::GETPERSISTENTHEADERS;
|
||||
uint32_t track;
|
||||
uint32_t avatarId;
|
||||
std::u16string category;
|
||||
};
|
||||
|
||||
template <typename StreamT>
|
||||
void read(StreamT& ar, ReqGetPersistentHeaders& data) {
|
||||
read(ar, data.track);
|
||||
read(ar, data.avatarId);
|
||||
read(ar, data.category);
|
||||
}
|
||||
|
||||
/** Begin GETPERSISTENTHEADERS */
|
||||
|
||||
struct ResGetPersistentHeaders {
|
||||
ResGetPersistentHeaders(uint32_t track_)
|
||||
: track{track_}
|
||||
, result{ChatResultCode::SUCCESS} {}
|
||||
|
||||
const ChatResponseType type = ChatResponseType::GETPERSISTENTHEADERS;
|
||||
uint32_t track;
|
||||
ChatResultCode result;
|
||||
std::vector<PersistentHeader> headers;
|
||||
};
|
||||
|
||||
template <typename StreamT>
|
||||
void write(StreamT& ar, const ResGetPersistentHeaders& data) {
|
||||
write(ar, data.type);
|
||||
write(ar, data.track);
|
||||
write(ar, data.result);
|
||||
write(ar, static_cast<uint32_t>(data.headers.size()));
|
||||
|
||||
for (auto& header : data.headers) {
|
||||
write(ar, header);
|
||||
}
|
||||
}
|
||||
|
||||
class GetPersistentHeaders {
|
||||
public:
|
||||
using RequestType = ReqGetPersistentHeaders;
|
||||
using ResponseType = ResGetPersistentHeaders;
|
||||
|
||||
GetPersistentHeaders(GatewayClient* client, const RequestType& request, ResponseType& response);
|
||||
|
||||
private:
|
||||
PersistentMessageService* messageService_;
|
||||
};
|
||||
@@ -0,0 +1,60 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "ChatEnums.hpp"
|
||||
#include "PersistentMessage.hpp"
|
||||
|
||||
class PersistentMessageService;
|
||||
class GatewayClient;
|
||||
|
||||
/** Begin GETPERSISTENTMESSAGE */
|
||||
|
||||
struct ReqGetPersistentMessage {
|
||||
const ChatRequestType type = ChatRequestType::GETPERSISTENTMESSAGE;
|
||||
uint32_t track;
|
||||
uint32_t srcAvatarId;
|
||||
uint32_t messageId;
|
||||
};
|
||||
|
||||
template <typename StreamT>
|
||||
void read(StreamT& ar, ReqGetPersistentMessage& data) {
|
||||
read(ar, data.track);
|
||||
read(ar, data.srcAvatarId);
|
||||
read(ar, data.messageId);
|
||||
}
|
||||
|
||||
/** Begin GETPERSISTENTMESSAGE */
|
||||
|
||||
struct ResGetPersistentMessage {
|
||||
ResGetPersistentMessage(
|
||||
uint32_t track_)
|
||||
: track{track_}
|
||||
, result{ChatResultCode::SUCCESS} {}
|
||||
|
||||
const ChatResponseType type = ChatResponseType::GETPERSISTENTMESSAGE;
|
||||
uint32_t track;
|
||||
ChatResultCode result;
|
||||
PersistentMessage message;
|
||||
};
|
||||
|
||||
template <typename StreamT>
|
||||
void write(StreamT& ar, const ResGetPersistentMessage& data) {
|
||||
write(ar, data.type);
|
||||
write(ar, data.track);
|
||||
write(ar, data.result);
|
||||
|
||||
if (data.result == ChatResultCode::SUCCESS) {
|
||||
write(ar, data.message);
|
||||
}
|
||||
}
|
||||
|
||||
class GetPersistentMessage {
|
||||
public:
|
||||
using RequestType = ReqGetPersistentMessage;
|
||||
using ResponseType = ResGetPersistentMessage;
|
||||
|
||||
GetPersistentMessage(GatewayClient* client, const RequestType& request, ResponseType& response);
|
||||
|
||||
private:
|
||||
PersistentMessageService* messageService_;
|
||||
};
|
||||
@@ -0,0 +1,65 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "ChatEnums.hpp"
|
||||
#include "ChatRoom.hpp"
|
||||
|
||||
class ChatAvatarService;
|
||||
class ChatRoomService;
|
||||
class GatewayClient;
|
||||
|
||||
/** Begin GETROOM */
|
||||
|
||||
struct ReqGetRoom {
|
||||
const ChatRequestType type = ChatRequestType::GETROOMSUMMARIES;
|
||||
uint32_t track;
|
||||
std::u16string roomAddress;
|
||||
};
|
||||
|
||||
template <typename StreamT>
|
||||
void read(StreamT& ar, ReqGetRoom& data) {
|
||||
read(ar, data.track);
|
||||
read(ar, data.roomAddress);
|
||||
}
|
||||
|
||||
/** Begin GETROOM */
|
||||
|
||||
struct ResGetRoom {
|
||||
ResGetRoom(uint32_t track_)
|
||||
: track{track_}
|
||||
, result{ChatResultCode::SUCCESS}
|
||||
, room{nullptr} {}
|
||||
|
||||
const ChatResponseType type = ChatResponseType::GETROOM;
|
||||
uint32_t track;
|
||||
ChatResultCode result;
|
||||
ChatRoom* room;
|
||||
std::vector<ChatRoom*> extraRooms;
|
||||
};
|
||||
|
||||
template <typename StreamT>
|
||||
void write(StreamT& ar, const ResGetRoom& data) {
|
||||
write(ar, data.type);
|
||||
write(ar, data.track);
|
||||
write(ar, data.result);
|
||||
|
||||
if (data.result == ChatResultCode::SUCCESS) {
|
||||
write(ar, *data.room);
|
||||
|
||||
write(ar, static_cast<uint32_t>(data.extraRooms.size()));
|
||||
for (auto room : data.extraRooms) {
|
||||
write(ar, *room);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class GetRoom {
|
||||
public:
|
||||
using RequestType = ReqGetRoom;
|
||||
using ResponseType = ResGetRoom;
|
||||
|
||||
GetRoom(GatewayClient* client, const RequestType& request, ResponseType& response);
|
||||
|
||||
private:
|
||||
ChatRoomService* roomService_;
|
||||
};
|
||||
@@ -0,0 +1,67 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "ChatEnums.hpp"
|
||||
#include "ChatRoom.hpp"
|
||||
|
||||
#include <vector>
|
||||
|
||||
class ChatAvatarService;
|
||||
class ChatRoomService;
|
||||
class GatewayClient;
|
||||
|
||||
/** Begin GETROOMSUMMARIES */
|
||||
|
||||
struct ReqGetRoomSummaries {
|
||||
const ChatRequestType type = ChatRequestType::GETROOMSUMMARIES;
|
||||
uint32_t track;
|
||||
std::u16string startNodeAddress;
|
||||
std::u16string roomFilter;
|
||||
};
|
||||
|
||||
template <typename StreamT>
|
||||
void read(StreamT& ar, ReqGetRoomSummaries& data) {
|
||||
read(ar, data.track);
|
||||
read(ar, data.startNodeAddress);
|
||||
read(ar, data.roomFilter);
|
||||
}
|
||||
|
||||
/** Begin GETROOMSUMMARIES */
|
||||
|
||||
struct ResGetRoomSummaries {
|
||||
ResGetRoomSummaries(uint32_t track_)
|
||||
: track{track_}
|
||||
, result{ChatResultCode::SUCCESS} {}
|
||||
|
||||
const ChatResponseType type = ChatResponseType::GETROOMSUMMARIES;
|
||||
uint32_t track;
|
||||
ChatResultCode result;
|
||||
std::vector<ChatRoom*> rooms;
|
||||
};
|
||||
|
||||
template <typename StreamT>
|
||||
void write(StreamT& ar, const ResGetRoomSummaries& data) {
|
||||
write(ar, data.type);
|
||||
write(ar, data.track);
|
||||
write(ar, data.result);
|
||||
|
||||
write(ar, static_cast<uint32_t>(data.rooms.size()));
|
||||
for (auto room : data.rooms) {
|
||||
write(ar, room->GetRoomAddress());
|
||||
write(ar, room->GetRoomTopic());
|
||||
write(ar, room->GetRoomAttributes());
|
||||
write(ar, room->GetCurrentRoomSize());
|
||||
write(ar, room->GetMaxRoomSize());
|
||||
}
|
||||
}
|
||||
|
||||
class GetRoomSummaries {
|
||||
public:
|
||||
using RequestType = ReqGetRoomSummaries;
|
||||
using ResponseType = ResGetRoomSummaries;
|
||||
|
||||
GetRoomSummaries(GatewayClient* client, const RequestType& request, ResponseType& response);
|
||||
|
||||
private:
|
||||
ChatRoomService* roomService_;
|
||||
};
|
||||
@@ -0,0 +1,67 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "ChatAvatar.hpp"
|
||||
#include "ChatEnums.hpp"
|
||||
|
||||
class ChatAvatarService;
|
||||
class ChatRoomService;
|
||||
class GatewayClient;
|
||||
|
||||
/** Begin IGNORESTATUS */
|
||||
|
||||
struct ReqIgnoreStatus {
|
||||
const ChatRequestType type = ChatRequestType::IGNORESTATUS;
|
||||
uint32_t track;
|
||||
uint32_t srcAvatarId;
|
||||
std::u16string srcAddress;
|
||||
};
|
||||
|
||||
template <typename StreamT>
|
||||
void read(StreamT& ar, ReqIgnoreStatus& data) {
|
||||
read(ar, data.track);
|
||||
read(ar, data.srcAvatarId);
|
||||
read(ar, data.srcAddress);
|
||||
}
|
||||
|
||||
/** Begin IGNORESTATUS */
|
||||
|
||||
struct ResIgnoreStatus {
|
||||
ResIgnoreStatus(uint32_t track_)
|
||||
: track{track_}
|
||||
, result{ChatResultCode::SUCCESS} {}
|
||||
|
||||
const ChatResponseType type = ChatResponseType::IGNORESTATUS;
|
||||
uint32_t track;
|
||||
ChatResultCode result;
|
||||
const ChatAvatar* srcAvatar;
|
||||
};
|
||||
|
||||
template <typename StreamT>
|
||||
void write(StreamT& ar, const ResIgnoreStatus& data) {
|
||||
write(ar, data.type);
|
||||
write(ar, data.track);
|
||||
write(ar, data.result);
|
||||
|
||||
if (data.result == ChatResultCode::SUCCESS && data.srcAvatar) {
|
||||
const auto& ignored = data.srcAvatar->GetIgnoreList();
|
||||
|
||||
write(ar, static_cast<uint32_t>(ignored.size()));
|
||||
for (auto& ignoredContact : ignored) {
|
||||
write(ar, ignoredContact);
|
||||
}
|
||||
} else {
|
||||
write(ar, static_cast<uint32_t>(0));
|
||||
}
|
||||
}
|
||||
|
||||
class IgnoreStatus {
|
||||
public:
|
||||
using RequestType = ReqIgnoreStatus;
|
||||
using ResponseType = ResIgnoreStatus;
|
||||
|
||||
IgnoreStatus(GatewayClient* client, const RequestType& request, ResponseType& response);
|
||||
|
||||
private:
|
||||
ChatAvatarService* avatarService_;
|
||||
};
|
||||
@@ -0,0 +1,63 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "ChatEnums.hpp"
|
||||
|
||||
class ChatAvatarService;
|
||||
class ChatRoomService;
|
||||
class GatewayClient;
|
||||
|
||||
/** Begin KICKAVATAR */
|
||||
|
||||
struct ReqKickAvatar {
|
||||
const ChatRequestType type = ChatRequestType::KICKAVATAR;
|
||||
uint32_t track;
|
||||
uint32_t srcAvatarId;
|
||||
std::u16string destAvatarName;
|
||||
std::u16string destAvatarAddress;
|
||||
std::u16string destRoomAddress;
|
||||
std::u16string srcAddress;
|
||||
};
|
||||
|
||||
template <typename StreamT>
|
||||
void read(StreamT& ar, ReqKickAvatar& data) {
|
||||
read(ar, data.track);
|
||||
read(ar, data.srcAvatarId);
|
||||
read(ar, data.destAvatarName);
|
||||
read(ar, data.destAvatarAddress);
|
||||
read(ar, data.destRoomAddress);
|
||||
read(ar, data.srcAddress);
|
||||
}
|
||||
|
||||
/** Begin KICKAVATAR */
|
||||
|
||||
struct ResKickAvatar {
|
||||
ResKickAvatar(uint32_t track_)
|
||||
: track{track_}
|
||||
, result{ChatResultCode::SUCCESS} {}
|
||||
|
||||
const ChatResponseType type = ChatResponseType::KICKAVATAR;
|
||||
uint32_t track;
|
||||
ChatResultCode result;
|
||||
uint32_t destRoomId;
|
||||
};
|
||||
|
||||
template <typename StreamT>
|
||||
void write(StreamT& ar, const ResKickAvatar& data) {
|
||||
write(ar, data.type);
|
||||
write(ar, data.track);
|
||||
write(ar, data.result);
|
||||
write(ar, data.destRoomId);
|
||||
}
|
||||
|
||||
class KickAvatar {
|
||||
public:
|
||||
using RequestType = ReqKickAvatar;
|
||||
using ResponseType = ResKickAvatar;
|
||||
|
||||
KickAvatar(GatewayClient* client, const RequestType& request, ResponseType& response);
|
||||
|
||||
private:
|
||||
ChatAvatarService* avatarService_;
|
||||
ChatRoomService* roomService_;
|
||||
};
|
||||
@@ -0,0 +1,59 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "ChatEnums.hpp"
|
||||
|
||||
class ChatAvatarService;
|
||||
class ChatRoomService;
|
||||
class GatewayClient;
|
||||
|
||||
/** Begin LEAVEROOM */
|
||||
|
||||
struct ReqLeaveRoom {
|
||||
const ChatRequestType type = ChatRequestType::LEAVEROOM;
|
||||
uint32_t track;
|
||||
uint32_t srcAvatarId;
|
||||
std::u16string roomAddress;
|
||||
std::u16string srcAddress;
|
||||
};
|
||||
|
||||
template <typename StreamT>
|
||||
void read(StreamT& ar, ReqLeaveRoom& data) {
|
||||
read(ar, data.track);
|
||||
read(ar, data.srcAvatarId);
|
||||
read(ar, data.roomAddress);
|
||||
read(ar, data.srcAddress);
|
||||
}
|
||||
|
||||
/** Begin LEAVEROOM */
|
||||
|
||||
struct ResLeaveRoom {
|
||||
ResLeaveRoom(uint32_t track_)
|
||||
: track{track_}
|
||||
, result{ChatResultCode::SUCCESS} {}
|
||||
|
||||
const ChatResponseType type = ChatResponseType::LEAVEROOM;
|
||||
uint32_t track;
|
||||
ChatResultCode result;
|
||||
uint32_t roomId;
|
||||
};
|
||||
|
||||
template <typename StreamT>
|
||||
void write(StreamT& ar, const ResLeaveRoom& data) {
|
||||
write(ar, data.type);
|
||||
write(ar, data.track);
|
||||
write(ar, data.result);
|
||||
write(ar, data.roomId);
|
||||
}
|
||||
|
||||
class LeaveRoom {
|
||||
public:
|
||||
using RequestType = ReqLeaveRoom;
|
||||
using ResponseType = ResLeaveRoom;
|
||||
|
||||
LeaveRoom(GatewayClient* client, const RequestType& request, ResponseType& response);
|
||||
|
||||
private:
|
||||
ChatAvatarService* avatarService_;
|
||||
ChatRoomService* roomService_;
|
||||
};
|
||||
@@ -0,0 +1,69 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "ChatAvatar.hpp"
|
||||
#include "ChatEnums.hpp"
|
||||
|
||||
class ChatAvatarService;
|
||||
class ChatRoomService;
|
||||
class GatewayClient;
|
||||
|
||||
/** Begin LOGINAVATAR */
|
||||
|
||||
struct ReqLoginAvatar {
|
||||
const ChatRequestType type = ChatRequestType::LOGINAVATAR;
|
||||
uint32_t track;
|
||||
uint32_t userId;
|
||||
std::u16string name;
|
||||
std::u16string address;
|
||||
std::u16string loginLocation;
|
||||
int32_t loginPriority;
|
||||
int32_t loginAttributes;
|
||||
};
|
||||
|
||||
template <typename StreamT>
|
||||
void read(StreamT& ar, ReqLoginAvatar& data) {
|
||||
read(ar, data.track);
|
||||
read(ar, data.userId);
|
||||
read(ar, data.name);
|
||||
read(ar, data.address);
|
||||
read(ar, data.loginLocation);
|
||||
read(ar, data.loginPriority);
|
||||
read(ar, data.loginAttributes);
|
||||
}
|
||||
|
||||
/** Begin LOGINAVATAR */
|
||||
|
||||
struct ResLoginAvatar {
|
||||
explicit ResLoginAvatar(uint32_t track_)
|
||||
: track{track_}
|
||||
, result{ChatResultCode::SUCCESS} {}
|
||||
|
||||
const ChatResponseType type = ChatResponseType::LOGINAVATAR;
|
||||
uint32_t track;
|
||||
ChatResultCode result;
|
||||
const ChatAvatar* avatar;
|
||||
};
|
||||
|
||||
template <typename StreamT>
|
||||
void write(StreamT& ar, const ResLoginAvatar& data) {
|
||||
write(ar, data.type);
|
||||
write(ar, data.track);
|
||||
write(ar, data.result);
|
||||
|
||||
if (data.result == ChatResultCode::SUCCESS) {
|
||||
write(ar, data.avatar);
|
||||
}
|
||||
}
|
||||
|
||||
class LoginAvatar {
|
||||
public:
|
||||
using RequestType = ReqLoginAvatar;
|
||||
using ResponseType = ResLoginAvatar;
|
||||
|
||||
LoginAvatar(GatewayClient* client, const RequestType& request, ResponseType& response);
|
||||
|
||||
private:
|
||||
ChatAvatarService* avatarService_;
|
||||
ChatRoomService* roomService_;
|
||||
};
|
||||
@@ -0,0 +1,54 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "ChatEnums.hpp"
|
||||
|
||||
class ChatAvatarService;
|
||||
class ChatRoomService;
|
||||
class GatewayClient;
|
||||
|
||||
/** Begin LOGOUTAVATAR */
|
||||
|
||||
struct ReqLogoutAvatar {
|
||||
const ChatRequestType type = ChatRequestType::LOGOUTAVATAR;
|
||||
uint32_t track;
|
||||
uint32_t avatarId;
|
||||
};
|
||||
|
||||
template <typename StreamT>
|
||||
void read(StreamT& ar, ReqLogoutAvatar& data) {
|
||||
read(ar, data.track);
|
||||
read(ar, data.avatarId);
|
||||
}
|
||||
|
||||
/** Begin LOGOUTAVATAR */
|
||||
|
||||
struct ResLogoutAvatar {
|
||||
explicit ResLogoutAvatar(uint32_t track_)
|
||||
: track{track_}
|
||||
, result{ChatResultCode::SUCCESS} {}
|
||||
|
||||
const ChatResponseType type = ChatResponseType::LOGOUTAVATAR;
|
||||
uint32_t track;
|
||||
ChatResultCode result;
|
||||
};
|
||||
|
||||
template <typename StreamT>
|
||||
void write(StreamT& ar, const ResLogoutAvatar& data) {
|
||||
write(ar, data.type);
|
||||
write(ar, data.track);
|
||||
write(ar, data.result);
|
||||
}
|
||||
|
||||
|
||||
class LogoutAvatar {
|
||||
public:
|
||||
using RequestType = ReqLogoutAvatar;
|
||||
using ResponseType = ResLogoutAvatar;
|
||||
|
||||
LogoutAvatar(GatewayClient* client, const RequestType& request, ResponseType& response);
|
||||
|
||||
private:
|
||||
ChatAvatarService* avatarService_;
|
||||
ChatRoomService* roomService_;
|
||||
};
|
||||
@@ -0,0 +1,727 @@
|
||||
#include "AddBan.hpp"
|
||||
|
||||
#include "ChatAvatarService.hpp"
|
||||
#include "ChatRoomService.hpp"
|
||||
#include "GatewayClient.hpp"
|
||||
#include "GatewayNode.hpp"
|
||||
#include "PersistentMessageService.hpp"
|
||||
#include "RegistrarClient.hpp"
|
||||
#include "RegistrarNode.hpp"
|
||||
#include "StringUtils.hpp"
|
||||
#include "StationChatConfig.hpp"
|
||||
|
||||
#include "protocol/AddBan.hpp"
|
||||
#include "protocol/AddFriend.hpp"
|
||||
#include "protocol/AddIgnore.hpp"
|
||||
#include "protocol/AddInvite.hpp"
|
||||
#include "protocol/AddModerator.hpp"
|
||||
#include "protocol/CreateRoom.hpp"
|
||||
#include "protocol/DestroyAvatar.hpp"
|
||||
#include "protocol/DestroyRoom.hpp"
|
||||
#include "protocol/EnterRoom.hpp"
|
||||
#include "protocol/FailoverReLoginAvatar.hpp"
|
||||
#include "protocol/FriendStatus.hpp"
|
||||
#include "protocol/GetAnyAvatar.hpp"
|
||||
#include "protocol/GetPersistentHeaders.hpp"
|
||||
#include "protocol/GetPersistentMessage.hpp"
|
||||
#include "protocol/GetRoom.hpp"
|
||||
#include "protocol/GetRoomSummaries.hpp"
|
||||
#include "protocol/IgnoreStatus.hpp"
|
||||
#include "protocol/KickAvatar.hpp"
|
||||
#include "protocol/LeaveRoom.hpp"
|
||||
#include "protocol/LoginAvatar.hpp"
|
||||
#include "protocol/LogoutAvatar.hpp"
|
||||
#include "protocol/RegistrarGetChatServer.hpp"
|
||||
#include "protocol/RemoveBan.hpp"
|
||||
#include "protocol/RemoveFriend.hpp"
|
||||
#include "protocol/RemoveIgnore.hpp"
|
||||
#include "protocol/RemoveInvite.hpp"
|
||||
#include "protocol/RemoveModerator.hpp"
|
||||
#include "protocol/SendInstantMessage.hpp"
|
||||
#include "protocol/SendPersistentMessage.hpp"
|
||||
#include "protocol/SendRoomMessage.hpp"
|
||||
#include "protocol/SetApiVersion.hpp"
|
||||
#include "protocol/SetAvatarAttributes.hpp"
|
||||
#include "protocol/UpdatePersistentMessage.hpp"
|
||||
|
||||
#include "easylogging++.h"
|
||||
|
||||
AddBan::AddBan(GatewayClient* client, const RequestType& request, ResponseType& response)
|
||||
: avatarService_{client->GetNode()->GetAvatarService()}
|
||||
, roomService_{client->GetNode()->GetRoomService()} {
|
||||
LOG(INFO) << "ADDBAN request received - adding ban for: "
|
||||
<< FromWideString(request.destAvatarName) << "@"
|
||||
<< FromWideString(request.destAvatarAddress) << " to "
|
||||
<< FromWideString(request.destRoomAddress);
|
||||
|
||||
auto srcAvatar = avatarService_->GetAvatar(request.srcAvatarId);
|
||||
if (!srcAvatar) {
|
||||
throw ChatResultException{ChatResultCode::SRCAVATARDOESNTEXIST};
|
||||
}
|
||||
|
||||
auto bannedAvatar
|
||||
= avatarService_->GetAvatar(request.destAvatarName, request.destAvatarAddress);
|
||||
if (!bannedAvatar) {
|
||||
throw ChatResultException{ChatResultCode::DESTAVATARDOESNTEXIST};
|
||||
}
|
||||
|
||||
auto room = roomService_->GetRoom(request.destRoomAddress);
|
||||
if (!room) {
|
||||
throw ChatResultException{ChatResultCode::ADDRESSNOTROOM};
|
||||
}
|
||||
|
||||
response.destRoomId = room->GetRoomId();
|
||||
|
||||
room->AddBanned(srcAvatar->GetAvatarId(), bannedAvatar);
|
||||
}
|
||||
|
||||
AddFriend::AddFriend(GatewayClient* client, const RequestType& request, ResponseType& response)
|
||||
: avatarService_{client->GetNode()->GetAvatarService()} {
|
||||
LOG(INFO) << "ADDFRIEND request received - adding: " << FromWideString(request.destName) << "@"
|
||||
<< FromWideString(request.destAddress) << " to " << request.srcAvatarId << "@"
|
||||
<< FromWideString(request.srcAddress);
|
||||
auto srcAvatar = avatarService_->GetAvatar(request.srcAvatarId);
|
||||
if (!srcAvatar) {
|
||||
throw ChatResultException{ChatResultCode::SRCAVATARDOESNTEXIST};
|
||||
}
|
||||
|
||||
auto destAvatar = avatarService_->GetAvatar(request.destName, request.destAddress);
|
||||
if (!destAvatar) {
|
||||
throw ChatResultException{ChatResultCode::DESTAVATARDOESNTEXIST};
|
||||
}
|
||||
|
||||
srcAvatar->AddFriend(destAvatar);
|
||||
|
||||
if (destAvatar->IsOnline()) {
|
||||
client->SendFriendLoginUpdate(srcAvatar, destAvatar);
|
||||
}
|
||||
}
|
||||
|
||||
AddIgnore::AddIgnore(GatewayClient* client, const RequestType& request, ResponseType& response)
|
||||
: avatarService_{client->GetNode()->GetAvatarService()} {
|
||||
LOG(INFO) << "ADDIGNORE request received - adding: " << FromWideString(request.destName) << "@"
|
||||
<< FromWideString(request.destAddress) << " to " << request.srcAvatarId << "@"
|
||||
<< FromWideString(request.srcAddress);
|
||||
auto srcAvatar = avatarService_->GetAvatar(request.srcAvatarId);
|
||||
if (!srcAvatar) {
|
||||
throw ChatResultException{ChatResultCode::SRCAVATARDOESNTEXIST};
|
||||
}
|
||||
|
||||
auto destAvatar = avatarService_->GetAvatar(request.destName, request.destAddress);
|
||||
if (!destAvatar) {
|
||||
throw ChatResultException{ChatResultCode::DESTAVATARDOESNTEXIST};
|
||||
}
|
||||
|
||||
srcAvatar->AddIgnore(destAvatar);
|
||||
}
|
||||
|
||||
AddInvite::AddInvite(GatewayClient* client, const RequestType& request, ResponseType& response)
|
||||
: avatarService_{client->GetNode()->GetAvatarService()}
|
||||
, roomService_{client->GetNode()->GetRoomService()} {
|
||||
LOG(INFO) << "ADDINVITE request received - adding invitation for: "
|
||||
<< FromWideString(request.destAvatarName) << "@"
|
||||
<< FromWideString(request.destAvatarAddress) << " to "
|
||||
<< FromWideString(request.destRoomAddress);
|
||||
|
||||
auto srcAvatar = avatarService_->GetAvatar(request.srcAvatarId);
|
||||
if (!srcAvatar) {
|
||||
throw ChatResultException{ChatResultCode::SRCAVATARDOESNTEXIST};
|
||||
}
|
||||
|
||||
auto invitedAvatar
|
||||
= avatarService_->GetAvatar(request.destAvatarName, request.destAvatarAddress);
|
||||
if (!invitedAvatar) {
|
||||
throw ChatResultException{ChatResultCode::DESTAVATARDOESNTEXIST};
|
||||
}
|
||||
|
||||
auto room = roomService_->GetRoom(request.destRoomAddress);
|
||||
if (!room) {
|
||||
throw ChatResultException{ChatResultCode::ADDRESSNOTROOM};
|
||||
}
|
||||
|
||||
response.destRoomId = room->GetRoomId();
|
||||
|
||||
room->AddInvite(srcAvatar->GetAvatarId(), invitedAvatar);
|
||||
}
|
||||
|
||||
AddModerator::AddModerator(
|
||||
GatewayClient* client, const RequestType& request, ResponseType& response)
|
||||
: avatarService_{client->GetNode()->GetAvatarService()}
|
||||
, roomService_{client->GetNode()->GetRoomService()} {
|
||||
LOG(INFO) << "ADDMODERATOR request recieved - adding: "
|
||||
<< FromWideString(request.destAvatarName) << "@"
|
||||
<< FromWideString(request.destAvatarAddress) << " to "
|
||||
<< FromWideString(request.destRoomAddress);
|
||||
|
||||
auto srcAvatar = avatarService_->GetAvatar(request.srcAvatarId);
|
||||
if (!srcAvatar) {
|
||||
throw ChatResultException{ChatResultCode::SRCAVATARDOESNTEXIST};
|
||||
}
|
||||
|
||||
auto moderatorAvatar
|
||||
= avatarService_->GetAvatar(request.destAvatarName, request.destAvatarAddress);
|
||||
if (!moderatorAvatar) {
|
||||
throw ChatResultException{ChatResultCode::DESTAVATARDOESNTEXIST};
|
||||
}
|
||||
|
||||
auto room = roomService_->GetRoom(request.destRoomAddress);
|
||||
if (!room) {
|
||||
throw ChatResultException{ChatResultCode::ADDRESSNOTROOM};
|
||||
}
|
||||
|
||||
response.destRoomId = room->GetRoomId();
|
||||
|
||||
room->AddModerator(srcAvatar->GetAvatarId(), moderatorAvatar);
|
||||
}
|
||||
|
||||
CreateRoom::CreateRoom(GatewayClient* client, const RequestType& request, ResponseType& response)
|
||||
: avatarService_{client->GetNode()->GetAvatarService()}
|
||||
, roomService_{client->GetNode()->GetRoomService()} {
|
||||
LOG(INFO) << "CREATEROOM request received - creator: " << request.creatorId << "@"
|
||||
<< FromWideString(request.srcAddress)
|
||||
<< " room: " << FromWideString(request.roomAddress);
|
||||
|
||||
response.room = roomService_->CreateRoom(avatarService_->GetAvatar(request.creatorId),
|
||||
request.roomName, request.roomTopic, request.roomPassword, request.roomAttributes,
|
||||
request.roomMaxSize, request.roomAddress, request.srcAddress);
|
||||
}
|
||||
|
||||
DestroyAvatar::DestroyAvatar(
|
||||
GatewayClient* client, const RequestType& request, ResponseType& response)
|
||||
: avatarService_{client->GetNode()->GetAvatarService()}
|
||||
, roomService_{client->GetNode()->GetRoomService()} {
|
||||
auto avatar = avatarService_->GetAvatar(request.avatarId);
|
||||
if (!avatar) {
|
||||
throw ChatResultException{ChatResultCode::SRCAVATARDOESNTEXIST};
|
||||
}
|
||||
|
||||
// Remove From All Rooms
|
||||
for (auto room : roomService_->GetJoinedRooms(avatar)) {
|
||||
auto addresses = room->GetConnectedAddresses();
|
||||
room->LeaveRoom(avatar);
|
||||
|
||||
client->SendLeaveRoomUpdate(addresses, avatar->GetAvatarId(), room->GetRoomId());
|
||||
}
|
||||
|
||||
// Destroy avatar
|
||||
avatarService_->DestroyAvatar(avatar);
|
||||
}
|
||||
|
||||
DestroyRoom::DestroyRoom(GatewayClient* client, const RequestType& request, ResponseType& response)
|
||||
: avatarService_{client->GetNode()->GetAvatarService()}
|
||||
, roomService_{client->GetNode()->GetRoomService()} {
|
||||
LOG(INFO) << "DESTROYROOM request received " << request.srcAvatarId << "@"
|
||||
<< FromWideString(request.srcAddress)
|
||||
<< " room: " << FromWideString(request.roomAddress);
|
||||
|
||||
auto srcAvatar = avatarService_->GetAvatar(request.srcAvatarId);
|
||||
if (!srcAvatar) {
|
||||
throw ChatResultException(ChatResultCode::SRCAVATARDOESNTEXIST);
|
||||
}
|
||||
|
||||
auto room = roomService_->GetRoom(request.roomAddress);
|
||||
if (!room) {
|
||||
throw ChatResultException(ChatResultCode::ADDRESSNOTROOM);
|
||||
}
|
||||
|
||||
auto addresses = room->GetRemoteAddresses();
|
||||
auto roomId = room->GetRoomId();
|
||||
|
||||
response.roomId = roomId;
|
||||
|
||||
roomService_->DestroyRoom(room);
|
||||
|
||||
client->SendDestroyRoomUpdate(srcAvatar, roomId, addresses);
|
||||
}
|
||||
|
||||
EnterRoom::EnterRoom(GatewayClient* client, const RequestType& request, ResponseType& response)
|
||||
: avatarService_{client->GetNode()->GetAvatarService()}
|
||||
, roomService_{client->GetNode()->GetRoomService()} {
|
||||
LOG(INFO) << "ENTERROOM request received - avatar: " << request.srcAvatarId << "@"
|
||||
<< FromWideString(request.srcAddress)
|
||||
<< " room: " << FromWideString(request.roomAddress);
|
||||
|
||||
auto srcAvatar = avatarService_->GetAvatar(request.srcAvatarId);
|
||||
if (!srcAvatar) {
|
||||
throw ChatResultException{ChatResultCode::SRCAVATARDOESNTEXIST};
|
||||
}
|
||||
|
||||
response.room = roomService_->GetRoom(request.roomAddress);
|
||||
if (!response.room) {
|
||||
throw ChatResultException{ChatResultCode::ADDRESSNOTROOM};
|
||||
}
|
||||
|
||||
response.roomId = response.room->GetRoomId();
|
||||
response.room->EnterRoom(srcAvatar, request.roomPassword);
|
||||
|
||||
client->SendEnterRoomUpdate(srcAvatar, response.room);
|
||||
}
|
||||
|
||||
FailoverReLoginAvatar::FailoverReLoginAvatar(
|
||||
GatewayClient* client, const RequestType& request, ResponseType& response)
|
||||
: avatarService_{client->GetNode()->GetAvatarService()}
|
||||
, roomService_{client->GetNode()->GetRoomService()} {
|
||||
LOG(INFO) << "FAILOVER_RELOGINAVATAR request received " << FromWideString(request.name) << "@"
|
||||
<< FromWideString(request.address);
|
||||
|
||||
auto avatar = avatarService_->GetAvatar(request.name, request.address);
|
||||
if (!avatar) {
|
||||
LOG(INFO) << "Login avatar does not exist, creating a new one " << FromWideString(request.name) << "@"
|
||||
<< FromWideString(request.address);
|
||||
avatar = avatarService_->CreateAvatar(request.name, request.address, request.userId,
|
||||
request.attributes, request.loginLocation);
|
||||
}
|
||||
|
||||
avatarService_->LoginAvatar(CHECK_NOTNULL(avatar));
|
||||
|
||||
if (avatar->GetName().compare(u"SYSTEM") == 0) {
|
||||
client->GetNode()->RegisterClientAddress(avatar->GetAddress(), client);
|
||||
roomService_->LoadRoomsFromStorage(request.address);
|
||||
} else {
|
||||
client->SendFriendLoginUpdates(avatar);
|
||||
}
|
||||
|
||||
for (auto room : roomService_->GetJoinedRooms(avatar)) {
|
||||
client->SendEnterRoomUpdate(avatar, room);
|
||||
}
|
||||
}
|
||||
|
||||
FriendStatus::FriendStatus(
|
||||
GatewayClient* client, const RequestType& request, ResponseType& response)
|
||||
: avatarService_{client->GetNode()->GetAvatarService()} {
|
||||
LOG(INFO) << "FRIENDSTATUS request received - for " << request.srcAvatarId << "@"
|
||||
<< FromWideString(request.srcAddress);
|
||||
|
||||
auto srcAvatar = avatarService_->GetAvatar(request.srcAvatarId);
|
||||
if (!srcAvatar) {
|
||||
throw ChatResultException{ChatResultCode::SRCAVATARDOESNTEXIST};
|
||||
}
|
||||
|
||||
response.srcAvatar = srcAvatar;
|
||||
}
|
||||
|
||||
GetAnyAvatar::GetAnyAvatar(
|
||||
GatewayClient* client, const RequestType& request, ResponseType& response)
|
||||
: avatarService_{client->GetNode()->GetAvatarService()} {
|
||||
LOG(INFO) << "GETANYAVATAR request received - avatar: " << FromWideString(request.name) << "@"
|
||||
<< FromWideString(request.address);
|
||||
|
||||
auto avatar = avatarService_->GetAvatar(request.name, request.address);
|
||||
if (!avatar) {
|
||||
throw ChatResultException{ChatResultCode::SRCAVATARDOESNTEXIST};
|
||||
}
|
||||
|
||||
response.isOnline = avatar->IsOnline();
|
||||
response.avatar = avatar;
|
||||
}
|
||||
|
||||
GetPersistentHeaders::GetPersistentHeaders(
|
||||
GatewayClient* client, const RequestType& request, ResponseType& response)
|
||||
: messageService_{client->GetNode()->GetMessageService()} {
|
||||
LOG(INFO) << "GETPERSISTENTHEADERS request recieved - avatar: " << request.avatarId
|
||||
<< " category: " << FromWideString(request.category);
|
||||
|
||||
response.headers = messageService_->GetMessageHeaders(request.avatarId);
|
||||
}
|
||||
|
||||
GetPersistentMessage::GetPersistentMessage(
|
||||
GatewayClient* client, const RequestType& request, ResponseType& response)
|
||||
: messageService_{client->GetNode()->GetMessageService()} {
|
||||
LOG(INFO) << "GETPERSISTENTMESSAGE request received - avatar: " << request.srcAvatarId
|
||||
<< " message: " << request.messageId;
|
||||
|
||||
response.message
|
||||
= messageService_->GetPersistentMessage(request.srcAvatarId, request.messageId);
|
||||
}
|
||||
|
||||
GetRoom::GetRoom(GatewayClient* client, const RequestType& request, ResponseType& response)
|
||||
: roomService_{client->GetNode()->GetRoomService()} {
|
||||
LOG(INFO) << "GETROOM request received - room: " << FromWideString(request.roomAddress);
|
||||
|
||||
auto room = roomService_->GetRoom(request.roomAddress);
|
||||
if (!room) {
|
||||
throw ChatResultException{ChatResultCode::ADDRESSDOESNTEXIST};
|
||||
}
|
||||
|
||||
response.room = room;
|
||||
}
|
||||
|
||||
GetRoomSummaries::GetRoomSummaries(
|
||||
GatewayClient* client, const RequestType& request, ResponseType& response)
|
||||
: roomService_{client->GetNode()->GetRoomService()} {
|
||||
LOG(INFO) << "GETROOMSUMMARIES request received - start node: "
|
||||
<< FromWideString(request.startNodeAddress)
|
||||
<< " filter: " << FromWideString(request.roomFilter);
|
||||
|
||||
response.rooms = roomService_->GetRoomSummaries(request.startNodeAddress, request.roomFilter);
|
||||
}
|
||||
|
||||
IgnoreStatus::IgnoreStatus(
|
||||
GatewayClient* client, const RequestType& request, ResponseType& response)
|
||||
: avatarService_{client->GetNode()->GetAvatarService()} {
|
||||
LOG(INFO) << "IGNORESTATUS request received - for " << request.srcAvatarId << "@"
|
||||
<< FromWideString(request.srcAddress);
|
||||
|
||||
auto srcAvatar = avatarService_->GetAvatar(request.srcAvatarId);
|
||||
if (!srcAvatar) {
|
||||
throw ChatResultException{ChatResultCode::SRCAVATARDOESNTEXIST};
|
||||
}
|
||||
|
||||
response.srcAvatar = srcAvatar;
|
||||
}
|
||||
|
||||
KickAvatar::KickAvatar(GatewayClient* client, const RequestType& request, ResponseType& response)
|
||||
: avatarService_{client->GetNode()->GetAvatarService()}
|
||||
, roomService_{client->GetNode()->GetRoomService()} {
|
||||
LOG(INFO) << "KICKAVATAR request received - kicking: " << FromWideString(request.destAvatarName)
|
||||
<< "@" << FromWideString(request.destAvatarAddress) << " from "
|
||||
<< FromWideString(request.destRoomAddress);
|
||||
|
||||
auto srcAvatar = avatarService_->GetAvatar(request.srcAvatarId);
|
||||
if (!srcAvatar) {
|
||||
throw ChatResultException{ChatResultCode::SRCAVATARDOESNTEXIST};
|
||||
}
|
||||
|
||||
auto destAvatar = avatarService_->GetAvatar(request.destAvatarName, request.destAvatarAddress);
|
||||
if (!destAvatar) {
|
||||
throw ChatResultException{ChatResultCode::DESTAVATARDOESNTEXIST};
|
||||
}
|
||||
|
||||
auto room = roomService_->GetRoom(request.destRoomAddress);
|
||||
if (!room) {
|
||||
throw ChatResultException{ChatResultCode::ADDRESSNOTROOM};
|
||||
}
|
||||
|
||||
response.destRoomId = room->GetRoomId();
|
||||
|
||||
auto addresses = room->GetConnectedAddresses();
|
||||
room->KickAvatar(srcAvatar->GetAvatarId(), destAvatar);
|
||||
|
||||
client->SendKickAvatarUpdate(addresses, srcAvatar, destAvatar, room);
|
||||
}
|
||||
|
||||
LeaveRoom::LeaveRoom(GatewayClient* client, const RequestType& request, ResponseType& response)
|
||||
: avatarService_{client->GetNode()->GetAvatarService()}
|
||||
, roomService_{client->GetNode()->GetRoomService()} {
|
||||
auto srcAvatar = avatarService_->GetAvatar(request.srcAvatarId);
|
||||
if (!srcAvatar) {
|
||||
throw ChatResultException{ChatResultCode::SRCAVATARDOESNTEXIST};
|
||||
}
|
||||
|
||||
auto room = roomService_->GetRoom(request.roomAddress);
|
||||
if (!room) {
|
||||
throw ChatResultException{ChatResultCode::ADDRESSNOTROOM};
|
||||
}
|
||||
|
||||
response.roomId = room->GetRoomId();
|
||||
|
||||
// Cache the addresses before leaving the room in case this avatar was the
|
||||
// last on their server, to ensure the update messages goes out.
|
||||
auto addresses = room->GetConnectedAddresses();
|
||||
room->LeaveRoom(srcAvatar);
|
||||
|
||||
client->SendLeaveRoomUpdate(addresses, srcAvatar->GetAvatarId(), room->GetRoomId());
|
||||
}
|
||||
|
||||
LoginAvatar::LoginAvatar(GatewayClient* client, const RequestType& request, ResponseType& response)
|
||||
: avatarService_{client->GetNode()->GetAvatarService()}
|
||||
, roomService_{client->GetNode()->GetRoomService()} {
|
||||
LOG(INFO) << "LOGINAVATAR request received " << FromWideString(request.name) << "@"
|
||||
<< FromWideString(request.address);
|
||||
|
||||
auto avatar = avatarService_->GetAvatar(request.name, request.address);
|
||||
if (!avatar) {
|
||||
LOG(INFO) << "Login avatar does not exist, creating a new one "
|
||||
<< FromWideString(request.name) << "@" << FromWideString(request.address);
|
||||
avatar = avatarService_->CreateAvatar(request.name, request.address, request.userId,
|
||||
request.loginAttributes, request.loginLocation);
|
||||
}
|
||||
|
||||
avatarService_->LoginAvatar(CHECK_NOTNULL(avatar));
|
||||
|
||||
if (avatar->GetName().compare(u"SYSTEM") == 0) {
|
||||
client->GetNode()->RegisterClientAddress(avatar->GetAddress(), client);
|
||||
roomService_->LoadRoomsFromStorage(request.address);
|
||||
} else {
|
||||
client->SendFriendLoginUpdates(avatar);
|
||||
}
|
||||
|
||||
response.avatar = avatar;
|
||||
}
|
||||
|
||||
LogoutAvatar::LogoutAvatar(GatewayClient* client, const RequestType& request, ResponseType& response)
|
||||
: avatarService_{client->GetNode()->GetAvatarService()}
|
||||
, roomService_{client->GetNode()->GetRoomService()} {
|
||||
LOG(INFO) << "LOGOUTAVATAR request received - avatar id:" << request.avatarId;
|
||||
|
||||
auto avatar = avatarService_->GetAvatar(request.avatarId);
|
||||
|
||||
for (auto room : roomService_->GetJoinedRooms(avatar)) {
|
||||
auto addresses = room->GetConnectedAddresses();
|
||||
room->LeaveRoom(avatar);
|
||||
|
||||
client->SendLeaveRoomUpdate(addresses, avatar->GetAvatarId(), room->GetRoomId());
|
||||
}
|
||||
|
||||
client->SendFriendLogoutUpdates(avatar);
|
||||
|
||||
avatarService_->LogoutAvatar(avatar);
|
||||
}
|
||||
|
||||
RegistrarGetChatServer::RegistrarGetChatServer(RegistrarClient* client, const RequestType& request, ResponseType& response) {
|
||||
auto& config = client->GetNode()->GetConfig();
|
||||
|
||||
response.hostname = ToWideString(config.gatewayAddress);
|
||||
response.port = config.gatewayPort;
|
||||
}
|
||||
|
||||
RemoveBan::RemoveBan(GatewayClient* client, const RequestType& request, ResponseType& response)
|
||||
: avatarService_{client->GetNode()->GetAvatarService()}
|
||||
, roomService_{client->GetNode()->GetRoomService()} {
|
||||
LOG(INFO) << "REMOVEBAN request received - removing ban for: "
|
||||
<< FromWideString(request.destAvatarName) << "@"
|
||||
<< FromWideString(request.destAvatarAddress) << " from "
|
||||
<< FromWideString(request.destRoomAddress);
|
||||
|
||||
auto srcAvatar = avatarService_->GetAvatar(request.srcAvatarId);
|
||||
if (!srcAvatar) {
|
||||
throw ChatResultException{ChatResultCode::SRCAVATARDOESNTEXIST};
|
||||
}
|
||||
|
||||
auto bannedAvatar
|
||||
= avatarService_->GetAvatar(request.destAvatarName, request.destAvatarAddress);
|
||||
if (!bannedAvatar) {
|
||||
throw ChatResultException{ChatResultCode::DESTAVATARDOESNTEXIST};
|
||||
}
|
||||
|
||||
auto room = roomService_->GetRoom(request.destRoomAddress);
|
||||
if (!room) {
|
||||
throw ChatResultException{ChatResultCode::ADDRESSNOTROOM};
|
||||
}
|
||||
|
||||
response.destRoomId = room->GetRoomId();
|
||||
|
||||
room->RemoveBanned(srcAvatar->GetAvatarId(), bannedAvatar->GetAvatarId());
|
||||
}
|
||||
|
||||
RemoveFriend::RemoveFriend(
|
||||
GatewayClient* client, const RequestType& request, ResponseType& response)
|
||||
: avatarService_{client->GetNode()->GetAvatarService()} {
|
||||
LOG(INFO) << "REMOVEFRIEND request received - removing: " << FromWideString(request.destName)
|
||||
<< "@" << FromWideString(request.destAddress) << " from " << request.srcAvatarId
|
||||
<< "@" << FromWideString(request.srcAddress);
|
||||
|
||||
auto srcAvatar = avatarService_->GetAvatar(request.srcAvatarId);
|
||||
if (!srcAvatar) {
|
||||
throw ChatResultException{ChatResultCode::SRCAVATARDOESNTEXIST};
|
||||
}
|
||||
|
||||
auto destAvatar = avatarService_->GetAvatar(request.destName, request.destAddress);
|
||||
if (!destAvatar) {
|
||||
throw ChatResultException{ChatResultCode::DESTAVATARDOESNTEXIST};
|
||||
}
|
||||
|
||||
srcAvatar->RemoveFriend(destAvatar);
|
||||
}
|
||||
|
||||
RemoveIgnore::RemoveIgnore(GatewayClient* client, const RequestType& request, ResponseType& response)
|
||||
: avatarService_{client->GetNode()->GetAvatarService()} {
|
||||
LOG(INFO) << "REMOVEIGNORE request received - removing: " << FromWideString(request.destName) << "@"
|
||||
<< FromWideString(request.destAddress) << " from " << request.srcAvatarId << "@"
|
||||
<< FromWideString(request.srcAddress);
|
||||
|
||||
auto srcAvatar = avatarService_->GetAvatar(request.srcAvatarId);
|
||||
if (!srcAvatar) {
|
||||
throw ChatResultException{ChatResultCode::SRCAVATARDOESNTEXIST};
|
||||
}
|
||||
|
||||
auto destAvatar = avatarService_->GetAvatar(request.destName, request.destAddress);
|
||||
if (!srcAvatar) {
|
||||
throw ChatResultException{ChatResultCode::DESTAVATARDOESNTEXIST};
|
||||
}
|
||||
|
||||
srcAvatar->RemoveIgnore(destAvatar);
|
||||
}
|
||||
|
||||
RemoveInvite::RemoveInvite(
|
||||
GatewayClient* client, const RequestType& request, ResponseType& response)
|
||||
: avatarService_{client->GetNode()->GetAvatarService()}
|
||||
, roomService_{client->GetNode()->GetRoomService()} {
|
||||
LOG(INFO) << "REMOVEINVITE request received - removing invitation for: "
|
||||
<< FromWideString(request.destAvatarName) << "@"
|
||||
<< FromWideString(request.destAvatarAddress) << " to "
|
||||
<< FromWideString(request.destRoomAddress);
|
||||
|
||||
auto srcAvatar = avatarService_->GetAvatar(request.srcAvatarId);
|
||||
if (!srcAvatar) {
|
||||
throw ChatResultException{ChatResultCode::SRCAVATARDOESNTEXIST};
|
||||
}
|
||||
|
||||
auto invitedAvatar
|
||||
= avatarService_->GetAvatar(request.destAvatarName, request.destAvatarAddress);
|
||||
if (!invitedAvatar) {
|
||||
throw ChatResultException{ChatResultCode::DESTAVATARDOESNTEXIST};
|
||||
}
|
||||
|
||||
auto room = roomService_->GetRoom(request.destRoomAddress);
|
||||
if (!room) {
|
||||
throw ChatResultException{ChatResultCode::ADDRESSNOTROOM};
|
||||
}
|
||||
|
||||
response.destRoomId = room->GetRoomId();
|
||||
|
||||
room->RemoveInvite(srcAvatar->GetAvatarId(), invitedAvatar->GetAvatarId());
|
||||
}
|
||||
|
||||
RemoveModerator::RemoveModerator(GatewayClient* client, const RequestType& request, ResponseType& response)
|
||||
: avatarService_{client->GetNode()->GetAvatarService()}
|
||||
, roomService_{client->GetNode()->GetRoomService()} {
|
||||
LOG(INFO) << "REMOVEMODERATOR request recieved - removing: " << FromWideString(request.destAvatarName) << "@"
|
||||
<< FromWideString(request.destAvatarAddress) << " from " << FromWideString(request.destRoomAddress);
|
||||
|
||||
auto srcAvatar = avatarService_->GetAvatar(request.srcAvatarId);
|
||||
if (!srcAvatar) {
|
||||
throw ChatResultException{ChatResultCode::SRCAVATARDOESNTEXIST};
|
||||
}
|
||||
|
||||
auto moderatorAvatar = avatarService_->GetAvatar(request.destAvatarName, request.destAvatarAddress);
|
||||
if (!moderatorAvatar) {
|
||||
throw ChatResultException{ChatResultCode::DESTAVATARDOESNTEXIST};
|
||||
}
|
||||
|
||||
auto room = roomService_->GetRoom(request.destRoomAddress);
|
||||
if (!room) {
|
||||
throw ChatResultException{ChatResultCode::ADDRESSNOTROOM};
|
||||
}
|
||||
|
||||
response.destRoomId = room->GetRoomId();
|
||||
|
||||
room->RemoveModerator(srcAvatar->GetAvatarId(), moderatorAvatar->GetAvatarId());
|
||||
}
|
||||
|
||||
SendInstantMessage::SendInstantMessage(
|
||||
GatewayClient* client, const RequestType& request, ResponseType& response)
|
||||
: avatarService_{client->GetNode()->GetAvatarService()} {
|
||||
LOG(INFO) << "SENDINSTANTMESSAGE request received "
|
||||
<< " - from " << request.srcAvatarId << "@" << FromWideString(request.srcAddress) << " to "
|
||||
<< FromWideString(request.destName) << "@" << FromWideString(request.destAddress);
|
||||
|
||||
auto srcAvatar = avatarService_->GetAvatar(request.srcAvatarId);
|
||||
if (!srcAvatar) {
|
||||
throw ChatResultException(ChatResultCode::SRCAVATARDOESNTEXIST);
|
||||
}
|
||||
|
||||
auto destAvatar = avatarService_->GetAvatar(request.destName, request.destAddress);
|
||||
if (!destAvatar) {
|
||||
throw ChatResultException(ChatResultCode::DESTAVATARDOESNTEXIST);
|
||||
}
|
||||
|
||||
if (destAvatar->IsIgnored(srcAvatar)) {
|
||||
throw ChatResultException(ChatResultCode::IGNORING);
|
||||
}
|
||||
|
||||
client->SendInstantMessageUpdate(srcAvatar, destAvatar, request.message, request.oob);
|
||||
}
|
||||
|
||||
SendPersistentMessage::SendPersistentMessage(GatewayClient* client, const RequestType& request, ResponseType& response)
|
||||
: avatarService_{client->GetNode()->GetAvatarService()}
|
||||
, messageService_{client->GetNode()->GetMessageService()} {
|
||||
LOG(INFO) << "SENDPERSISTENTMESSAGE request received:";
|
||||
|
||||
auto destAvatar = avatarService_->GetAvatar(request.destName, request.destAddress);
|
||||
if (!destAvatar) {
|
||||
throw ChatResultException{ChatResultCode::DESTAVATARDOESNTEXIST};
|
||||
}
|
||||
|
||||
PersistentMessage message;
|
||||
|
||||
if (request.avatarPresence) {
|
||||
auto srcAvatar = avatarService_->GetAvatar(request.srcAvatarId);
|
||||
if (!srcAvatar) {
|
||||
throw ChatResultException{ChatResultCode::SRCAVATARDOESNTEXIST};
|
||||
}
|
||||
|
||||
if (destAvatar->IsIgnored(srcAvatar)) {
|
||||
throw ChatResultException(ChatResultCode::IGNORING);
|
||||
}
|
||||
|
||||
message.header.fromName = srcAvatar->GetName();
|
||||
message.header.fromAddress = srcAvatar->GetAddress();
|
||||
} else {
|
||||
message.header.fromName = request.srcName;
|
||||
message.header.fromAddress = destAvatar->GetAddress();
|
||||
}
|
||||
|
||||
message.header.sentTime = static_cast<uint32_t>(std::time(nullptr));
|
||||
message.header.avatarId = destAvatar->GetAvatarId();
|
||||
message.header.subject = request.subject;
|
||||
message.header.category = request.category;
|
||||
message.message = request.msg;
|
||||
message.oob = request.oob;
|
||||
|
||||
messageService_->StoreMessage(message);
|
||||
|
||||
response.messageId = message.header.messageId;
|
||||
|
||||
client->SendPersistentMessageUpdate(destAvatar, message.header);
|
||||
}
|
||||
|
||||
SendRoomMessage::SendRoomMessage(
|
||||
GatewayClient* client, const RequestType& request, ResponseType& response)
|
||||
: avatarService_{client->GetNode()->GetAvatarService()}
|
||||
, roomService_{client->GetNode()->GetRoomService()} {
|
||||
LOG(INFO) << "SENDROOMMESSAGE request received "
|
||||
<< " - from " << request.srcAvatarId << "@" << FromWideString(request.srcAddress)
|
||||
<< " to " << FromWideString(request.destRoomAddress);
|
||||
|
||||
auto srcAvatar = avatarService_->GetAvatar(request.srcAvatarId);
|
||||
if (!srcAvatar) {
|
||||
throw ChatResultException(ChatResultCode::SRCAVATARDOESNTEXIST);
|
||||
}
|
||||
|
||||
auto room = roomService_->GetRoom(request.destRoomAddress);
|
||||
if (!room) {
|
||||
throw ChatResultException(ChatResultCode::ADDRESSNOTROOM);
|
||||
}
|
||||
|
||||
response.roomId = room->GetRoomId();
|
||||
|
||||
client->SendRoomMessageUpdate(
|
||||
srcAvatar, room, room->GetNextMessageId(), request.message, request.oob);
|
||||
}
|
||||
|
||||
SetApiVersion::SetApiVersion(
|
||||
GatewayClient* client, const RequestType& request, ResponseType& response) {
|
||||
LOG(INFO) << "SETAPIVERSION request received - version: " << request.version;
|
||||
response.version = client->GetNode()->GetConfig().version;
|
||||
response.result = (response.version == request.version)
|
||||
? ChatResultCode::SUCCESS
|
||||
: ChatResultCode::WRONGCHATSERVERFORREQUEST;
|
||||
}
|
||||
|
||||
SetAvatarAttributes::SetAvatarAttributes(GatewayClient* client, const RequestType& request, ResponseType& response)
|
||||
: avatarService_{client->GetNode()->GetAvatarService()} {
|
||||
LOG(INFO) << "SETAVATARATTRIBUTES request received - avatar: " << request.avatarId;
|
||||
|
||||
auto avatar = avatarService_->GetAvatar(request.avatarId);
|
||||
if (!avatar) {
|
||||
throw ChatResultException{ChatResultCode::SRCAVATARDOESNTEXIST};
|
||||
}
|
||||
|
||||
response.avatar = avatar;
|
||||
|
||||
if (avatar->GetAttributes() != request.avatarAttributes) {
|
||||
avatar->SetAttributes(request.avatarAttributes);
|
||||
|
||||
if (request.persistent != 0) {
|
||||
avatarService_->PersistAvatar(avatar);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
UpdatePersistentMessage::UpdatePersistentMessage(GatewayClient* client, const RequestType& request, ResponseType& response)
|
||||
: messageService_{client->GetNode()->GetMessageService()} {
|
||||
LOG(INFO) << "UPDATEPERSISTENTMESSAGE request received";
|
||||
messageService_->UpdateMessageStatus(
|
||||
request.srcAvatarId, request.messageId, request.status);
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "ChatEnums.hpp"
|
||||
|
||||
class RegistrarClient;
|
||||
|
||||
/** Begin REGISTRAR_GETCHATSERVER */
|
||||
|
||||
struct ReqRegistrarGetChatServer {
|
||||
const ChatRequestType type = ChatRequestType::REGISTRAR_GETCHATSERVER;
|
||||
uint32_t track;
|
||||
std::u16string hostname;
|
||||
uint16_t port;
|
||||
};
|
||||
|
||||
template <typename StreamT>
|
||||
void read(StreamT& ar, ReqRegistrarGetChatServer& data) {
|
||||
read(ar, data.track);
|
||||
read(ar, data.hostname);
|
||||
read(ar, data.port);
|
||||
}
|
||||
|
||||
/** Begin REGISTRAR_GETCHATSERVER */
|
||||
|
||||
struct ResRegistrarGetChatServer {
|
||||
ResRegistrarGetChatServer(
|
||||
uint32_t track_)
|
||||
: track{track_}
|
||||
, result{ChatResultCode::SUCCESS} {}
|
||||
|
||||
const ChatResponseType type = ChatResponseType::REGISTRAR_GETCHATSERVER;
|
||||
uint32_t track;
|
||||
ChatResultCode result;
|
||||
std::u16string hostname;
|
||||
uint16_t port;
|
||||
};
|
||||
|
||||
template <typename StreamT>
|
||||
void write(StreamT& ar, const ResRegistrarGetChatServer& data) {
|
||||
write(ar, data.type);
|
||||
write(ar, data.track);
|
||||
write(ar, data.result);
|
||||
write(ar, data.hostname);
|
||||
write(ar, data.port);
|
||||
}
|
||||
|
||||
class RegistrarGetChatServer {
|
||||
public:
|
||||
using RequestType = ReqRegistrarGetChatServer;
|
||||
using ResponseType = ResRegistrarGetChatServer;
|
||||
|
||||
RegistrarGetChatServer(RegistrarClient* client, const RequestType& request, ResponseType& response);
|
||||
};
|
||||
@@ -0,0 +1,63 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "ChatEnums.hpp"
|
||||
|
||||
class ChatAvatarService;
|
||||
class ChatRoomService;
|
||||
class GatewayClient;
|
||||
|
||||
/** Begin REMOVEBAN */
|
||||
|
||||
struct ReqRemoveBan {
|
||||
const ChatRequestType type = ChatRequestType::REMOVEBAN;
|
||||
uint32_t track;
|
||||
uint32_t srcAvatarId;
|
||||
std::u16string destAvatarName;
|
||||
std::u16string destAvatarAddress;
|
||||
std::u16string destRoomAddress;
|
||||
std::u16string srcAddress;
|
||||
};
|
||||
|
||||
template <typename StreamT>
|
||||
void read(StreamT& ar, ReqRemoveBan& data) {
|
||||
read(ar, data.track);
|
||||
read(ar, data.srcAvatarId);
|
||||
read(ar, data.destAvatarName);
|
||||
read(ar, data.destAvatarAddress);
|
||||
read(ar, data.destRoomAddress);
|
||||
read(ar, data.srcAddress);
|
||||
}
|
||||
|
||||
/** Begin REMOVEBAN */
|
||||
|
||||
struct ResRemoveBan {
|
||||
explicit ResRemoveBan(uint32_t track_)
|
||||
: track{track_}
|
||||
, result{ChatResultCode::SUCCESS} {}
|
||||
|
||||
const ChatResponseType type = ChatResponseType::REMOVEBAN;
|
||||
uint32_t track;
|
||||
ChatResultCode result;
|
||||
uint32_t destRoomId;
|
||||
};
|
||||
|
||||
template <typename StreamT>
|
||||
void write(StreamT& ar, const ResRemoveBan& data) {
|
||||
write(ar, data.type);
|
||||
write(ar, data.track);
|
||||
write(ar, data.result);
|
||||
write(ar, data.destRoomId);
|
||||
}
|
||||
|
||||
class RemoveBan {
|
||||
public:
|
||||
using RequestType = ReqRemoveBan;
|
||||
using ResponseType = ResRemoveBan;
|
||||
|
||||
RemoveBan(GatewayClient* client, const RequestType& request, ResponseType& response);
|
||||
|
||||
private:
|
||||
ChatAvatarService* avatarService_;
|
||||
ChatRoomService* roomService_;
|
||||
};
|
||||
@@ -0,0 +1,58 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "ChatEnums.hpp"
|
||||
|
||||
class ChatAvatarService;
|
||||
class ChatRoomService;
|
||||
class GatewayClient;
|
||||
|
||||
/** Begin REMOVEFRIEND */
|
||||
|
||||
struct ReqRemoveFriend {
|
||||
const ChatRequestType type = ChatRequestType::REMOVEFRIEND;
|
||||
uint32_t track;
|
||||
uint32_t srcAvatarId;
|
||||
std::u16string destName;
|
||||
std::u16string destAddress;
|
||||
std::u16string srcAddress;
|
||||
};
|
||||
|
||||
template <typename StreamT>
|
||||
void read(StreamT& ar, ReqRemoveFriend& data) {
|
||||
read(ar, data.track);
|
||||
read(ar, data.srcAvatarId);
|
||||
read(ar, data.destName);
|
||||
read(ar, data.destAddress);
|
||||
read(ar, data.srcAddress);
|
||||
}
|
||||
|
||||
/** Begin REMOVEFRIEND */
|
||||
|
||||
struct ResRemoveFriend {
|
||||
ResRemoveFriend(uint32_t track_)
|
||||
: track{track_}
|
||||
, result{ChatResultCode::SUCCESS} {}
|
||||
|
||||
const ChatResponseType type = ChatResponseType::REMOVEFRIEND;
|
||||
uint32_t track;
|
||||
ChatResultCode result;
|
||||
};
|
||||
|
||||
template <typename StreamT>
|
||||
void write(StreamT& ar, const ResRemoveFriend& data) {
|
||||
write(ar, data.type);
|
||||
write(ar, data.track);
|
||||
write(ar, data.result);
|
||||
}
|
||||
|
||||
class RemoveFriend {
|
||||
public:
|
||||
using RequestType = ReqRemoveFriend;
|
||||
using ResponseType = ResRemoveFriend;
|
||||
|
||||
RemoveFriend(GatewayClient* client, const RequestType& request, ResponseType& response);
|
||||
|
||||
private:
|
||||
ChatAvatarService* avatarService_;
|
||||
};
|
||||
@@ -0,0 +1,58 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "ChatEnums.hpp"
|
||||
|
||||
class ChatAvatarService;
|
||||
class ChatRoomService;
|
||||
class GatewayClient;
|
||||
|
||||
/** Begin REMOVEIGNORE */
|
||||
|
||||
struct ReqRemoveIgnore {
|
||||
const ChatRequestType type = ChatRequestType::REMOVEIGNORE;
|
||||
uint32_t track;
|
||||
uint32_t srcAvatarId;
|
||||
std::u16string destName;
|
||||
std::u16string destAddress;
|
||||
std::u16string srcAddress;
|
||||
};
|
||||
|
||||
template <typename StreamT>
|
||||
void read(StreamT& ar, ReqRemoveIgnore& data) {
|
||||
read(ar, data.track);
|
||||
read(ar, data.srcAvatarId);
|
||||
read(ar, data.destName);
|
||||
read(ar, data.destAddress);
|
||||
read(ar, data.srcAddress);
|
||||
}
|
||||
|
||||
/** Begin REMOVEIGNORE */
|
||||
|
||||
struct ResRemoveIgnore {
|
||||
ResRemoveIgnore(uint32_t track_)
|
||||
: track{track_}
|
||||
, result{ChatResultCode::SUCCESS} {}
|
||||
|
||||
const ChatResponseType type = ChatResponseType::REMOVEIGNORE;
|
||||
uint32_t track;
|
||||
ChatResultCode result;
|
||||
};
|
||||
|
||||
template <typename StreamT>
|
||||
void write(StreamT& ar, const ResRemoveIgnore& data) {
|
||||
write(ar, data.type);
|
||||
write(ar, data.track);
|
||||
write(ar, data.result);
|
||||
}
|
||||
|
||||
class RemoveIgnore {
|
||||
public:
|
||||
using RequestType = ReqRemoveIgnore;
|
||||
using ResponseType = ResRemoveIgnore;
|
||||
|
||||
RemoveIgnore(GatewayClient* client, const RequestType& request, ResponseType& response);
|
||||
|
||||
private:
|
||||
ChatAvatarService* avatarService_;
|
||||
};
|
||||
@@ -0,0 +1,63 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "ChatEnums.hpp"
|
||||
|
||||
class ChatAvatarService;
|
||||
class ChatRoomService;
|
||||
class GatewayClient;
|
||||
|
||||
/** Begin REMOVEINVITE */
|
||||
|
||||
struct ReqRemoveInvite {
|
||||
const ChatRequestType type = ChatRequestType::REMOVEINVITE;
|
||||
uint32_t track;
|
||||
uint32_t srcAvatarId;
|
||||
std::u16string destAvatarName;
|
||||
std::u16string destAvatarAddress;
|
||||
std::u16string destRoomAddress;
|
||||
std::u16string srcAddress;
|
||||
};
|
||||
|
||||
template <typename StreamT>
|
||||
void read(StreamT& ar, ReqRemoveInvite& data) {
|
||||
read(ar, data.track);
|
||||
read(ar, data.srcAvatarId);
|
||||
read(ar, data.destAvatarName);
|
||||
read(ar, data.destAvatarAddress);
|
||||
read(ar, data.destRoomAddress);
|
||||
read(ar, data.srcAddress);
|
||||
}
|
||||
|
||||
/** Begin REMOVEINVITE */
|
||||
|
||||
struct ResRemoveInvite {
|
||||
explicit ResRemoveInvite(uint32_t track_)
|
||||
: track{track_}
|
||||
, result{ChatResultCode::SUCCESS} {}
|
||||
|
||||
const ChatResponseType type = ChatResponseType::REMOVEINVITE;
|
||||
uint32_t track;
|
||||
ChatResultCode result;
|
||||
uint32_t destRoomId;
|
||||
};
|
||||
|
||||
template <typename StreamT>
|
||||
void write(StreamT& ar, const ResRemoveInvite& data) {
|
||||
write(ar, data.type);
|
||||
write(ar, data.track);
|
||||
write(ar, data.result);
|
||||
write(ar, data.destRoomId);
|
||||
}
|
||||
|
||||
class RemoveInvite {
|
||||
public:
|
||||
using RequestType = ReqRemoveInvite;
|
||||
using ResponseType = ResRemoveInvite;
|
||||
|
||||
RemoveInvite(GatewayClient* client, const RequestType& request, ResponseType& response);
|
||||
|
||||
private:
|
||||
ChatAvatarService* avatarService_;
|
||||
ChatRoomService* roomService_;
|
||||
};
|
||||
@@ -0,0 +1,63 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "ChatEnums.hpp"
|
||||
|
||||
class ChatAvatarService;
|
||||
class ChatRoomService;
|
||||
class GatewayClient;
|
||||
|
||||
/** Begin REMOVEMODERATOR */
|
||||
|
||||
struct ReqRemoveModerator {
|
||||
const ChatRequestType type = ChatRequestType::REMOVEMODERATOR;
|
||||
uint32_t track;
|
||||
uint32_t srcAvatarId;
|
||||
std::u16string destAvatarName;
|
||||
std::u16string destAvatarAddress;
|
||||
std::u16string destRoomAddress;
|
||||
std::u16string srcAddress;
|
||||
};
|
||||
|
||||
template <typename StreamT>
|
||||
void read(StreamT& ar, ReqRemoveModerator& data) {
|
||||
read(ar, data.track);
|
||||
read(ar, data.srcAvatarId);
|
||||
read(ar, data.destAvatarName);
|
||||
read(ar, data.destAvatarAddress);
|
||||
read(ar, data.destRoomAddress);
|
||||
read(ar, data.srcAddress);
|
||||
}
|
||||
|
||||
/** Begin REMOVEMODERATOR */
|
||||
|
||||
struct ResRemoveModerator {
|
||||
ResRemoveModerator(uint32_t track_)
|
||||
: track{track_}
|
||||
, result{ChatResultCode::SUCCESS} {}
|
||||
|
||||
const ChatResponseType type = ChatResponseType::REMOVEMODERATOR;
|
||||
uint32_t track;
|
||||
ChatResultCode result;
|
||||
uint32_t destRoomId;
|
||||
};
|
||||
|
||||
template <typename StreamT>
|
||||
void write(StreamT& ar, const ResRemoveModerator& data) {
|
||||
write(ar, data.type);
|
||||
write(ar, data.track);
|
||||
write(ar, data.result);
|
||||
write(ar, data.destRoomId);
|
||||
}
|
||||
|
||||
class RemoveModerator {
|
||||
public:
|
||||
using RequestType = ReqRemoveModerator;
|
||||
using ResponseType = ResRemoveModerator;
|
||||
|
||||
RemoveModerator(GatewayClient* client, const RequestType& request, ResponseType& response);
|
||||
|
||||
private:
|
||||
ChatAvatarService* avatarService_;
|
||||
ChatRoomService* roomService_;
|
||||
};
|
||||
@@ -0,0 +1,62 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "ChatEnums.hpp"
|
||||
|
||||
class ChatAvatarService;
|
||||
class ChatRoomService;
|
||||
class GatewayClient;
|
||||
|
||||
/** Begin SENDINSTANTMESSAGE */
|
||||
|
||||
struct ReqSendInstantMessage {
|
||||
const ChatRequestType type = ChatRequestType::SENDINSTANTMESSAGE;
|
||||
uint32_t track;
|
||||
uint32_t srcAvatarId;
|
||||
std::u16string destName;
|
||||
std::u16string destAddress;
|
||||
std::u16string message;
|
||||
std::u16string oob;
|
||||
std::u16string srcAddress;
|
||||
};
|
||||
|
||||
template <typename StreamT>
|
||||
void read(StreamT& ar, ReqSendInstantMessage& data) {
|
||||
read(ar, data.track);
|
||||
read(ar, data.srcAvatarId);
|
||||
read(ar, data.destName);
|
||||
read(ar, data.destAddress);
|
||||
read(ar, data.message);
|
||||
read(ar, data.oob);
|
||||
read(ar, data.srcAddress);
|
||||
}
|
||||
|
||||
/** Begin SENDINSTANTMESSAGE */
|
||||
|
||||
struct ResSendInstantMessage {
|
||||
ResSendInstantMessage(uint32_t track_)
|
||||
: track{track_}
|
||||
, result{ChatResultCode::SUCCESS} {}
|
||||
|
||||
const ChatResponseType type = ChatResponseType::SENDINSTANTMESSAGE;
|
||||
uint32_t track;
|
||||
ChatResultCode result;
|
||||
};
|
||||
|
||||
template <typename StreamT>
|
||||
void write(StreamT& ar, const ResSendInstantMessage& data) {
|
||||
write(ar, data.type);
|
||||
write(ar, data.track);
|
||||
write(ar, data.result);
|
||||
}
|
||||
|
||||
class SendInstantMessage {
|
||||
public:
|
||||
using RequestType = ReqSendInstantMessage;
|
||||
using ResponseType = ResSendInstantMessage;
|
||||
|
||||
SendInstantMessage(GatewayClient* client, const RequestType& request, ResponseType& response);
|
||||
|
||||
private:
|
||||
ChatAvatarService* avatarService_;
|
||||
};
|
||||
@@ -0,0 +1,83 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "ChatEnums.hpp"
|
||||
|
||||
class ChatAvatarService;
|
||||
class PersistentMessageService;
|
||||
class GatewayClient;
|
||||
|
||||
/** Begin SENDPERSISTENTMESSAGE */
|
||||
|
||||
struct ReqSendPersistentMessage {
|
||||
const ChatRequestType type = ChatRequestType::SENDPERSISTENTMESSAGE;
|
||||
uint32_t track;
|
||||
uint16_t avatarPresence;
|
||||
uint32_t srcAvatarId;
|
||||
std::u16string srcName;
|
||||
std::u16string destName;
|
||||
std::u16string destAddress;
|
||||
std::u16string subject;
|
||||
std::u16string msg;
|
||||
std::u16string oob;
|
||||
std::u16string category;
|
||||
bool enforceInboxLimit;
|
||||
uint32_t categoryLimit;
|
||||
};
|
||||
|
||||
template <typename StreamT>
|
||||
void read(StreamT& ar, ReqSendPersistentMessage& data) {
|
||||
read(ar, data.track);
|
||||
read(ar, data.avatarPresence);
|
||||
|
||||
if (data.avatarPresence) {
|
||||
read(ar, data.srcAvatarId);
|
||||
} else {
|
||||
read(ar, data.srcName);
|
||||
}
|
||||
|
||||
read(ar, data.destName);
|
||||
read(ar, data.destAddress);
|
||||
read(ar, data.subject);
|
||||
read(ar, data.msg);
|
||||
read(ar, data.oob);
|
||||
read(ar, data.category);
|
||||
read(ar, data.enforceInboxLimit);
|
||||
read(ar, data.categoryLimit);
|
||||
}
|
||||
|
||||
/** Begin SENDPERSISTENTMESSAGE */
|
||||
|
||||
struct ResSendPersistentMessage {
|
||||
ResSendPersistentMessage(uint32_t track_)
|
||||
: track{track_}
|
||||
, result{ChatResultCode::SUCCESS} {}
|
||||
|
||||
const ChatResponseType type = ChatResponseType::SENDPERSISTENTMESSAGE;
|
||||
uint32_t track;
|
||||
ChatResultCode result;
|
||||
uint32_t messageId;
|
||||
};
|
||||
|
||||
template <typename StreamT>
|
||||
void write(StreamT& ar, const ResSendPersistentMessage& data) {
|
||||
write(ar, data.type);
|
||||
write(ar, data.track);
|
||||
write(ar, data.result);
|
||||
|
||||
if (data.result == ChatResultCode::SUCCESS) {
|
||||
write(ar, data.messageId);
|
||||
}
|
||||
}
|
||||
|
||||
class SendPersistentMessage {
|
||||
public:
|
||||
using RequestType = ReqSendPersistentMessage;
|
||||
using ResponseType = ResSendPersistentMessage;
|
||||
|
||||
SendPersistentMessage(GatewayClient* client, const RequestType& request, ResponseType& response);
|
||||
|
||||
private:
|
||||
ChatAvatarService* avatarService_;
|
||||
PersistentMessageService* messageService_;
|
||||
};
|
||||
@@ -0,0 +1,68 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "ChatEnums.hpp"
|
||||
|
||||
class ChatAvatarService;
|
||||
class ChatRoomService;
|
||||
class GatewayClient;
|
||||
|
||||
/** Begin SENDROOMMESSAGE */
|
||||
|
||||
struct ReqSendRoomMessage {
|
||||
const ChatRequestType type = ChatRequestType::SENDROOMMESSAGE;
|
||||
uint32_t track;
|
||||
uint32_t srcAvatarId;
|
||||
std::u16string destRoomAddress;
|
||||
std::u16string message;
|
||||
std::u16string oob;
|
||||
std::u16string srcAddress;
|
||||
};
|
||||
|
||||
template <typename StreamT>
|
||||
void read(StreamT& ar, ReqSendRoomMessage& data) {
|
||||
read(ar, data.track);
|
||||
read(ar, data.srcAvatarId);
|
||||
read(ar, data.destRoomAddress);
|
||||
read(ar, data.message);
|
||||
read(ar, data.oob);
|
||||
read(ar, data.srcAddress);
|
||||
}
|
||||
|
||||
/** Begin SENDROOMMESSAGE */
|
||||
|
||||
struct ResSendRoomMessage {
|
||||
explicit ResSendRoomMessage(uint32_t track_)
|
||||
: track{track_}
|
||||
, result{ChatResultCode::SUCCESS} {}
|
||||
|
||||
ResSendRoomMessage(uint32_t track_, ChatResultCode result_, uint32_t roomId_)
|
||||
: track{track_}
|
||||
, result{result_}
|
||||
, roomId{roomId_} {}
|
||||
|
||||
const ChatResponseType type = ChatResponseType::SENDROOMMESSAGE;
|
||||
uint32_t track;
|
||||
ChatResultCode result;
|
||||
uint32_t roomId;
|
||||
};
|
||||
|
||||
template <typename StreamT>
|
||||
void write(StreamT& ar, const ResSendRoomMessage& data) {
|
||||
write(ar, data.type);
|
||||
write(ar, data.track);
|
||||
write(ar, data.result);
|
||||
write(ar, data.roomId);
|
||||
}
|
||||
|
||||
class SendRoomMessage {
|
||||
public:
|
||||
using RequestType = ReqSendRoomMessage;
|
||||
using ResponseType = ResSendRoomMessage;
|
||||
|
||||
SendRoomMessage(GatewayClient* client, const RequestType& request, ResponseType& response);
|
||||
|
||||
private:
|
||||
ChatAvatarService* avatarService_;
|
||||
ChatRoomService* roomService_;
|
||||
};
|
||||
@@ -0,0 +1,55 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "ChatEnums.hpp"
|
||||
|
||||
class ChatAvatarService;
|
||||
class ChatRoomService;
|
||||
class GatewayClient;
|
||||
|
||||
/** Begin SETAPIVERSION */
|
||||
|
||||
struct ReqSetApiVersion {
|
||||
const ChatRequestType type = ChatRequestType::SETAPIVERSION;
|
||||
uint32_t track;
|
||||
uint32_t version;
|
||||
};
|
||||
|
||||
template <typename StreamT>
|
||||
void read(StreamT& ar, ReqSetApiVersion& data) {
|
||||
read(ar, data.track);
|
||||
read(ar, data.version);
|
||||
}
|
||||
|
||||
/** Begin SETAPIVERSION */
|
||||
|
||||
struct ResSetApiVersion {
|
||||
ResSetApiVersion(uint32_t track_)
|
||||
: track{track_}
|
||||
, result{ChatResultCode::SUCCESS} {}
|
||||
|
||||
const ChatResponseType type = ChatResponseType::SETAPIVERSION;
|
||||
uint32_t track;
|
||||
ChatResultCode result;
|
||||
uint32_t version;
|
||||
};
|
||||
|
||||
template <typename StreamT>
|
||||
void write(StreamT& ar, const ResSetApiVersion& data) {
|
||||
write(ar, data.type);
|
||||
write(ar, data.track);
|
||||
write(ar, data.result);
|
||||
write(ar, data.version);
|
||||
}
|
||||
|
||||
class SetApiVersion {
|
||||
public:
|
||||
using RequestType = ReqSetApiVersion;
|
||||
using ResponseType = ResSetApiVersion;
|
||||
|
||||
SetApiVersion(GatewayClient* client, const RequestType& request, ResponseType& response);
|
||||
|
||||
private:
|
||||
ChatAvatarService* avatarService_;
|
||||
ChatRoomService* roomService_;
|
||||
};
|
||||
@@ -0,0 +1,63 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "ChatAvatar.hpp"
|
||||
#include "ChatEnums.hpp"
|
||||
|
||||
class ChatAvatarService;
|
||||
class GatewayClient;
|
||||
|
||||
/** Begin SETAVATARATTRIBUTES */
|
||||
|
||||
struct ReqSetAvatarAttributes {
|
||||
const ChatRequestType type = ChatRequestType::SETAVATARATTRIBUTES;
|
||||
uint32_t track;
|
||||
uint32_t avatarId;
|
||||
uint32_t avatarAttributes;
|
||||
uint32_t persistent;
|
||||
std::u16string srcAddress;
|
||||
};
|
||||
|
||||
template <typename StreamT>
|
||||
void read(StreamT& ar, ReqSetAvatarAttributes& data) {
|
||||
read(ar, data.track);
|
||||
read(ar, data.avatarId);
|
||||
read(ar, data.avatarAttributes);
|
||||
read(ar, data.persistent);
|
||||
read(ar, data.srcAddress);
|
||||
}
|
||||
|
||||
/** Begin SETAVATARATTRIBUTES */
|
||||
|
||||
struct ResSetAvatarAttributes {
|
||||
ResSetAvatarAttributes(uint32_t track_)
|
||||
: track{track_}
|
||||
, result{ChatResultCode::SUCCESS} {}
|
||||
|
||||
const ChatResponseType type = ChatResponseType::SETAVATARATTRIBUTES;
|
||||
uint32_t track;
|
||||
ChatResultCode result;
|
||||
const ChatAvatar* avatar;
|
||||
};
|
||||
|
||||
template <typename StreamT>
|
||||
void write(StreamT& ar, const ResSetAvatarAttributes& data) {
|
||||
write(ar, data.type);
|
||||
write(ar, data.track);
|
||||
write(ar, data.result);
|
||||
|
||||
if (data.result == ChatResultCode::SUCCESS) {
|
||||
write(ar, data.avatar);
|
||||
}
|
||||
}
|
||||
|
||||
class SetAvatarAttributes {
|
||||
public:
|
||||
using RequestType = ReqSetAvatarAttributes;
|
||||
using ResponseType = ResSetAvatarAttributes;
|
||||
|
||||
SetAvatarAttributes(GatewayClient* client, const RequestType& request, ResponseType& response);
|
||||
|
||||
private:
|
||||
ChatAvatarService* avatarService_;
|
||||
};
|
||||
@@ -0,0 +1,56 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "ChatEnums.hpp"
|
||||
#include "PersistentMessage.hpp"
|
||||
|
||||
class PersistentMessageService;
|
||||
class GatewayClient;
|
||||
|
||||
/** Begin UPDATEPERSISTENTMESSAGE */
|
||||
|
||||
struct ReqUpdatePersistentMessage {
|
||||
const ChatRequestType type = ChatRequestType::UPDATEPERSISTENTMESSAGE;
|
||||
uint32_t track;
|
||||
uint32_t srcAvatarId;
|
||||
uint32_t messageId;
|
||||
PersistentState status;
|
||||
};
|
||||
|
||||
template <typename StreamT>
|
||||
void read(StreamT& ar, ReqUpdatePersistentMessage& data) {
|
||||
read(ar, data.track);
|
||||
read(ar, data.srcAvatarId);
|
||||
read(ar, data.messageId);
|
||||
read(ar, data.status);
|
||||
}
|
||||
|
||||
/** Begin UPDATEPERSISTENTMESSAGE */
|
||||
|
||||
struct ResUpdatePersistentMessage {
|
||||
ResUpdatePersistentMessage(uint32_t track_)
|
||||
: track{track_}
|
||||
, result{ChatResultCode::SUCCESS} {}
|
||||
|
||||
const ChatResponseType type = ChatResponseType::UPDATEPERSISTENTMESSAGE;
|
||||
uint32_t track;
|
||||
ChatResultCode result;
|
||||
};
|
||||
|
||||
template <typename StreamT>
|
||||
void write(StreamT& ar, const ResUpdatePersistentMessage& data) {
|
||||
write(ar, data.type);
|
||||
write(ar, data.track);
|
||||
write(ar, data.result);
|
||||
}
|
||||
|
||||
class UpdatePersistentMessage {
|
||||
public:
|
||||
using RequestType = ReqUpdatePersistentMessage;
|
||||
using ResponseType = ResUpdatePersistentMessage;
|
||||
|
||||
UpdatePersistentMessage(GatewayClient* client, const RequestType& request, ResponseType& response);
|
||||
|
||||
private:
|
||||
PersistentMessageService* messageService_;
|
||||
};
|
||||
Reference in New Issue
Block a user