Split into library and application code to prepare for future stationapi based apps

This commit is contained in:
apathy
2016-07-26 20:00:38 -07:00
parent 05c07dc3c3
commit 2d4ddee956
74 changed files with 109 additions and 102 deletions
+84
View File
@@ -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()
+91
View File
@@ -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;
}
+131
View File
@@ -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());
}
+488
View File
@@ -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;
}
+65
View File
@@ -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_;
};
+154
View File
@@ -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 "";
}
+252
View File
@@ -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);
+307
View File
@@ -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; }));
}
+170
View File
@@ -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);
}
+419
View File
@@ -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_)};
}
}
+59
View File
@@ -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_;
};
+38
View File
@@ -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());
}
+245
View File
@@ -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()});
}
}
+69
View File
@@ -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_;
};
+39
View File
@@ -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() {}
+45
View File
@@ -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_;
};
+298
View File
@@ -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);
}
+51
View File
@@ -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_;
};
+45
View File
@@ -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;
}
}
+22
View File
@@ -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_;
};
+17
View File
@@ -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() {}
+20
View File
@@ -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_;
};
+17
View File
@@ -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();
}
+25
View File
@@ -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_;
};
+24
View File
@@ -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;
};
+115
View File
@@ -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
+63
View File
@@ -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_;
};
+62
View File
@@ -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_;
};
+58
View File
@@ -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_;
};
+63
View File
@@ -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_;
};
+63
View File
@@ -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_;
};
+83
View File
@@ -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_;
};
+59
View File
@@ -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_;
};
+89
View File
@@ -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);
}
+70
View File
@@ -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_;
};
+68
View File
@@ -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_;
};
+65
View File
@@ -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_;
};
+67
View File
@@ -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_;
};
+63
View File
@@ -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_;
};
+59
View File
@@ -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_;
};
+69
View File
@@ -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_;
};
+54
View File
@@ -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_;
};
+727
View File
@@ -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);
};
+63
View File
@@ -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_;
};
+58
View File
@@ -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_;
};
+58
View File
@@ -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_;
};
+63
View File
@@ -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_;
};