mirror of
https://github.com/SWG-Source/stationapi.git
synced 2026-07-13 21:01:03 -04:00
Initial project commit
Added udplibrary - consider making this an external dependency Add basic application loop and a ServiceContainer class. Added basic registrar service Clang format Rename RegistrarService to RegistrarNode Add serialization helpers Process GetChatServer message Add tools for streaming binary data to output Move Connection management into NodeClient Refactored NodeClient to be the layer between the application and the udp library that handles tasks specific to translating from one system to the other Abstracted common bits of the node class out to a reusable base for the gateway as well. Added stub classes for gateway node and clients Add missing OnTick call Added SetApiVersion handler and related messages Use :: to prevent the overload selected by argument dependent lookup from being used Enable C++14 building on gcc/clang Add missing header Iterator returned by remove_if should not be a ref Added start of ChatAvatarService Add serialization support directly for strongly typed enums Make sending message calls more concise Add stubs for getting avatars from the online list and from persistent storage Add SQLite3 dependency Fixed variable name regression in last commit Make param for SendMessage const Tweak network message logging Removed ServiceContainer, each Node instance serves as its own "service container" Remove unused file Open database connection in GatewayNode to pass to services that might need it. GetPersistedAvatarByNameAndAddress implemented Refactored class to return boost::optional from "Find" member functions. Move result codes enum to its own header as it will be included in other locations. Handle LoginAvatar messages Added missing include Fixed compile error on gcc Use optional avatar arguments for network messages where an avatar might not exist due to an error Added simple sql script for creating the necessary table structure. Move init_database.sql to extras Add a travis-ci file Added newline to end of file Changed min required cmake version Modern C++ compiler support on travis-ci Disable clang for now (issue on travis-ci end) Missed disabling the llvm toolchain Add the travis-ci build badge to the README, which also serves as the project landing page Added a notes on the dependencies for swgchat and simple build instructions. Added ChatRoom and related service class for managing rooms. Added GetRoomSummaries request/response messages and related handler. Added create table statement for room data Load chat room data from persistent storage Support room creation and persistence Minor tweaks to room address handling Added GetRoom request/response messages and handler Added EnterRoom request/response and handler Build the application configuration from command line, config file or both. Command line settings take precidence over those in the config file. Adds dependency on boost::program_options Use trusty Reset state when servers reconnect Added logger support via easyloggingpp, a header-only logger. Updated places that were using cout for logging to use the logger. Moved all external code to an "externals" directory. Renamed SendMessage to prevent pita clashes when windows headers get included. Create verbose logs with unique filenames on each run. Moved the logger_config option to a commandline only option Added LOGOUTAVATAR request/response messages and handler Added SETAVATARATTRIBUTES request/response messages and handler Added stub classes for persistent message handling Added GETPERSISTENTHEADERS request message and handler stub Add a table for persistent message storage Add handler for GetPersistentHeaders Add messages and handlers for sending/getting/updating persistent messages Fix isset check for avatar Adding initial Contact management Added support for friend/ignore list management Add a response callback message to notify recipients of mail they have a new message Remove the ContactService, manage friends/ignore list within the related avatar Send FRIENDLOGIN update messages Removed contact.hpp header, fixed cyclic dependency with ChatAvatar Send updates on avatar logout Only send non-deleted message headers. Send update messages to the appropriately connected server. fix compile issue in currently unused template Added instant message support Testing travis-ci with clang once more as the llvm apt repo is now back online Uncommented clang-3.7 package Adding libc++ and libc++abi packages Disabling clang building for now, will need to devise a solution for building the boost dependency with clang as well before enabling again Added implementations for a number of room related messages. Handle add/remove banned - will add persistence for the banned/admin/moderator lists shortly Handle room chat. Initial work on room moderation/attribute management Added support for destroying rooms Message sending tweaks Prevent sending redundant messages to a game server that has already received the update. Implement the leave room handler Added add/remove moderator handlers Added descriptive comment for this member func Specified unique columns and foreign keys Handle storing moderator/banned lists Cleanup of the EnterRoom handler Avatar that creates a room is also a moderator Restructure projects for testing Moved all code not relating to the app lifetime to a library so it can be easily linked to for testing In addition, the initial setup for tests using the Catch library was created Add a general handler to orchestrate the request/response process. This pulls all the duplicate code for setup/teardown/message handling leaving the message handlers to be simpler and easier to take in. Moving each request/response/handler set to its own compilation unit to make it easier to find and read them. Moved LogoutAvatar to its own compilation unit Moved CreateRoom to its own compilation unit Moved DestroyRoom to its own compilation unit Moved SendInstantMessage to own compilation unit Also added a basic info log for each incoming request received. Moved SendRoomMessage to its own compilation unit Moved AddFriend handling to its own compilation unit Moved RemoveFriend handling to its own compilation unit Moved FriendStatus handling to its own compilation unit Moved AddIgnore handling to its own compilation unit Moved RemoveIgnore to its own compilation unit Moved EnterRoom handling to its own compilation unit Moved LeaveRoom handling to its own compilation unit Move AddModerator to its own compilation unit Moved RemoveModerator to its own compilation unit Moved add/remove banned handlers to own compilation unit Move Add/Remove invite handlers to own compilation unit Move GetRoom handler to own compilation unit Moved GetRoomSummaries handler to own compilation unit Moved persistent message handlers to own compilation unit Moved IgnoreStatus to own compilation unit Move SetApiVersion handler to own compilation unit Moved GetAnyAvatar and SetAvatarAttributes handlers to own compilation units Moving remaining messages to own compilation units Moved request/response enums to the ChatEnum header Fix typename issue Fixed source grouping helper Load up a galaxies rooms when system user logs in Use stringstreams vs static array As more rooms and more players are added, the buffer holding the serialized data needs to be able to expand accordingly, this fix addresses that throw appropriate exceptions from the message service ChatAvatar tracks rooms they are in now LogoutAvatar now removes avatar from all rooms they are joined to currently. Add appropriate checks for managing the room String version of error codes are now logged instead of just integer codes Implement kick avatar Fixes potential crash when the vector of rooms is resized (could invalidate pointers into the container) fix for persistent message oob storage Support for destroying avatars Fixed unsigned/signed mismatch Support failoverreloginavatar Replace wstring usage (which has a base type of wchar_t that is OS specific) with u16string which has a base type of uchar16_t that is guaranteed to be 16bit, exactly the size needed by the SOE protocol. Fix issue with streaming u16string types Remove udplibrary source from codebase Ignore the udplibrary dir if it exists
This commit is contained in:
@@ -0,0 +1 @@
|
||||
externals/udplibrary
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
sudo: required
|
||||
dist: trusty
|
||||
language: cpp
|
||||
compiler:
|
||||
- gcc
|
||||
script:
|
||||
- mkdir build
|
||||
- cd build
|
||||
- cmake .. && make
|
||||
|
||||
notifications:
|
||||
email:
|
||||
recipients: [email protected]
|
||||
on_success: change
|
||||
on_failure: always
|
||||
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
packages:
|
||||
- g++-5
|
||||
- gcc-5
|
||||
- libboost-dev
|
||||
- libboost-program-options-dev
|
||||
- libsqlite3-dev
|
||||
|
||||
install:
|
||||
- if [ "$CXX" = "g++" ]; then export CXX="g++-5" CC="gcc-5"; fi
|
||||
@@ -0,0 +1,40 @@
|
||||
# don't allow in-source project generation
|
||||
if (${CMAKE_SOURCE_DIR} STREQUAL ${CMAKE_BINARY_DIR})
|
||||
message(WARNING "\n\nCMake generation is not allowed within the source directory!\n")
|
||||
message(STATUS "Cancelling CMake and cleaning up source tree...")
|
||||
execute_process(COMMAND ${CMAKE_COMMAND} -E remove_directory "${CMAKE_BINARY_DIR}/CMakeFiles")
|
||||
math(EXPR Crash 0/0)
|
||||
message(FATAL_ERROR "CMake should have crashed - this is a failsafe in case the call used to trigger the crash gets fixed.")
|
||||
endif()
|
||||
|
||||
cmake_minimum_required(VERSION 2.8)
|
||||
|
||||
project(stationapi CXX)
|
||||
|
||||
set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
|
||||
|
||||
include(GroupSourceByFilesystem)
|
||||
include(ModernCpp)
|
||||
set_property(GLOBAL PROPERTY USE_FOLDERS ON)
|
||||
|
||||
if (EXISTS "externals/udplibrary/CMakeLists.txt")
|
||||
set(HAVE_UDPLIBRARY 1)
|
||||
endif()
|
||||
|
||||
add_definitions(-DBOOST_ALL_NO_LIB)
|
||||
set(Boost_USE_STATIC_LIBS ON)
|
||||
set(Boost_USE_MULTITHREADED ON)
|
||||
|
||||
find_package(Boost COMPONENTS program_options REQUIRED)
|
||||
find_package(SQLite3 REQUIRED)
|
||||
|
||||
if (${CMAKE_CXX_COMPILER_ID} STREQUAL "GNU")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-write-strings")
|
||||
endif ()
|
||||
|
||||
add_subdirectory(externals)
|
||||
add_subdirectory(src)
|
||||
add_subdirectory(tests)
|
||||
|
||||
configure_file(extras/logger.cfg.dist src/logger.cfg COPYONLY)
|
||||
configure_file(extras/swgchat.cfg.dist src/swgchat.cfg COPYONLY)
|
||||
@@ -0,0 +1,37 @@
|
||||
# swgchat [](https://travis-ci.com/apathyboy/swgchat) #
|
||||
|
||||
An open implementation of the chat gateway that SOE based games used to provide various social communication features such as mail, custom chat rooms, friend management, etc.
|
||||
|
||||
Like my work and want to support my free and open-source contributions?
|
||||
|
||||
[](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=8KCAU8HB9J7YU)
|
||||
|
||||
## Implementation ##
|
||||
|
||||
Uses the SOE libraries to implement chat features in a standalone utility. Ideally, the completed implementation would allow for multiple galaxies to connect and allow players to communicate across them.
|
||||
|
||||
## External Dependencies ##
|
||||
|
||||
c++14 compatible compiler
|
||||
boost::iostreams (header only)
|
||||
boost::optional (header only)
|
||||
boost::program_options
|
||||
sqlite3
|
||||
udplibrary - bundled in the Star Wars Galaxies official source
|
||||
|
||||
## Building ##
|
||||
|
||||
Copy the udplibrary directory from the Star Wars Galaxies offical source to the top level swgchat directory, then run the following:
|
||||
|
||||
mkdir build; cd build
|
||||
cmake ..
|
||||
cmake --build .
|
||||
|
||||
## Database Initialization ##
|
||||
|
||||
Create the database with the following commands:
|
||||
|
||||
sqlite3 chat.db
|
||||
sqlite> .read /path/to/init_database.sql
|
||||
|
||||
Then update the **database_path** config option with the full path to the database.
|
||||
@@ -0,0 +1,25 @@
|
||||
|
||||
find_path(SQLite3_INCLUDE_DIR sqlite3.h
|
||||
HINTS
|
||||
$ENV{SQLite3_ROOT}
|
||||
PATH_SUFFIXES include
|
||||
PATHS
|
||||
${SQLite3_ROOT}
|
||||
${SQLite3_INCLUDEDIR}
|
||||
)
|
||||
|
||||
find_library(SQLite3_LIBRARY
|
||||
NAMES sqlite3
|
||||
PATH_SUFFIXES lib
|
||||
HINTS
|
||||
$ENV{SQLite3_ROOT}
|
||||
${SQLite3_ROOT}
|
||||
${SQLite3_LIBRARYDIR}
|
||||
)
|
||||
|
||||
# handle the QUIETLY and REQUIRED arguments and set OPENAL_FOUND to TRUE if
|
||||
# all listed variables are TRUE
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(SQLite3 DEFAULT_MSG SQLite3_LIBRARY SQLite3_INCLUDE_DIR)
|
||||
|
||||
mark_as_advanced(SQLite3_ROOT SQLite3_INCLUDE_DIR SQLite3_LIBRARY)
|
||||
@@ -0,0 +1,16 @@
|
||||
function(GroupSourceByFilesystem SOURCES)
|
||||
foreach(FILE ${SOURCES})
|
||||
get_filename_component(PARENT_DIR "${FILE}" DIRECTORY)
|
||||
string(REPLACE "${CMAKE_CURRENT_SOURCE_DIR}" "" GROUP "${PARENT_DIR}")
|
||||
string(REPLACE "/" "\\" GROUP "${GROUP}")
|
||||
|
||||
# Group into "Source Files" and "Header Files"
|
||||
if ("${FILE}" MATCHES ".*\\.cpp")
|
||||
set(GROUP "Source Files\\${GROUP}")
|
||||
elseif("${FILE}" MATCHES ".*\\.h")
|
||||
set(GROUP "Header Files\\${GROUP}")
|
||||
endif()
|
||||
|
||||
source_group("${GROUP}" FILES "${FILE}")
|
||||
endforeach()
|
||||
endfunction(GroupSourceByFilesystem)
|
||||
@@ -0,0 +1,9 @@
|
||||
|
||||
if (${CMAKE_CXX_COMPILER_ID} MATCHES "Clang")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++14 -stdlib=libc++")
|
||||
if (NOT APPLE)
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -lc++abi")
|
||||
endif ()
|
||||
elseif (${CMAKE_CXX_COMPILER_ID} STREQUAL "GNU")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++14")
|
||||
endif ()
|
||||
Vendored
+4
@@ -0,0 +1,4 @@
|
||||
|
||||
if (HAVE_UDPLIBRARY)
|
||||
add_subdirectory(udplibrary)
|
||||
endif()
|
||||
Vendored
+10593
File diff suppressed because it is too large
Load Diff
Vendored
+24
@@ -0,0 +1,24 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2015 muflihun.com
|
||||
|
||||
http://github.com/easylogging/
|
||||
http://easylogging.muflihun.com
|
||||
http://muflihun.com
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
+6663
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,73 @@
|
||||
CREATE TABLE avatar (id INTEGER PRIMARY KEY,
|
||||
user_id INTEGER,
|
||||
name TEXT,
|
||||
address TEXT,
|
||||
attributes INTEGER,
|
||||
UNIQUE(name, address));
|
||||
|
||||
CREATE TABLE room (id INTEGER PRIMARY KEY,
|
||||
creator_id INTEGER,
|
||||
creator_name TEXT,
|
||||
creator_address TEXT,
|
||||
room_name TEXT,
|
||||
room_topic TEXT,
|
||||
room_password TEXT,
|
||||
room_prefix TEXT,
|
||||
room_address TEXT,
|
||||
room_attributes INTEGER,
|
||||
room_max_size INTEGER,
|
||||
room_message_id INTEGER,
|
||||
created_at INTEGER,
|
||||
node_level INTEGER,
|
||||
UNIQUE(room_name, room_address),
|
||||
FOREIGN KEY(creator_id) REFERENCES avatar(id));
|
||||
|
||||
CREATE TABLE room_administrator (admin_avatar_id INTEGER,
|
||||
room_id INTEGER,
|
||||
PRIMARY KEY(admin_avatar_id, room_id),
|
||||
FOREIGN KEY(admin_avatar_id) REFERENCES avatar(id) ON DELETE CASCADE,
|
||||
FOREIGN KEY(room_id) REFERENCES room(id) ON DELETE CASCADE);
|
||||
|
||||
CREATE TABLE room_moderator (moderator_avatar_id INTEGER,
|
||||
room_id INTEGER,
|
||||
PRIMARY KEY(moderator_avatar_id, room_id),
|
||||
FOREIGN KEY(moderator_avatar_id) REFERENCES avatar(id) ON DELETE CASCADE,
|
||||
FOREIGN KEY(room_id) REFERENCES room(id) ON DELETE CASCADE);
|
||||
|
||||
CREATE TABLE room_ban (banned_avatar_id INTEGER,
|
||||
room_id INTEGER,
|
||||
PRIMARY KEY(banned_avatar_id, room_id),
|
||||
FOREIGN KEY(banned_avatar_id) REFERENCES avatar(id) ON DELETE CASCADE,
|
||||
FOREIGN KEY(room_id) REFERENCES room(id) ON DELETE CASCADE);
|
||||
|
||||
CREATE TABLE room_invite (invited_avatar_id INTEGER,
|
||||
room_id INTEGER,
|
||||
PRIMARY KEY(invited_avatar_id, room_id),
|
||||
FOREIGN KEY(invited_avatar_id) REFERENCES avatar(id) ON DELETE CASCADE,
|
||||
FOREIGN KEY(room_id) REFERENCES room(id) ON DELETE CASCADE);
|
||||
|
||||
CREATE TABLE persistent_message (id INTEGER PRIMARY KEY,
|
||||
avatar_id INTEGER,
|
||||
from_name TEXT,
|
||||
from_address TEXT,
|
||||
subject TEXT,
|
||||
sent_time INTEGER,
|
||||
status INTEGER,
|
||||
folder TEXT,
|
||||
category TEXT,
|
||||
message TEXT,
|
||||
oob BLOB,
|
||||
FOREIGN KEY(avatar_id) REFERENCES avatar(id) ON DELETE CASCADE);
|
||||
|
||||
CREATE TABLE friend (avatar_id INTEGER,
|
||||
friend_avatar_id INTEGER,
|
||||
comment TEXT,
|
||||
PRIMARY KEY(avatar_id, friend_avatar_id),
|
||||
FOREIGN KEY(avatar_id) REFERENCES avatar(id) ON DELETE CASCADE,
|
||||
FOREIGN KEY(friend_avatar_id) REFERENCES avatar(id) ON DELETE CASCADE);
|
||||
|
||||
CREATE TABLE ignore (avatar_id INTEGER,
|
||||
ignore_avatar_id INTEGER,
|
||||
PRIMARY KEY(avatar_id, ignore_avatar_id)
|
||||
FOREIGN KEY(avatar_id) REFERENCES avatar(id) ON DELETE CASCADE,
|
||||
FOREIGN KEY(ignore_avatar_id) REFERENCES avatar(id) ON DELETE CASCADE);
|
||||
@@ -0,0 +1,18 @@
|
||||
* GLOBAL:
|
||||
FILENAME = "logs/swgchat.log"
|
||||
TO_STANDARD_OUTPUT = true
|
||||
* TRACE:
|
||||
FILENAME = "logs/swgchat.log"
|
||||
* DEBUG:
|
||||
FILENAME = "logs/swgchat.log"
|
||||
* FATAL:
|
||||
FILENAME = "logs/swgchat.log"
|
||||
* ERROR:
|
||||
FILENAME = "logs/swgchat.log"
|
||||
* WARNING:
|
||||
FILENAME = "logs/swgchat.log"
|
||||
* INFO:
|
||||
FILENAME = "logs/swgchat.log"
|
||||
* VERBOSE:
|
||||
FILENAME = "logs/verbose.%datetime{%Y%M%d_%H%m%s}.log"
|
||||
TO_STANDARD_OUTPUT = false
|
||||
@@ -0,0 +1,14 @@
|
||||
# Address that the gateway server will listen for connections on
|
||||
gateway_address = 127.0.0.1
|
||||
|
||||
# Port the gateway server will listen for connections on
|
||||
gateway_port = 5001
|
||||
|
||||
# Address that the registrar server will listen for connections on
|
||||
registrar_address = 127.0.0.1
|
||||
|
||||
# Port the registrar server will listen for connections on
|
||||
registrar_port = 5000
|
||||
|
||||
# Path to the application database
|
||||
database_path = chat.db
|
||||
@@ -0,0 +1,132 @@
|
||||
include_directories(
|
||||
${CMAKE_CURRENT_SOURCE_DIR}
|
||||
${PROJECT_SOURCE_DIR}/externals/easyloggingpp
|
||||
${Boost_INCLUDE_DIRS}
|
||||
${SQLite3_INCLUDE_DIR})
|
||||
|
||||
if(HAVE_UDPLIBRARY)
|
||||
include_directories(${PROJECT_SOURCE_DIR}/externals/udplibrary)
|
||||
endif()
|
||||
|
||||
set(SOURCES
|
||||
protocol/AddBan.cpp
|
||||
protocol/AddBan.hpp
|
||||
protocol/AddFriend.cpp
|
||||
protocol/AddFriend.hpp
|
||||
protocol/AddIgnore.cpp
|
||||
protocol/AddIgnore.hpp
|
||||
protocol/AddInvite.cpp
|
||||
protocol/AddInvite.hpp
|
||||
protocol/AddModerator.cpp
|
||||
protocol/AddModerator.hpp
|
||||
protocol/CreateRoom.cpp
|
||||
protocol/CreateRoom.hpp
|
||||
protocol/DestroyAvatar.cpp
|
||||
protocol/DestroyAvatar.hpp
|
||||
protocol/DestroyRoom.cpp
|
||||
protocol/DestroyRoom.hpp
|
||||
protocol/EnterRoom.cpp
|
||||
protocol/EnterRoom.hpp
|
||||
protocol/FailoverReLoginAvatar.cpp
|
||||
protocol/FailoverReLoginAvatar.hpp
|
||||
protocol/FriendStatus.cpp
|
||||
protocol/FriendStatus.hpp
|
||||
protocol/GetAnyAvatar.cpp
|
||||
protocol/GetAnyAvatar.hpp
|
||||
protocol/GetPersistentHeaders.cpp
|
||||
protocol/GetPersistentHeaders.hpp
|
||||
protocol/GetPersistentMessage.cpp
|
||||
protocol/GetPersistentMessage.hpp
|
||||
protocol/GetRoom.cpp
|
||||
protocol/GetRoom.hpp
|
||||
protocol/GetRoomSummaries.cpp
|
||||
protocol/GetRoomSummaries.hpp
|
||||
protocol/IgnoreStatus.cpp
|
||||
protocol/IgnoreStatus.hpp
|
||||
protocol/KickAvatar.cpp
|
||||
protocol/KickAvatar.hpp
|
||||
protocol/LeaveRoom.cpp
|
||||
protocol/LeaveRoom.hpp
|
||||
protocol/LoginAvatar.cpp
|
||||
protocol/LoginAvatar.hpp
|
||||
protocol/LogoutAvatar.cpp
|
||||
protocol/LogoutAvatar.hpp
|
||||
protocol/RegistrarGetChatServer.cpp
|
||||
protocol/RegistrarGetChatServer.hpp
|
||||
protocol/RemoveBan.cpp
|
||||
protocol/RemoveBan.hpp
|
||||
protocol/RemoveFriend.cpp
|
||||
protocol/RemoveFriend.hpp
|
||||
protocol/RemoveIgnore.cpp
|
||||
protocol/RemoveIgnore.hpp
|
||||
protocol/RemoveInvite.cpp
|
||||
protocol/RemoveInvite.hpp
|
||||
protocol/RemoveModerator.cpp
|
||||
protocol/RemoveModerator.hpp
|
||||
protocol/SendInstantMessage.cpp
|
||||
protocol/SendInstantMessage.hpp
|
||||
protocol/SendPersistentMessage.cpp
|
||||
protocol/SendPersistentMessage.hpp
|
||||
protocol/SendRoomMessage.cpp
|
||||
protocol/SendRoomMessage.hpp
|
||||
protocol/SetApiVersion.cpp
|
||||
protocol/SetApiVersion.hpp
|
||||
protocol/SetAvatarAttributes.cpp
|
||||
protocol/SetAvatarAttributes.hpp
|
||||
protocol/UpdatePersistentMessage.cpp
|
||||
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
|
||||
Message.hpp
|
||||
Node.hpp
|
||||
NodeClient.cpp
|
||||
NodeClient.hpp
|
||||
PersistentMessage.hpp
|
||||
PersistentMessageService.cpp
|
||||
PersistentMessageService.hpp
|
||||
RegistrarClient.cpp
|
||||
RegistrarClient.hpp
|
||||
RegistrarNode.cpp
|
||||
RegistrarNode.hpp
|
||||
Serialization.hpp
|
||||
SQLite3.hpp
|
||||
StreamUtils.cpp
|
||||
StreamUtils.hpp
|
||||
StringUtils.cpp
|
||||
StringUtils.hpp)
|
||||
|
||||
add_library(stationapi ${SOURCES})
|
||||
|
||||
GroupSourceByFilesystem("${SOURCES}")
|
||||
|
||||
add_executable(stationchat
|
||||
main.cpp
|
||||
StationChatApp.cpp
|
||||
StationChatApp.hpp
|
||||
StationChatConfig.hpp)
|
||||
|
||||
target_link_libraries(stationchat
|
||||
stationapi
|
||||
${Boost_LIBRARIES}
|
||||
${SQLite3_LIBRARY})
|
||||
|
||||
if (HAVE_UDPLIBRARY)
|
||||
target_link_libraries(stationchat udplibrary)
|
||||
endif()
|
||||
|
||||
if(WIN32)
|
||||
target_link_libraries(stationchat ws2_32)
|
||||
endif()
|
||||
@@ -0,0 +1,107 @@
|
||||
#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;
|
||||
}
|
||||
|
||||
std::vector<ChatRoom*> ChatAvatar::GetJoinedRooms() {
|
||||
return rooms_;
|
||||
}
|
||||
|
||||
void ChatAvatar::JoinRoom(ChatRoom * room) {
|
||||
rooms_.push_back(room);
|
||||
}
|
||||
|
||||
void ChatAvatar::UnjoinRoom(ChatRoom * room) {
|
||||
if (rooms_.empty()) return;
|
||||
|
||||
rooms_.erase(std::remove_if(std::begin(rooms_), std::end(rooms_), [room](const auto joinedRoom) {
|
||||
return room->GetRoomId() == joinedRoom->GetRoomId();
|
||||
}));
|
||||
}
|
||||
@@ -0,0 +1,135 @@
|
||||
|
||||
#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_; }
|
||||
|
||||
std::vector<ChatRoom*> GetJoinedRooms();
|
||||
void JoinRoom(ChatRoom* room);
|
||||
void UnjoinRoom(ChatRoom* room);
|
||||
|
||||
private:
|
||||
friend class ChatAvatarService;
|
||||
|
||||
ChatAvatarService* avatarService_;
|
||||
|
||||
uint32_t avatarId_ = 0;
|
||||
uint32_t userId_ = 0;
|
||||
std::u16string name_ = u"";
|
||||
std::u16string address_ = u"";
|
||||
uint32_t attributes_ = 0;
|
||||
std::u16string loginLocation_ = u"";
|
||||
std::u16string server_ = u"";
|
||||
std::u16string gateway_ = u"";
|
||||
uint32_t serverId_ = 0;
|
||||
uint32_t gatewayId_ = 0;
|
||||
std::u16string email_ = u"";
|
||||
uint32_t inboxLimit_ = 0;
|
||||
std::u16string statusMessage_ = u"";
|
||||
bool isOnline_ = false;
|
||||
|
||||
std::vector<FriendContact> friendList_;
|
||||
std::vector<IgnoreContact> ignoreList_;
|
||||
|
||||
std::vector<ChatRoom*> rooms_;
|
||||
};
|
||||
|
||||
template <typename StreamT>
|
||||
void write(StreamT& ar, const ChatAvatar* data) {
|
||||
write(ar, data->GetAvatarId());
|
||||
write(ar, data->GetUserId());
|
||||
write(ar, data->GetName());
|
||||
write(ar, data->GetAddress());
|
||||
write(ar, data->GetAttributes());
|
||||
write(ar, data->GetLoginLocation());
|
||||
write(ar, data->GetServer());
|
||||
write(ar, data->GetGateway());
|
||||
write(ar, data->GetServerId());
|
||||
write(ar, data->GetGatewayId());
|
||||
}
|
||||
|
||||
|
||||
template <typename StreamT>
|
||||
void write(StreamT& ar, const FriendContact& data) {
|
||||
write(ar, data.frnd->GetName());
|
||||
write(ar, data.frnd->GetAddress());
|
||||
write(ar, data.comment);
|
||||
write(ar, static_cast<short>(data.frnd->IsOnline() ? 1 : 0));
|
||||
}
|
||||
|
||||
template <typename StreamT>
|
||||
void write(StreamT& ar, const IgnoreContact& data) {
|
||||
write(ar, data.ignored->GetName());
|
||||
write(ar, data.ignored->GetAddress());
|
||||
}
|
||||
@@ -0,0 +1,488 @@
|
||||
#include "ChatAvatarService.hpp"
|
||||
#include "ChatAvatar.hpp"
|
||||
#include "SQLite3.hpp"
|
||||
#include "StringUtils.hpp"
|
||||
|
||||
#include <easylogging++.h>
|
||||
|
||||
ChatAvatarService::ChatAvatarService(sqlite3* db)
|
||||
: db_{db} {}
|
||||
|
||||
ChatAvatarService::~ChatAvatarService() {}
|
||||
|
||||
ChatAvatar* ChatAvatarService::GetAvatar(const std::u16string& name, const std::u16string& address) {
|
||||
ChatAvatar* avatar = GetCachedAvatar(name, address);
|
||||
|
||||
if (!avatar) {
|
||||
auto loadedAvatar = LoadStoredAvatar(name, address);
|
||||
if (loadedAvatar != nullptr) {
|
||||
avatar = loadedAvatar.get();
|
||||
avatarCache_.emplace_back(std::move(loadedAvatar));
|
||||
|
||||
LoadFriendList(avatar);
|
||||
LoadIgnoreList(avatar);
|
||||
}
|
||||
}
|
||||
|
||||
return avatar;
|
||||
}
|
||||
|
||||
ChatAvatar* ChatAvatarService::GetAvatar(uint32_t avatarId) {
|
||||
ChatAvatar* avatar = GetCachedAvatar(avatarId);
|
||||
|
||||
if (!avatar) {
|
||||
auto loadedAvatar = LoadStoredAvatar(avatarId);
|
||||
if (loadedAvatar != nullptr) {
|
||||
avatar = loadedAvatar.get();
|
||||
avatarCache_.emplace_back(std::move(loadedAvatar));
|
||||
|
||||
LoadFriendList(avatar);
|
||||
LoadIgnoreList(avatar);
|
||||
}
|
||||
}
|
||||
|
||||
return avatar;
|
||||
}
|
||||
|
||||
ChatAvatar* ChatAvatarService::CreateAvatar(const std::u16string& name, const std::u16string& address,
|
||||
uint32_t userId, uint32_t loginAttributes, const std::u16string& loginLocation) {
|
||||
auto tmp
|
||||
= std::make_unique<ChatAvatar>(this, name, address, userId, loginAttributes, loginLocation);
|
||||
auto avatar = tmp.get();
|
||||
|
||||
InsertAvatar(avatar);
|
||||
|
||||
avatarCache_.emplace_back(std::move(tmp));
|
||||
|
||||
return avatar;
|
||||
}
|
||||
|
||||
void ChatAvatarService::DestroyAvatar(ChatAvatar* avatar) {
|
||||
DeleteAvatar(avatar);
|
||||
LogoutAvatar(avatar);
|
||||
RemoveCachedAvatar(avatar->GetAvatarId());
|
||||
}
|
||||
|
||||
void ChatAvatarService::LoginAvatar(ChatAvatar* avatar) {
|
||||
avatar->isOnline_ = true;
|
||||
|
||||
if (!IsOnline(avatar)) {
|
||||
onlineAvatars_.push_back(avatar);
|
||||
}
|
||||
}
|
||||
|
||||
void ChatAvatarService::LogoutAvatar(ChatAvatar* avatar) {
|
||||
avatar->isOnline_ = false;
|
||||
|
||||
onlineAvatars_.erase(std::remove_if(
|
||||
std::begin(onlineAvatars_), std::end(onlineAvatars_), [avatar](auto onlineAvatar) {
|
||||
return onlineAvatar->GetAvatarId() == avatar->GetAvatarId();
|
||||
}));
|
||||
}
|
||||
|
||||
void ChatAvatarService::PersistAvatar(const ChatAvatar* avatar) { UpdateAvatar(avatar); }
|
||||
|
||||
void ChatAvatarService::PersistFriend(
|
||||
uint32_t srcAvatarId, uint32_t destAvatarId, const std::u16string& comment) {
|
||||
sqlite3_stmt* stmt;
|
||||
char sql[] = "INSERT INTO friend (avatar_id, friend_avatar_id, comment) VALUES (@avatar_id, "
|
||||
"@friend_avatar_id, @comment)";
|
||||
|
||||
auto result = sqlite3_prepare_v2(db_, sql, -1, &stmt, 0);
|
||||
if (result != SQLITE_OK) {
|
||||
throw SQLite3Exception{result, sqlite3_errmsg(db_)};
|
||||
}
|
||||
|
||||
int avatarIdIdx = sqlite3_bind_parameter_index(stmt, "@avatar_id");
|
||||
int friendAvatarIdIdx = sqlite3_bind_parameter_index(stmt, "@friend_avatar_id");
|
||||
int commentIdx = sqlite3_bind_parameter_index(stmt, "@comment");
|
||||
|
||||
std::string commentStr = FromWideString(comment);
|
||||
|
||||
sqlite3_bind_int(stmt, avatarIdIdx, srcAvatarId);
|
||||
sqlite3_bind_int(stmt, friendAvatarIdIdx, destAvatarId);
|
||||
sqlite3_bind_text(stmt, commentIdx, commentStr.c_str(), -1, 0);
|
||||
|
||||
result = sqlite3_step(stmt);
|
||||
if (result != SQLITE_DONE) {
|
||||
throw SQLite3Exception{result, sqlite3_errmsg(db_)};
|
||||
}
|
||||
}
|
||||
|
||||
void ChatAvatarService::PersistIgnore(uint32_t srcAvatarId, uint32_t destAvatarId) {
|
||||
sqlite3_stmt* stmt;
|
||||
char sql[] = "INSERT INTO ignore (avatar_id, ignore_avatar_id, comment) VALUES (@avatar_id, "
|
||||
"@ignore_avatar_id)";
|
||||
|
||||
auto result = sqlite3_prepare_v2(db_, sql, -1, &stmt, 0);
|
||||
if (result != SQLITE_OK) {
|
||||
throw SQLite3Exception{result, sqlite3_errmsg(db_)};
|
||||
}
|
||||
|
||||
int avatarIdIdx = sqlite3_bind_parameter_index(stmt, "@avatar_id");
|
||||
int ignoreAvatarIdIdx = sqlite3_bind_parameter_index(stmt, "@ignore_avatar_id");
|
||||
|
||||
sqlite3_bind_int(stmt, avatarIdIdx, srcAvatarId);
|
||||
sqlite3_bind_int(stmt, ignoreAvatarIdIdx, destAvatarId);
|
||||
|
||||
result = sqlite3_step(stmt);
|
||||
if (result != SQLITE_DONE) {
|
||||
throw SQLite3Exception{result, sqlite3_errmsg(db_)};
|
||||
}
|
||||
}
|
||||
|
||||
void ChatAvatarService::RemoveFriend(uint32_t srcAvatarId, uint32_t destAvatarId) {
|
||||
sqlite3_stmt* stmt;
|
||||
|
||||
char sql[] = "DELETE FROM friend WHERE avatar_id = @avatar_id AND friend_avatar_id = "
|
||||
"@friend_avatar_id";
|
||||
|
||||
auto result = sqlite3_prepare_v2(db_, sql, -1, &stmt, 0);
|
||||
if (result != SQLITE_OK) {
|
||||
throw SQLite3Exception{result, sqlite3_errmsg(db_)};
|
||||
}
|
||||
|
||||
int avatarIdIdx = sqlite3_bind_parameter_index(stmt, "@avatar_id");
|
||||
int friendAvatarIdIdx = sqlite3_bind_parameter_index(stmt, "@friend_avatar_id");
|
||||
|
||||
sqlite3_bind_int(stmt, avatarIdIdx, srcAvatarId);
|
||||
sqlite3_bind_int(stmt, friendAvatarIdIdx, destAvatarId);
|
||||
|
||||
result = sqlite3_step(stmt);
|
||||
if (result != SQLITE_DONE) {
|
||||
throw SQLite3Exception{result, sqlite3_errmsg(db_)};
|
||||
}
|
||||
}
|
||||
|
||||
void ChatAvatarService::RemoveIgnore(uint32_t srcAvatarId, uint32_t destAvatarId) {
|
||||
sqlite3_stmt* stmt;
|
||||
|
||||
char sql[] = "DELETE FROM ignore WHERE avatar_id = @avatar_id AND ignore_avatar_id = "
|
||||
"@ignore_avatar_id";
|
||||
|
||||
auto result = sqlite3_prepare_v2(db_, sql, -1, &stmt, 0);
|
||||
if (result != SQLITE_OK) {
|
||||
throw SQLite3Exception{result, sqlite3_errmsg(db_)};
|
||||
}
|
||||
|
||||
int avatarIdIdx = sqlite3_bind_parameter_index(stmt, "@avatar_id");
|
||||
int ignoreAvatarIdIdx = sqlite3_bind_parameter_index(stmt, "@ignore_avatar_id");
|
||||
|
||||
sqlite3_bind_int(stmt, avatarIdIdx, srcAvatarId);
|
||||
sqlite3_bind_int(stmt, ignoreAvatarIdIdx, destAvatarId);
|
||||
|
||||
result = sqlite3_step(stmt);
|
||||
if (result != SQLITE_DONE) {
|
||||
throw SQLite3Exception{result, sqlite3_errmsg(db_)};
|
||||
}
|
||||
}
|
||||
|
||||
void ChatAvatarService::UpdateFriendComment(
|
||||
uint32_t srcAvatarId, uint32_t destAvatarId, const std::u16string& comment) {
|
||||
sqlite3_stmt* stmt;
|
||||
char sql[] = "UDPATE friend SET comment = @comment WHERE avatar_id = @avatar_id AND "
|
||||
"friend_avatar_id = @friend_avatar_id";
|
||||
|
||||
auto result = sqlite3_prepare_v2(db_, sql, -1, &stmt, 0);
|
||||
if (result != SQLITE_OK) {
|
||||
throw SQLite3Exception{result, sqlite3_errmsg(db_)};
|
||||
}
|
||||
|
||||
int commentIdx = sqlite3_bind_parameter_index(stmt, "@comment");
|
||||
int avatarIdIdx = sqlite3_bind_parameter_index(stmt, "@avatar_id");
|
||||
int friendAvatarIdIdx = sqlite3_bind_parameter_index(stmt, "@friend_avatar_id");
|
||||
|
||||
std::string commentStr = FromWideString(comment);
|
||||
|
||||
sqlite3_bind_text(stmt, commentIdx, commentStr.c_str(), -1, 0);
|
||||
sqlite3_bind_int(stmt, avatarIdIdx, srcAvatarId);
|
||||
sqlite3_bind_int(stmt, friendAvatarIdIdx, destAvatarId);
|
||||
|
||||
result = sqlite3_step(stmt);
|
||||
if (result != SQLITE_DONE) {
|
||||
throw SQLite3Exception{result, sqlite3_errmsg(db_)};
|
||||
}
|
||||
}
|
||||
|
||||
ChatAvatar* ChatAvatarService::GetCachedAvatar(
|
||||
const std::u16string& name, const std::u16string& address) {
|
||||
ChatAvatar* avatar = nullptr;
|
||||
|
||||
// First look for the avatar in the cache
|
||||
auto find_iter = std::find_if(
|
||||
std::begin(avatarCache_), std::end(avatarCache_), [name, address](const auto& avatar) {
|
||||
return avatar->name_.compare(name) == 0 && avatar->address_.compare(address) == 0;
|
||||
});
|
||||
|
||||
if (find_iter != std::end(avatarCache_)) {
|
||||
avatar = find_iter->get();
|
||||
}
|
||||
|
||||
return avatar;
|
||||
}
|
||||
|
||||
ChatAvatar* ChatAvatarService::GetCachedAvatar(uint32_t avatarId) {
|
||||
ChatAvatar* avatar = nullptr;
|
||||
|
||||
// First look for the avatar in the cache
|
||||
auto find_iter = std::find_if(std::begin(avatarCache_), std::end(avatarCache_),
|
||||
[avatarId](const auto& avatar) { return avatar->avatarId_ == avatarId; });
|
||||
|
||||
if (find_iter != std::end(avatarCache_)) {
|
||||
avatar = find_iter->get();
|
||||
}
|
||||
|
||||
return avatar;
|
||||
}
|
||||
|
||||
void ChatAvatarService::RemoveCachedAvatar(uint32_t avatarId) {
|
||||
auto remove_iter = std::remove_if(std::begin(avatarCache_), std::end(avatarCache_),
|
||||
[avatarId](const auto& avatar) { return avatar->avatarId_ == avatarId; });
|
||||
|
||||
if (remove_iter != std::end(avatarCache_)) {
|
||||
avatarCache_.erase(remove_iter);
|
||||
}
|
||||
}
|
||||
|
||||
void ChatAvatarService::RemoveAsFriendOrIgnoreFromAll(const ChatAvatar* avatar) {
|
||||
for (auto& cachedAvatar : avatarCache_) {
|
||||
if (cachedAvatar->IsFriend(avatar)) {
|
||||
cachedAvatar->RemoveFriend(avatar);
|
||||
}
|
||||
|
||||
if (cachedAvatar->IsIgnored(avatar)) {
|
||||
cachedAvatar->RemoveIgnore(avatar);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::unique_ptr<ChatAvatar> ChatAvatarService::LoadStoredAvatar(
|
||||
const std::u16string& name, const std::u16string& address) {
|
||||
std::unique_ptr<ChatAvatar> avatar{nullptr};
|
||||
|
||||
sqlite3_stmt* stmt;
|
||||
|
||||
char sql[] = "SELECT id, user_id, name, address, attributes FROM avatar WHERE name = @name AND "
|
||||
"address = @address";
|
||||
|
||||
auto result = sqlite3_prepare_v2(db_, sql, -1, &stmt, 0);
|
||||
if (result != SQLITE_OK) {
|
||||
throw SQLite3Exception{result, sqlite3_errmsg(db_)};
|
||||
}
|
||||
|
||||
std::string nameStr = FromWideString(name);
|
||||
std::string addressStr = FromWideString(address);
|
||||
|
||||
int nameIdx = sqlite3_bind_parameter_index(stmt, "@name");
|
||||
int addressIdx = sqlite3_bind_parameter_index(stmt, "@address");
|
||||
|
||||
sqlite3_bind_text(stmt, nameIdx, nameStr.c_str(), -1, 0);
|
||||
sqlite3_bind_text(stmt, addressIdx, addressStr.c_str(), -1, 0);
|
||||
|
||||
if (sqlite3_step(stmt) == SQLITE_ROW) {
|
||||
avatar = std::make_unique<ChatAvatar>(this);
|
||||
avatar->avatarId_ = sqlite3_column_int(stmt, 0);
|
||||
avatar->userId_ = sqlite3_column_int(stmt, 1);
|
||||
|
||||
auto tmp = std::string(reinterpret_cast<const char*>(sqlite3_column_text(stmt, 2)));
|
||||
avatar->name_ = std::u16string{std::begin(tmp), std::end(tmp)};
|
||||
|
||||
tmp = std::string(reinterpret_cast<const char*>(sqlite3_column_text(stmt, 3)));
|
||||
avatar->address_ = std::u16string(std::begin(tmp), std::end(tmp));
|
||||
|
||||
avatar->attributes_ = sqlite3_column_int(stmt, 4);
|
||||
}
|
||||
|
||||
sqlite3_finalize(stmt);
|
||||
|
||||
return avatar;
|
||||
}
|
||||
|
||||
std::unique_ptr<ChatAvatar> ChatAvatarService::LoadStoredAvatar(uint32_t avatarId) {
|
||||
std::unique_ptr<ChatAvatar> avatar{nullptr};
|
||||
|
||||
sqlite3_stmt* stmt;
|
||||
|
||||
char sql[] = "SELECT id, user_id, name, address, attributes FROM avatar WHERE id = @avatar_id";
|
||||
|
||||
auto result = sqlite3_prepare_v2(db_, sql, -1, &stmt, 0);
|
||||
if (result != SQLITE_OK) {
|
||||
throw SQLite3Exception{result, sqlite3_errmsg(db_)};
|
||||
}
|
||||
|
||||
int avatarIdIdx = sqlite3_bind_parameter_index(stmt, "@avatar_id");
|
||||
|
||||
sqlite3_bind_int(stmt, avatarIdIdx, avatarId);
|
||||
|
||||
if (sqlite3_step(stmt) == SQLITE_ROW) {
|
||||
avatar = std::make_unique<ChatAvatar>(this);
|
||||
avatar->avatarId_ = sqlite3_column_int(stmt, 0);
|
||||
avatar->userId_ = sqlite3_column_int(stmt, 1);
|
||||
|
||||
auto tmp = std::string(reinterpret_cast<const char*>(sqlite3_column_text(stmt, 2)));
|
||||
avatar->name_ = std::u16string{std::begin(tmp), std::end(tmp)};
|
||||
|
||||
tmp = std::string(reinterpret_cast<const char*>(sqlite3_column_text(stmt, 3)));
|
||||
avatar->address_ = std::u16string(std::begin(tmp), std::end(tmp));
|
||||
|
||||
avatar->attributes_ = sqlite3_column_int(stmt, 4);
|
||||
}
|
||||
|
||||
sqlite3_finalize(stmt);
|
||||
|
||||
return avatar;
|
||||
}
|
||||
|
||||
void ChatAvatarService::InsertAvatar(ChatAvatar* avatar) {
|
||||
CHECK_NOTNULL(avatar);
|
||||
sqlite3_stmt* stmt;
|
||||
|
||||
char sql[] = "INSERT INTO avatar (user_id, name, address, attributes) VALUES (@user_id, @name, "
|
||||
"@address, @attributes)";
|
||||
|
||||
auto result = sqlite3_prepare_v2(db_, sql, -1, &stmt, 0);
|
||||
if (result != SQLITE_OK) {
|
||||
throw SQLite3Exception{result, sqlite3_errmsg(db_)};
|
||||
}
|
||||
|
||||
std::string nameStr = FromWideString(avatar->name_);
|
||||
std::string addressStr = FromWideString(avatar->address_);
|
||||
|
||||
int userIdIdx = sqlite3_bind_parameter_index(stmt, "@user_id");
|
||||
int nameIdx = sqlite3_bind_parameter_index(stmt, "@name");
|
||||
int addressIdx = sqlite3_bind_parameter_index(stmt, "@address");
|
||||
int attributesIdx = sqlite3_bind_parameter_index(stmt, "@attributes");
|
||||
|
||||
sqlite3_bind_int(stmt, userIdIdx, avatar->userId_);
|
||||
sqlite3_bind_text(stmt, nameIdx, nameStr.c_str(), -1, 0);
|
||||
sqlite3_bind_text(stmt, addressIdx, addressStr.c_str(), -1, 0);
|
||||
sqlite3_bind_int(stmt, attributesIdx, avatar->attributes_);
|
||||
|
||||
result = sqlite3_step(stmt);
|
||||
if (result != SQLITE_DONE) {
|
||||
throw SQLite3Exception{result, sqlite3_errmsg(db_)};
|
||||
}
|
||||
|
||||
avatar->avatarId_ = static_cast<uint32_t>(sqlite3_last_insert_rowid(db_));
|
||||
|
||||
sqlite3_finalize(stmt);
|
||||
}
|
||||
|
||||
void ChatAvatarService::UpdateAvatar(const ChatAvatar* avatar) {
|
||||
CHECK_NOTNULL(avatar);
|
||||
sqlite3_stmt* stmt;
|
||||
|
||||
char sql[] = "UPDATE avatar SET user_id = @user_id, name = @name, address = @address, "
|
||||
"attributes = @attributes "
|
||||
"WHERE id = @avatar_id";
|
||||
|
||||
auto result = sqlite3_prepare_v2(db_, sql, -1, &stmt, 0);
|
||||
if (result != SQLITE_OK) {
|
||||
throw SQLite3Exception{result, sqlite3_errmsg(db_)};
|
||||
}
|
||||
|
||||
std::string nameStr = FromWideString(avatar->name_);
|
||||
std::string addressStr = FromWideString(avatar->address_);
|
||||
|
||||
int userIdIdx = sqlite3_bind_parameter_index(stmt, "@user_id");
|
||||
int nameIdx = sqlite3_bind_parameter_index(stmt, "@name");
|
||||
int addressIdx = sqlite3_bind_parameter_index(stmt, "@address");
|
||||
int attributesIdx = sqlite3_bind_parameter_index(stmt, "@attributes");
|
||||
int avatarIdIdx = sqlite3_bind_parameter_index(stmt, "@avatar_id");
|
||||
|
||||
sqlite3_bind_int(stmt, userIdIdx, avatar->userId_);
|
||||
sqlite3_bind_text(stmt, nameIdx, nameStr.c_str(), -1, 0);
|
||||
sqlite3_bind_text(stmt, addressIdx, addressStr.c_str(), -1, 0);
|
||||
sqlite3_bind_int(stmt, attributesIdx, avatar->attributes_);
|
||||
sqlite3_bind_int(stmt, avatarIdIdx, avatar->avatarId_);
|
||||
|
||||
result = sqlite3_step(stmt);
|
||||
if (result != SQLITE_DONE) {
|
||||
throw SQLite3Exception{result, sqlite3_errmsg(db_)};
|
||||
}
|
||||
|
||||
sqlite3_finalize(stmt);
|
||||
}
|
||||
|
||||
void ChatAvatarService::DeleteAvatar(ChatAvatar* avatar) {
|
||||
CHECK_NOTNULL(avatar);
|
||||
sqlite3_stmt* stmt;
|
||||
|
||||
char sql[] = "DELETE FROM avatar WHERE id = @avatar_id";
|
||||
|
||||
auto result = sqlite3_prepare_v2(db_, sql, -1, &stmt, 0);
|
||||
if (result != SQLITE_OK) {
|
||||
throw SQLite3Exception{result, sqlite3_errmsg(db_)};
|
||||
}
|
||||
|
||||
int avatarIdIdx = sqlite3_bind_parameter_index(stmt, "@avatar_id");
|
||||
|
||||
sqlite3_bind_int(stmt, avatarIdIdx, avatar->avatarId_);
|
||||
|
||||
result = sqlite3_step(stmt);
|
||||
if (result != SQLITE_DONE) {
|
||||
throw SQLite3Exception{result, sqlite3_errmsg(db_)};
|
||||
}
|
||||
|
||||
sqlite3_finalize(stmt);
|
||||
}
|
||||
|
||||
void ChatAvatarService::LoadFriendList(ChatAvatar* avatar) {
|
||||
sqlite3_stmt* stmt;
|
||||
|
||||
char sql[] = "SELECT friend_avatar_id, comment FROM friend WHERE avatar_id = @avatar_id";
|
||||
|
||||
auto result = sqlite3_prepare_v2(db_, sql, -1, &stmt, 0);
|
||||
if (result != SQLITE_OK) {
|
||||
throw SQLite3Exception{result, sqlite3_errmsg(db_)};
|
||||
}
|
||||
|
||||
int avatarIdIdx = sqlite3_bind_parameter_index(stmt, "@avatar_id");
|
||||
|
||||
sqlite3_bind_int(stmt, avatarIdIdx, avatar->avatarId_);
|
||||
|
||||
uint32_t tmpFriendId;
|
||||
std::string tmpComment;
|
||||
while (sqlite3_step(stmt) == SQLITE_ROW) {
|
||||
tmpFriendId = sqlite3_column_int(stmt, 0);
|
||||
tmpComment = reinterpret_cast<const char*>(sqlite3_column_text(stmt, 1));
|
||||
|
||||
auto friendAvatar = GetAvatar(tmpFriendId);
|
||||
|
||||
avatar->friendList_.emplace_back(friendAvatar, ToWideString(tmpComment));
|
||||
}
|
||||
}
|
||||
|
||||
void ChatAvatarService::LoadIgnoreList(ChatAvatar* avatar) {
|
||||
sqlite3_stmt* stmt;
|
||||
|
||||
char sql[] = "SELECT ignore_avatar_id FROM ignore WHERE avatar_id = @avatar_id";
|
||||
|
||||
auto result = sqlite3_prepare_v2(db_, sql, -1, &stmt, 0);
|
||||
if (result != SQLITE_OK) {
|
||||
throw SQLite3Exception{result, sqlite3_errmsg(db_)};
|
||||
}
|
||||
|
||||
int avatarIdIdx = sqlite3_bind_parameter_index(stmt, "@avatar_id");
|
||||
|
||||
sqlite3_bind_int(stmt, avatarIdIdx, avatar->avatarId_);
|
||||
|
||||
uint32_t tmpIgnoreId;
|
||||
while (sqlite3_step(stmt) == SQLITE_ROW) {
|
||||
tmpIgnoreId = sqlite3_column_int(stmt, 0);
|
||||
|
||||
auto ignoreAvatar = GetAvatar(tmpIgnoreId);
|
||||
|
||||
avatar->ignoreList_.emplace_back(ignoreAvatar);
|
||||
}
|
||||
}
|
||||
|
||||
bool ChatAvatarService::IsOnline(const ChatAvatar * avatar) const {
|
||||
for (auto onlineAvatar : onlineAvatars_) {
|
||||
if (onlineAvatar->GetAvatarId() == avatar->GetAvatarId()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "ChatAvatar.hpp"
|
||||
#include "ChatEnums.hpp"
|
||||
|
||||
#include <boost/optional.hpp>
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
|
||||
struct sqlite3;
|
||||
|
||||
class ChatAvatarService {
|
||||
public:
|
||||
explicit ChatAvatarService(sqlite3* db);
|
||||
~ChatAvatarService();
|
||||
|
||||
ChatAvatar* GetAvatar(const std::u16string& name, const std::u16string& address);
|
||||
ChatAvatar* GetAvatar(uint32_t avatarId);
|
||||
|
||||
ChatAvatar* CreateAvatar(const std::u16string& name,
|
||||
const std::u16string& address, uint32_t userId, uint32_t loginAttributes,
|
||||
const std::u16string& loginLocation);
|
||||
|
||||
void DestroyAvatar(ChatAvatar* avatar);
|
||||
|
||||
void LoginAvatar(ChatAvatar* avatar);
|
||||
void LogoutAvatar(ChatAvatar* avatar);
|
||||
|
||||
void PersistAvatar(const ChatAvatar* avatar);
|
||||
void PersistFriend(uint32_t srcAvatarId, uint32_t destAvatarId, const std::u16string& comment);
|
||||
void PersistIgnore(uint32_t srcAvatarId, uint32_t destAvatarId);
|
||||
|
||||
void RemoveFriend(uint32_t srcAvatarId, uint32_t destAvatarId);
|
||||
void RemoveIgnore(uint32_t srcAvatarId, uint32_t destAvatarId);
|
||||
|
||||
void UpdateFriendComment(uint32_t srcAvatarId, uint32_t destAvatarId, const std::u16string& comment);
|
||||
|
||||
const std::vector<ChatAvatar*>& GetOnlineAvatars() const { return onlineAvatars_; }
|
||||
|
||||
private:
|
||||
ChatAvatar* GetCachedAvatar(const std::u16string& name, const std::u16string& address);
|
||||
ChatAvatar* GetCachedAvatar(uint32_t avatarId);
|
||||
|
||||
void RemoveCachedAvatar(uint32_t avatarId);
|
||||
void RemoveAsFriendOrIgnoreFromAll(const ChatAvatar* avatar);
|
||||
|
||||
std::unique_ptr<ChatAvatar> LoadStoredAvatar(const std::u16string& name, const std::u16string& address);
|
||||
std::unique_ptr<ChatAvatar> LoadStoredAvatar(uint32_t avatarId);
|
||||
|
||||
void InsertAvatar(ChatAvatar* avatar);
|
||||
void UpdateAvatar(const ChatAvatar* avatar);
|
||||
void DeleteAvatar(ChatAvatar* avatar);
|
||||
|
||||
void LoadFriendList(ChatAvatar* avatar);
|
||||
void LoadIgnoreList(ChatAvatar* avatar);
|
||||
|
||||
bool IsOnline(const ChatAvatar* avatar) const;
|
||||
|
||||
std::vector<std::unique_ptr<ChatAvatar>> avatarCache_;
|
||||
std::vector<ChatAvatar*> onlineAvatars_;
|
||||
sqlite3* db_;
|
||||
};
|
||||
@@ -0,0 +1,152 @@
|
||||
#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";
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,252 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
|
||||
enum class ChatRequestType : uint16_t {
|
||||
LOGINAVATAR = 0,
|
||||
LOGOUTAVATAR,
|
||||
DESTROYAVATAR,
|
||||
GETAVATAR,
|
||||
CREATEROOM,
|
||||
DESTROYROOM, // 5
|
||||
SENDINSTANTMESSAGE,
|
||||
SENDROOMMESSAGE,
|
||||
SENDBROADCASTMESSAGE,
|
||||
ADDFRIEND,
|
||||
REMOVEFRIEND, // 10
|
||||
FRIENDSTATUS,
|
||||
ADDIGNORE,
|
||||
REMOVEIGNORE,
|
||||
ENTERROOM,
|
||||
LEAVEROOM, // 15
|
||||
ADDMODERATOR,
|
||||
REMOVEMODERATOR,
|
||||
ADDBAN,
|
||||
REMOVEBAN,
|
||||
ADDINVITE, // 20
|
||||
REMOVEINVITE,
|
||||
KICKAVATAR,
|
||||
SETROOMPARAMS,
|
||||
GETROOM,
|
||||
GETROOMSUMMARIES, // 25
|
||||
SENDPERSISTENTMESSAGE,
|
||||
GETPERSISTENTHEADERS,
|
||||
GETPERSISTENTMESSAGE,
|
||||
UPDATEPERSISTENTMESSAGE,
|
||||
UNREGISTERROOM, // 30
|
||||
IGNORESTATUS,
|
||||
FAILOVER_RELOGINAVATAR,
|
||||
FAILOVER_RECREATEROOM,
|
||||
CONFIRMFRIEND,
|
||||
GETAVATARKEYWORDS, // 35
|
||||
SETAVATARKEYWORDS,
|
||||
SEARCHAVATARKEYWORDS,
|
||||
GETFANCLUBHANDLE,
|
||||
UPDATEPERSISTENTMESSAGES,
|
||||
FINDAVATARBYUID, // 40
|
||||
CHANGEROOMOWNER,
|
||||
SETAPIVERSION,
|
||||
ADDTEMPORARYMODERATOR,
|
||||
REMOVETEMPORARYMODERATOR,
|
||||
GRANTVOICE, // 45
|
||||
REVOKEVOICE,
|
||||
SETAVATARATTRIBUTES,
|
||||
ADDSNOOPAVATAR,
|
||||
REMOVESNOOPAVATAR,
|
||||
ADDSNOOPROOM, // 50
|
||||
REMOVESNOOPROOM,
|
||||
GETSNOOPLIST,
|
||||
PARTIALPERSISTENTHEADERS,
|
||||
COUNTPERSISTENTMESSAGES,
|
||||
PURGEPERSISTENTMESSAGES, // 55
|
||||
SETFRIENDCOMMENT,
|
||||
TRANSFERAVATAR,
|
||||
CHANGEPERSISTENTFOLDER,
|
||||
ALLOWROOMENTRY,
|
||||
SETAVATAREMAIL, // 60
|
||||
SETAVATARINBOXLIMIT,
|
||||
SENDMULTIPLEPERSISTENTMESSAGES,
|
||||
GETMULTIPLEPERSISTENTMESSAGES,
|
||||
ALTERPERISTENTMESSAGE,
|
||||
GETANYAVATAR, // 65
|
||||
TEMPORARYAVATAR,
|
||||
AVATARLIST,
|
||||
SETAVATARSTATUSMESSAGE,
|
||||
CONFIRMFRIEND_RECIPROCATE,
|
||||
ADDFRIEND_RECIPROCATE, // 70
|
||||
REMOVEFRIEND_RECIPROCATE,
|
||||
FILTERMESSAGE,
|
||||
FILTERMESSAGE_EX,
|
||||
REGISTRAR_GETCHATSERVER = 20001,
|
||||
};
|
||||
|
||||
enum class ChatResponseType : uint16_t {
|
||||
LOGINAVATAR = 0,
|
||||
LOGOUTAVATAR,
|
||||
DESTROYAVATAR,
|
||||
GETAVATAR,
|
||||
CREATEROOM,
|
||||
DESTROYROOM,
|
||||
SENDINSTANTMESSAGE,
|
||||
SENDROOMMESSAGE,
|
||||
SENDBROADCASTMESSAGE,
|
||||
ADDFRIEND,
|
||||
REMOVEFRIEND,
|
||||
FRIENDSTATUS,
|
||||
ADDIGNORE,
|
||||
REMOVEIGNORE,
|
||||
ENTERROOM,
|
||||
LEAVEROOM,
|
||||
ADDMODERATOR,
|
||||
REMOVEMODERATOR,
|
||||
ADDBAN,
|
||||
REMOVEBAN,
|
||||
ADDINVITE,
|
||||
REMOVEINVITE,
|
||||
KICKAVATAR,
|
||||
SETROOMPARAMS,
|
||||
GETROOM,
|
||||
GETROOMSUMMARIES,
|
||||
SENDPERSISTENTMESSAGE,
|
||||
GETPERSISTENTHEADERS,
|
||||
GETPERSISTENTMESSAGE,
|
||||
UPDATEPERSISTENTMESSAGE,
|
||||
UNREGISTERROOM,
|
||||
IGNORESTATUS,
|
||||
FAILOVER_RELOGINAVATAR,
|
||||
FAILOVER_RECREATEROOM,
|
||||
CONFIRMFRIEND,
|
||||
GETAVATARKEYWORDS,
|
||||
SETAVATARKEYWORDS,
|
||||
SEARCHAVATARKEYWORDS,
|
||||
GETFANCLUBHANDLE,
|
||||
UPDATEPERSISTENTMESSAGES,
|
||||
FINDAVATARBYUID,
|
||||
CHANGEROOMOWNER,
|
||||
SETAPIVERSION,
|
||||
ADDTEMPORARYMODERATOR,
|
||||
REMOVETEMPORARYMODERATOR,
|
||||
GRANTVOICE,
|
||||
REVOKEVOICE,
|
||||
SETAVATARATTRIBUTES,
|
||||
ADDSNOOPAVATAR,
|
||||
REMOVESNOOPAVATAR,
|
||||
ADDSNOOPROOM,
|
||||
REMOVESNOOPROOM,
|
||||
GETSNOOPLIST,
|
||||
PARTIALPERSISTENTHEADERS,
|
||||
COUNTPERSISTENTMESSAGES,
|
||||
PURGEPERSISTENTMESSAGES,
|
||||
SETFRIENDCOMMENT,
|
||||
TRANSFERAVATAR,
|
||||
CHANGEPERSISTENTFOLDER,
|
||||
ALLOWROOMENTRY,
|
||||
SETAVATAREMAIL,
|
||||
SETAVATARINBOXLIMIT,
|
||||
SENDMULTIPLEPERSISTENTMESSAGES,
|
||||
GETMULTIPLEPERSISTENTMESSAGES,
|
||||
ALTERPERSISTENTMESSAGE,
|
||||
GETANYAVATAR,
|
||||
TEMPORARYAVATAR,
|
||||
AVATARLIST,
|
||||
SETSTATUSMESSAGE,
|
||||
CONFIRMFRIEND_RECIPROCATE,
|
||||
ADDFRIEND_RECIPROCATE,
|
||||
REMOVEFRIEND_RECIPROCATE,
|
||||
FILTERMESSAGE,
|
||||
FILTERMESSAGE_EX,
|
||||
|
||||
REGISTRAR_GETCHATSERVER = 20001,
|
||||
};
|
||||
|
||||
enum class ChatResultCode : uint32_t {
|
||||
SUCCESS = 0,
|
||||
TIMEOUT = 1,
|
||||
DUPLICATELOGIN,
|
||||
SRCAVATARDOESNTEXIST,
|
||||
DESTAVATARDOESNTEXIST,
|
||||
ADDRESSDOESNTEXIST, // 5
|
||||
ADDRESSNOTROOM,
|
||||
ADDRESSNOTAID,
|
||||
FRIENDNOTFOUND,
|
||||
ROOM_UNKNOWNFAILURE,
|
||||
ROOM_SRCNOTINROOM, // 10
|
||||
ROOM_DESTNOTINROOM,
|
||||
ROOM_BANNEDAVATAR,
|
||||
ROOM_PRIVATEROOM,
|
||||
ROOM_MODERATEDROOM,
|
||||
ROOM_NOTINROOM, // 15
|
||||
ROOM_NOPRIVILEGES,
|
||||
DATABASE,
|
||||
CANNOTGETAVATARID,
|
||||
CANNOTGETNODEID,
|
||||
CANNOTGETPMSGID, // 20
|
||||
PMSGNOTFOUND,
|
||||
ROOMMAXAVATARSREACHED,
|
||||
IGNORING,
|
||||
ROOM_ALREADYEXISTS,
|
||||
NOTHINGTOCONFIRM, // 25
|
||||
DUPLICATEFRIEND,
|
||||
IGNORENOTFOUND,
|
||||
DUPLICATEIGNORE,
|
||||
DBFAIL,
|
||||
ROOM_DESTAVATARNOTMODERATOR, // 30
|
||||
ROOM_DESTAVATARNOTINVITED,
|
||||
ROOM_DESTAVATARNOTBANNED,
|
||||
ROOM_DUPLICATEBAN,
|
||||
ROOM_DUPLICATEMODERATOR,
|
||||
ROOM_DUPLICATEINVITE, // 35
|
||||
ROOM_ALREADYINROOM,
|
||||
ROOM_PARENTNONPERSISTENT,
|
||||
ROOM_PARENTBADNODETYPE,
|
||||
NOFANCLUBHANDLE,
|
||||
AIDALREADYEXISTS, // 40
|
||||
UIDALREADYEXISTS,
|
||||
WRONGCHATSERVERFORREQUEST,
|
||||
SUCCESSBADDATA,
|
||||
NULLNAMELOGIN,
|
||||
SERVER_IDENTITY_EMPTY, // 45
|
||||
SERVER_IDENTITY_TAKEN,
|
||||
REMOTESERVERDOWN,
|
||||
NODEIDCONFLICT,
|
||||
INVALIDNODENAME,
|
||||
INSUFFICIENTGMPRIVS, // 50
|
||||
SNOOPALREADYADDED,
|
||||
NOTSNOOPING,
|
||||
ROOM_DESTAVATARNOTTEMPORARYMODERATOR,
|
||||
ROOM_DESTAVATARNOTVOICE,
|
||||
ROOM_DUPLICATETEMPORARYMODERATOR, // 55
|
||||
ROOM_DUPLICATEVOICE,
|
||||
AVATARMUSTBELOGGEDOUT,
|
||||
NOTHINGTODO,
|
||||
TRANSFERNAMENULL,
|
||||
TRANSFERUSERIDZERO, // 60
|
||||
TRANSFERADDRESSNULL,
|
||||
OUTOFIDS,
|
||||
ROOM_LOCALROOM,
|
||||
ROOM_GAMEROOM,
|
||||
ROOM_DESTAVATARNOTENTERING, // 65
|
||||
INSUFFICIENTPRIORITY,
|
||||
ROOM_WAITINGFORENTRY,
|
||||
INBOXLIMITEXCEEDED,
|
||||
DUPLICATEDESTINATION,
|
||||
CATEGORYLIMITEXCEEDED, // 70
|
||||
MESSAGE_FILTER_FAILURE,
|
||||
INVALID_INPUT,
|
||||
};
|
||||
|
||||
struct ChatResultException {
|
||||
ChatResultCode code;
|
||||
std::string message;
|
||||
|
||||
explicit ChatResultException(const ChatResultCode result)
|
||||
: code{result} {}
|
||||
|
||||
ChatResultException(const ChatResultCode result, char const * text)
|
||||
: code{result}
|
||||
, message{text} {}
|
||||
};
|
||||
|
||||
const char* ToString(ChatResultCode code);
|
||||
@@ -0,0 +1,307 @@
|
||||
|
||||
#include "ChatRoom.hpp"
|
||||
#include "ChatAvatar.hpp"
|
||||
#include "ChatRoomService.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
inline unsigned IS_SET(unsigned var, unsigned bit) { return (var & bit); }
|
||||
|
||||
ChatRoom::ChatRoom(ChatRoomService* roomService, uint32_t roomId, const ChatAvatar* creator,
|
||||
const std::u16string& roomName, const std::u16string& roomTopic, const std::u16string& roomPassword,
|
||||
uint32_t roomAttributes, uint32_t maxRoomSize, const std::u16string& roomAddress,
|
||||
const std::u16string& srcAddress)
|
||||
: roomService_{roomService}
|
||||
, roomId_{roomId}
|
||||
, creatorName_{creator->GetName()}
|
||||
, creatorAddress_{creator->GetAddress()}
|
||||
, roomName_{roomName}
|
||||
, roomTopic_{roomTopic}
|
||||
, roomPassword_{roomPassword}
|
||||
, roomAddress_{roomAddress + u"+" + roomName}
|
||||
, creatorId_{creator->GetAvatarId()}
|
||||
, roomAttributes_{roomAttributes}
|
||||
, maxRoomSize_{maxRoomSize} {
|
||||
administrators_.push_back(creator);
|
||||
moderators_.push_back(creator);
|
||||
}
|
||||
|
||||
bool ChatRoom::IsPrivate() const {
|
||||
return (roomAttributes_ & static_cast<uint32_t>(RoomAttributes::PRIVATE)) != 0;
|
||||
}
|
||||
|
||||
bool ChatRoom::IsModerated() const {
|
||||
return (roomAttributes_ & static_cast<uint32_t>(RoomAttributes::MODERATED)) != 0;
|
||||
}
|
||||
|
||||
bool ChatRoom::IsPersistent() const {
|
||||
return (roomAttributes_ & static_cast<uint32_t>(RoomAttributes::PERSISTENT)) != 0;
|
||||
}
|
||||
|
||||
bool ChatRoom::IsLocalWorld() const {
|
||||
return (roomAttributes_ & static_cast<uint32_t>(RoomAttributes::LOCAL_WORLD)) != 0;
|
||||
}
|
||||
|
||||
bool ChatRoom::IsLocalGame() const {
|
||||
return (roomAttributes_ & static_cast<uint32_t>(RoomAttributes::LOCAL_GAME)) != 0;
|
||||
}
|
||||
|
||||
void ChatRoom::EnterRoom(ChatAvatar* avatar, const std::u16string& password) {
|
||||
if (roomPassword_.length() > 0 && roomPassword_.compare(password) != 0) {
|
||||
throw ChatResultException{ChatResultCode::ROOM_PRIVATEROOM};
|
||||
}
|
||||
|
||||
if (IsBanned(avatar->GetAvatarId())) {
|
||||
throw ChatResultException{ChatResultCode::ROOM_BANNEDAVATAR};
|
||||
}
|
||||
|
||||
if (IsInRoom(avatar)) {
|
||||
throw ChatResultException{ChatResultCode::ROOM_ALREADYINROOM};
|
||||
}
|
||||
|
||||
if (IsPrivate() && !IsCreator(avatar->GetAvatarId()) && !IsInvited(avatar->GetAvatarId())) {
|
||||
throw ChatResultException{ChatResultCode::ROOM_PRIVATEROOM};
|
||||
}
|
||||
|
||||
avatars_.push_back(avatar);
|
||||
avatarIds_.push_back(avatar->GetAvatarId());
|
||||
avatar->JoinRoom(this);
|
||||
}
|
||||
|
||||
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) {
|
||||
avatar->UnjoinRoom(this);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
auto avatarsIdIter = std::remove_if(std::begin(avatarIds_), std::end(avatarIds_), [avatar](auto avatarId) {
|
||||
return avatar->GetAvatarId() == avatarId;
|
||||
});
|
||||
|
||||
if (avatarsIdIter != std::end(avatarIds_)) {
|
||||
avatarIds_.erase(avatarsIdIter);
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<std::u16string> ChatRoom::GetConnectedAddresses() const {
|
||||
std::vector<std::u16string> connectedAddresses;
|
||||
|
||||
std::u16string address;
|
||||
for (auto avatar : avatars_) {
|
||||
address = avatar->GetAddress();
|
||||
if (connectedAddresses.empty()
|
||||
|| std::none_of(std::begin(connectedAddresses), std::end(connectedAddresses),
|
||||
[&address](const auto& connectedAddress) {
|
||||
return connectedAddress.compare(address) == 0;
|
||||
})) {
|
||||
connectedAddresses.push_back(address);
|
||||
}
|
||||
}
|
||||
|
||||
return connectedAddresses;
|
||||
}
|
||||
|
||||
std::vector<std::u16string> ChatRoom::GetRemoteAddresses() const {
|
||||
std::vector<std::u16string> connectedAddresses;
|
||||
|
||||
std::u16string address;
|
||||
for (auto avatar : avatars_) {
|
||||
address = avatar->GetAddress();
|
||||
if (creatorAddress_.compare(address) != 0 && (connectedAddresses.empty()
|
||||
|| std::none_of(std::begin(connectedAddresses), std::end(connectedAddresses),
|
||||
[&address](const auto& connectedAddress) {
|
||||
return connectedAddress.compare(address) == 0;
|
||||
}))) {
|
||||
connectedAddresses.push_back(address);
|
||||
}
|
||||
}
|
||||
|
||||
return connectedAddresses;
|
||||
}
|
||||
|
||||
bool ChatRoom::IsCreator(uint32_t avatarId) const { return avatarId == creatorId_; }
|
||||
|
||||
bool ChatRoom::IsModerator(uint32_t avatarId) const {
|
||||
if (moderators_.empty())
|
||||
return false;
|
||||
|
||||
auto find_iter = std::find_if(std::begin(moderators_), std::end(moderators_),
|
||||
[avatarId](const auto& moderator) { return moderator->GetAvatarId() == avatarId; });
|
||||
|
||||
return find_iter != std::end(moderators_);
|
||||
}
|
||||
|
||||
bool ChatRoom::IsAdministrator(uint32_t avatarId) const {
|
||||
if (administrators_.empty())
|
||||
return false;
|
||||
|
||||
auto find_iter = std::find_if(std::begin(administrators_), std::end(administrators_),
|
||||
[avatarId](const auto& administrator) { return administrator->GetAvatarId() == avatarId; });
|
||||
|
||||
return find_iter != std::end(administrators_);
|
||||
}
|
||||
|
||||
bool ChatRoom::IsBanned(uint32_t avatarId) const {
|
||||
if (banned_.empty())
|
||||
return false;
|
||||
|
||||
auto find_iter = std::find_if(std::begin(banned_), std::end(banned_),
|
||||
[avatarId](const auto& banned) { return banned->GetAvatarId() == avatarId; });
|
||||
|
||||
return find_iter != std::end(banned_);
|
||||
}
|
||||
|
||||
bool ChatRoom::IsInvited(uint32_t avatarId) const {
|
||||
if (invited_.empty())
|
||||
return false;
|
||||
|
||||
auto find_iter = std::find_if(std::begin(invited_), std::end(invited_),
|
||||
[avatarId](const auto& invited) { return invited->GetAvatarId() == avatarId; });
|
||||
|
||||
return find_iter != std::end(invited_);
|
||||
}
|
||||
|
||||
void ChatRoom::KickAvatar(uint32_t srcAvatarId, ChatAvatar* destAvatar) {
|
||||
if (!IsModerator(srcAvatarId)) {
|
||||
throw ChatResultException{ChatResultCode::ROOM_NOPRIVILEGES};
|
||||
}
|
||||
|
||||
if (!IsInRoom(destAvatar)) {
|
||||
throw ChatResultException{ChatResultCode::ROOM_NOTINROOM};
|
||||
}
|
||||
|
||||
LeaveRoom(destAvatar);
|
||||
}
|
||||
|
||||
void ChatRoom::AddAdministrator(uint32_t srcAvatarId, ChatAvatar* administrator) {
|
||||
if (!IsCreator(srcAvatarId)) {
|
||||
throw ChatResultException{ChatResultCode::ROOM_NOPRIVILEGES};
|
||||
}
|
||||
|
||||
if (!IsAdministrator(administrator->GetAvatarId())) {
|
||||
administrators_.push_back(administrator);
|
||||
|
||||
if (IsPersistent()) {
|
||||
roomService_->PersistBanned(administrator->GetAvatarId(), roomId_);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ChatRoom::AddModerator(uint32_t srcAvatarId, ChatAvatar* moderator) {
|
||||
if (!IsCreator(srcAvatarId)) {
|
||||
throw ChatResultException{ChatResultCode::ROOM_NOPRIVILEGES};
|
||||
}
|
||||
|
||||
if (IsModerator(moderator->GetAvatarId())) {
|
||||
throw ChatResultException{ChatResultCode::ROOM_DUPLICATEMODERATOR};
|
||||
}
|
||||
|
||||
moderators_.push_back(moderator);
|
||||
|
||||
if (IsPersistent()) {
|
||||
roomService_->PersistBanned(moderator->GetAvatarId(), roomId_);
|
||||
}
|
||||
}
|
||||
|
||||
void ChatRoom::AddBanned(uint32_t srcAvatarId, ChatAvatar* banned) {
|
||||
if (!IsModerator(srcAvatarId)) {
|
||||
throw ChatResultException{ChatResultCode::ROOM_NOPRIVILEGES};
|
||||
}
|
||||
|
||||
if (IsBanned(banned->GetAvatarId())) {
|
||||
throw ChatResultException{ChatResultCode::ROOM_DUPLICATEBAN};
|
||||
}
|
||||
|
||||
banned_.push_back(banned);
|
||||
|
||||
if (IsPersistent()) {
|
||||
roomService_->PersistBanned(banned->GetAvatarId(), roomId_);
|
||||
}
|
||||
}
|
||||
|
||||
void ChatRoom::AddInvite(uint32_t srcAvatarId, ChatAvatar* invited) {
|
||||
if (!IsModerator(srcAvatarId)) {
|
||||
throw ChatResultException{ChatResultCode::ROOM_NOPRIVILEGES};
|
||||
}
|
||||
|
||||
if (IsInvited(invited->GetAvatarId())) {
|
||||
throw ChatResultException{ChatResultCode::ROOM_DUPLICATEINVITE};
|
||||
}
|
||||
|
||||
invited_.push_back(invited);
|
||||
}
|
||||
|
||||
void ChatRoom::RemoveAdministrator(uint32_t srcAvatarId, uint32_t avatarId) {
|
||||
if (!IsCreator(srcAvatarId)) {
|
||||
throw ChatResultException{ChatResultCode::ROOM_NOPRIVILEGES};
|
||||
}
|
||||
|
||||
if (administrators_.empty())
|
||||
return;
|
||||
|
||||
administrators_.erase(std::remove_if(std::begin(administrators_), std::end(administrators_),
|
||||
[avatarId](auto administrator) { return administrator->GetAvatarId() == avatarId; }));
|
||||
|
||||
if (IsPersistent()) {
|
||||
roomService_->DeleteAdministrator(avatarId, roomId_);
|
||||
}
|
||||
}
|
||||
|
||||
void ChatRoom::RemoveModerator(uint32_t srcAvatarId, uint32_t avatarId) {
|
||||
if (!IsCreator(srcAvatarId)) {
|
||||
throw ChatResultException{ChatResultCode::ROOM_NOPRIVILEGES};
|
||||
}
|
||||
|
||||
if (moderators_.empty() || !IsModerator(avatarId)) {
|
||||
throw ChatResultException{ChatResultCode::ROOM_DESTAVATARNOTMODERATOR};
|
||||
}
|
||||
|
||||
moderators_.erase(std::remove_if(std::begin(moderators_), std::end(moderators_),
|
||||
[avatarId](auto moderator) { return moderator->GetAvatarId() == avatarId; }));
|
||||
|
||||
if (IsPersistent()) {
|
||||
roomService_->DeleteModerator(avatarId, roomId_);
|
||||
}
|
||||
}
|
||||
|
||||
void ChatRoom::RemoveBanned(uint32_t srcAvatarId, uint32_t avatarId) {
|
||||
if (!IsModerator(srcAvatarId)) {
|
||||
throw ChatResultException{ChatResultCode::ROOM_NOPRIVILEGES};
|
||||
}
|
||||
|
||||
if (banned_.empty() || !IsBanned(avatarId)) {
|
||||
throw ChatResultException{ChatResultCode::ROOM_DESTAVATARNOTBANNED};
|
||||
}
|
||||
|
||||
banned_.erase(std::remove_if(std::begin(banned_), std::end(banned_),
|
||||
[avatarId](auto banned) { return banned->GetAvatarId() == avatarId; }));
|
||||
|
||||
if (IsPersistent()) {
|
||||
roomService_->DeleteBanned(avatarId, roomId_);
|
||||
}
|
||||
}
|
||||
|
||||
void ChatRoom::RemoveInvite(uint32_t srcAvatarId, uint32_t avatarId) {
|
||||
if (!IsModerator(srcAvatarId)) {
|
||||
throw ChatResultException{ChatResultCode::ROOM_NOPRIVILEGES};
|
||||
}
|
||||
|
||||
if (invited_.empty() || !IsInvited(avatarId)) {
|
||||
throw ChatResultException{ChatResultCode::ROOM_DESTAVATARNOTINVITED};
|
||||
}
|
||||
|
||||
invited_.erase(std::remove_if(std::begin(invited_), std::end(invited_),
|
||||
[avatarId](auto invited) { return invited->GetAvatarId() == avatarId; }));
|
||||
}
|
||||
@@ -0,0 +1,169 @@
|
||||
|
||||
#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_; }
|
||||
std::vector<uint32_t> GetAvatarIds() const { return avatarIds_; }
|
||||
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<uint32_t> avatarIds_;
|
||||
std::vector<const ChatAvatar*> administrators_;
|
||||
std::vector<const ChatAvatar*> moderators_;
|
||||
std::vector<const ChatAvatar*> tempModerators_;
|
||||
std::vector<const ChatAvatar*> banned_;
|
||||
std::vector<const ChatAvatar*> invited_;
|
||||
std::vector<const ChatAvatar*> voice_;
|
||||
};
|
||||
|
||||
template <typename StreamT>
|
||||
void write(StreamT& ar, const ChatRoom& data) {
|
||||
write(ar, data.GetCreatorName());
|
||||
write(ar, data.GetCreatorAddress());
|
||||
write(ar, data.GetCreatorId());
|
||||
write(ar, data.GetRoomName());
|
||||
write(ar, data.GetRoomTopic());
|
||||
write(ar, data.GetRoomPrefix());
|
||||
write(ar, data.GetRoomAddress());
|
||||
write(ar, data.GetRoomPassword());
|
||||
write(ar, data.GetRoomAttributes());
|
||||
write(ar, data.GetMaxRoomSize());
|
||||
write(ar, data.GetRoomId());
|
||||
write(ar, data.GetCreateTime());
|
||||
write(ar, data.GetNodeLevel());
|
||||
|
||||
auto& avatars = data.GetAvatars();
|
||||
write(ar, static_cast<uint32_t>(avatars.size()));
|
||||
for (auto& avatar : avatars)
|
||||
write(ar, avatar);
|
||||
|
||||
auto& administrators = data.GetAdminstrators();
|
||||
write(ar, static_cast<uint32_t>(administrators.size()));
|
||||
for (auto& avatar : administrators)
|
||||
write(ar, avatar);
|
||||
|
||||
auto& moderators = data.GetModerators();
|
||||
write(ar, static_cast<uint32_t>(moderators.size()));
|
||||
for (auto& avatar : moderators)
|
||||
write(ar, avatar);
|
||||
|
||||
auto& tempModerators = data.GetTempModerators();
|
||||
write(ar, static_cast<uint32_t>(tempModerators.size()));
|
||||
for (auto& avatar : tempModerators)
|
||||
write(ar, avatar);
|
||||
|
||||
auto& banned = data.GetBanned();
|
||||
write(ar, static_cast<uint32_t>(banned.size()));
|
||||
for (auto& avatar : banned)
|
||||
write(ar, avatar);
|
||||
|
||||
auto& invited = data.GetInvited();
|
||||
write(ar, static_cast<uint32_t>(invited.size()));
|
||||
for (auto& avatar : invited)
|
||||
write(ar, avatar);
|
||||
|
||||
auto& voice = data.GetVoice();
|
||||
write(ar, static_cast<uint32_t>(voice.size()));
|
||||
for (auto& avatar : voice)
|
||||
write(ar, avatar);
|
||||
}
|
||||
@@ -0,0 +1,407 @@
|
||||
#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;
|
||||
}
|
||||
|
||||
void ChatRoomService::DeleteRoom(ChatRoom* room) {
|
||||
sqlite3_stmt* stmt;
|
||||
char sql[] = "DELETE FROM room WHERE id = @id";
|
||||
|
||||
auto result = sqlite3_prepare_v2(db_, sql, -1, &stmt, 0);
|
||||
if (result != SQLITE_OK) {
|
||||
throw SQLite3Exception{result, sqlite3_errmsg(db_)};
|
||||
}
|
||||
|
||||
int idIdx = sqlite3_bind_parameter_index(stmt, "@id");
|
||||
sqlite3_bind_int(stmt, idIdx, room->dbId_);
|
||||
|
||||
result = sqlite3_step(stmt);
|
||||
if (result != SQLITE_DONE) {
|
||||
throw SQLite3Exception{result, sqlite3_errmsg(db_)};
|
||||
}
|
||||
}
|
||||
|
||||
void ChatRoomService::LoadModerators(ChatRoom * room) {
|
||||
sqlite3_stmt* stmt;
|
||||
char sql[] = "SELECT moderator_avatar_id FROM room_moderator WHERE room_id = @room_id";
|
||||
|
||||
auto result = sqlite3_prepare_v2(db_, sql, -1, &stmt, 0);
|
||||
if (result != SQLITE_OK) {
|
||||
throw SQLite3Exception{result, sqlite3_errmsg(db_)};
|
||||
}
|
||||
|
||||
int roomIdIdx = sqlite3_bind_parameter_index(stmt, "@room_id");
|
||||
sqlite3_bind_int(stmt, roomIdIdx, room->GetRoomId());
|
||||
|
||||
while (sqlite3_step(stmt) == SQLITE_ROW) {
|
||||
uint32_t moderatorId = sqlite3_column_int(stmt, 0);
|
||||
room->moderators_.push_back(avatarService_->GetAvatar(moderatorId));
|
||||
}
|
||||
}
|
||||
|
||||
void ChatRoomService::PersistModerator(uint32_t moderatorId, uint32_t roomId) {
|
||||
sqlite3_stmt* stmt;
|
||||
char sql[] = "INSERT OR IGNORE INTO room_moderator (moderator_avatar_id, room_id) VALUES (@moderator_avatar_id, @room_id)";
|
||||
|
||||
auto result = sqlite3_prepare_v2(db_, sql, -1, &stmt, 0);
|
||||
if (result != SQLITE_OK) {
|
||||
throw SQLite3Exception{result, sqlite3_errmsg(db_)};
|
||||
}
|
||||
|
||||
int moderatorAvatarIdIdx = sqlite3_bind_parameter_index(stmt, "@moderator_avatar_id");
|
||||
int roomIdIdx = sqlite3_bind_parameter_index(stmt, "@room_id");
|
||||
|
||||
sqlite3_bind_int(stmt, moderatorAvatarIdIdx, moderatorId);
|
||||
sqlite3_bind_int(stmt, roomIdIdx, roomId);
|
||||
|
||||
result = sqlite3_step(stmt);
|
||||
if (result != SQLITE_DONE) {
|
||||
throw SQLite3Exception{result, sqlite3_errmsg(db_)};
|
||||
}
|
||||
}
|
||||
|
||||
void ChatRoomService::DeleteModerator(uint32_t moderatorId, uint32_t roomId) {
|
||||
sqlite3_stmt* stmt;
|
||||
char sql[] = "DELETE FROM room_moderator WHERE moderator_avatar_id = @moderator_avatar_id AND room_id = @room_id";
|
||||
|
||||
auto result = sqlite3_prepare_v2(db_, sql, -1, &stmt, 0);
|
||||
if (result != SQLITE_OK) {
|
||||
throw SQLite3Exception{result, sqlite3_errmsg(db_)};
|
||||
}
|
||||
|
||||
int moderatorAvatarIdIdx = sqlite3_bind_parameter_index(stmt, "@moderator_avatar_id");
|
||||
int roomIdIdx = sqlite3_bind_parameter_index(stmt, "@room_id");
|
||||
|
||||
sqlite3_bind_int(stmt, moderatorAvatarIdIdx, moderatorId);
|
||||
sqlite3_bind_int(stmt, roomIdIdx, roomId);
|
||||
|
||||
result = sqlite3_step(stmt);
|
||||
if (result != SQLITE_DONE) {
|
||||
throw SQLite3Exception{result, sqlite3_errmsg(db_)};
|
||||
}
|
||||
}
|
||||
|
||||
void ChatRoomService::LoadAdministrators(ChatRoom * room) {
|
||||
sqlite3_stmt* stmt;
|
||||
char sql[] = "SELECT administrator_avatar_id FROM room_administrator WHERE room_id = @room_id";
|
||||
|
||||
auto result = sqlite3_prepare_v2(db_, sql, -1, &stmt, 0);
|
||||
if (result != SQLITE_OK) {
|
||||
throw SQLite3Exception{result, sqlite3_errmsg(db_)};
|
||||
}
|
||||
|
||||
int roomIdIdx = sqlite3_bind_parameter_index(stmt, "@room_id");
|
||||
sqlite3_bind_int(stmt, roomIdIdx, room->GetRoomId());
|
||||
|
||||
while (sqlite3_step(stmt) == SQLITE_ROW) {
|
||||
uint32_t administratorId = sqlite3_column_int(stmt, 0);
|
||||
room->administrators_.push_back(avatarService_->GetAvatar(administratorId));
|
||||
}
|
||||
}
|
||||
|
||||
void ChatRoomService::PersistAdministrator(uint32_t administratorId, uint32_t roomId) {
|
||||
sqlite3_stmt* stmt;
|
||||
char sql[] = "INSERT OR IGNORE INTO room_administrator (administrator_avatar_id, room_id) VALUES (@administrator_avatar_id, @room_id)";
|
||||
|
||||
auto result = sqlite3_prepare_v2(db_, sql, -1, &stmt, 0);
|
||||
if (result != SQLITE_OK) {
|
||||
throw SQLite3Exception{result, sqlite3_errmsg(db_)};
|
||||
}
|
||||
|
||||
int administratorAvatarIdIdx = sqlite3_bind_parameter_index(stmt, "@administrator_avatar_id");
|
||||
int roomIdIdx = sqlite3_bind_parameter_index(stmt, "@room_id");
|
||||
|
||||
sqlite3_bind_int(stmt, administratorAvatarIdIdx, administratorId);
|
||||
sqlite3_bind_int(stmt, roomIdIdx, roomId);
|
||||
|
||||
result = sqlite3_step(stmt);
|
||||
if (result != SQLITE_DONE) {
|
||||
throw SQLite3Exception{result, sqlite3_errmsg(db_)};
|
||||
}
|
||||
}
|
||||
|
||||
void ChatRoomService::DeleteAdministrator(uint32_t administratorId, uint32_t roomId) {
|
||||
sqlite3_stmt* stmt;
|
||||
char sql[] = "DELETE FROM room_administrator WHERE administrator_avatar_id = @administrator_avatar_id AND room_id = @room_id";
|
||||
|
||||
auto result = sqlite3_prepare_v2(db_, sql, -1, &stmt, 0);
|
||||
if (result != SQLITE_OK) {
|
||||
throw SQLite3Exception{result, sqlite3_errmsg(db_)};
|
||||
}
|
||||
|
||||
int administratorAvatarIdIdx = sqlite3_bind_parameter_index(stmt, "@administrator_avatar_id");
|
||||
int roomIdIdx = sqlite3_bind_parameter_index(stmt, "@room_id");
|
||||
|
||||
sqlite3_bind_int(stmt, administratorAvatarIdIdx, administratorId);
|
||||
sqlite3_bind_int(stmt, roomIdIdx, roomId);
|
||||
|
||||
result = sqlite3_step(stmt);
|
||||
if (result != SQLITE_DONE) {
|
||||
throw SQLite3Exception{result, sqlite3_errmsg(db_)};
|
||||
}
|
||||
}
|
||||
|
||||
void ChatRoomService::LoadBanned(ChatRoom * room) {
|
||||
sqlite3_stmt* stmt;
|
||||
char sql[] = "SELECT banned_avatar_id FROM room_ban WHERE room_id = @room_id";
|
||||
|
||||
auto result = sqlite3_prepare_v2(db_, sql, -1, &stmt, 0);
|
||||
if (result != SQLITE_OK) {
|
||||
throw SQLite3Exception{result, sqlite3_errmsg(db_)};
|
||||
}
|
||||
|
||||
int roomIdIdx = sqlite3_bind_parameter_index(stmt, "@room_id");
|
||||
sqlite3_bind_int(stmt, roomIdIdx, room->GetRoomId());
|
||||
|
||||
while (sqlite3_step(stmt) == SQLITE_ROW) {
|
||||
uint32_t bannedId = sqlite3_column_int(stmt, 0);
|
||||
room->banned_.push_back(avatarService_->GetAvatar(bannedId));
|
||||
}
|
||||
}
|
||||
|
||||
void ChatRoomService::PersistBanned(uint32_t bannedId, uint32_t roomId) {
|
||||
sqlite3_stmt* stmt;
|
||||
char sql[] = "INSERT OR IGNORE INTO room_ban (banned_avatar_id, room_id) VALUES (@banned_avatar_id, @room_id)";
|
||||
|
||||
auto result = sqlite3_prepare_v2(db_, sql, -1, &stmt, 0);
|
||||
if (result != SQLITE_OK) {
|
||||
throw SQLite3Exception{result, sqlite3_errmsg(db_)};
|
||||
}
|
||||
|
||||
int bannedAvatarIdIdx = sqlite3_bind_parameter_index(stmt, "@moderator_avatar_id");
|
||||
int roomIdIdx = sqlite3_bind_parameter_index(stmt, "@room_id");
|
||||
|
||||
sqlite3_bind_int(stmt, bannedAvatarIdIdx, bannedId);
|
||||
sqlite3_bind_int(stmt, roomIdIdx, roomId);
|
||||
|
||||
result = sqlite3_step(stmt);
|
||||
if (result != SQLITE_DONE) {
|
||||
throw SQLite3Exception{result, sqlite3_errmsg(db_)};
|
||||
}
|
||||
}
|
||||
|
||||
void ChatRoomService::DeleteBanned(uint32_t bannedId, uint32_t roomId) {
|
||||
sqlite3_stmt* stmt;
|
||||
char sql[] = "DELETE FROM room_ban WHERE banned_avatar_id = @banned_avatar_id AND room_id = @room_id";
|
||||
|
||||
auto result = sqlite3_prepare_v2(db_, sql, -1, &stmt, 0);
|
||||
if (result != SQLITE_OK) {
|
||||
throw SQLite3Exception{result, sqlite3_errmsg(db_)};
|
||||
}
|
||||
|
||||
int bannedAvatarIdIdx = sqlite3_bind_parameter_index(stmt, "@banned_avatar_id");
|
||||
int roomIdIdx = sqlite3_bind_parameter_index(stmt, "@room_id");
|
||||
|
||||
sqlite3_bind_int(stmt, bannedAvatarIdIdx, bannedId);
|
||||
sqlite3_bind_int(stmt, roomIdIdx, roomId);
|
||||
|
||||
result = sqlite3_step(stmt);
|
||||
if (result != SQLITE_DONE) {
|
||||
throw SQLite3Exception{result, sqlite3_errmsg(db_)};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
|
||||
#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);
|
||||
|
||||
private:
|
||||
friend class ChatRoom;
|
||||
void DeleteRoom(ChatRoom* room);
|
||||
void LoadModerators(ChatRoom* room);
|
||||
void PersistModerator(uint32_t moderatorId, uint32_t roomId);
|
||||
void DeleteModerator(uint32_t moderatorId, uint32_t roomId);
|
||||
void LoadAdministrators(ChatRoom* room);
|
||||
void PersistAdministrator(uint32_t administratorId, uint32_t roomId);
|
||||
void DeleteAdministrator(uint32_t administratorId, uint32_t roomId);
|
||||
void LoadBanned(ChatRoom* room);
|
||||
void PersistBanned(uint32_t bannedId, uint32_t roomId);
|
||||
void DeleteBanned(uint32_t bannedId, uint32_t roomId);
|
||||
|
||||
uint32_t nextRoomId_ = 0;
|
||||
std::vector<std::unique_ptr<ChatRoom>> rooms_;
|
||||
ChatAvatarService* avatarService_;
|
||||
sqlite3* db_;
|
||||
};
|
||||
@@ -0,0 +1,38 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Serialization.hpp"
|
||||
|
||||
#include <string>
|
||||
|
||||
class ChatAvatar;
|
||||
|
||||
struct FriendContact {
|
||||
FriendContact(const ChatAvatar* frnd_, const std::wstring& comment_)
|
||||
: frnd{frnd_}
|
||||
, comment{comment_} {}
|
||||
|
||||
const ChatAvatar* frnd;
|
||||
std::wstring comment = L"";
|
||||
};
|
||||
|
||||
template <typename StreamT>
|
||||
void write(StreamT& ar, const FriendContact& data) {
|
||||
write(ar, data.frnd->GetName());
|
||||
write(ar, data.frnd->GetAddress());
|
||||
write(ar, data.comment);
|
||||
write(ar, static_cast<short>(data.frnd->IsOnline() ? 1 : 0));
|
||||
}
|
||||
|
||||
struct IgnoreContact {
|
||||
IgnoreContact(const ChatAvatar* ignored_)
|
||||
: ignored{ignored_} {}
|
||||
|
||||
const ChatAvatar* ignored;
|
||||
};
|
||||
|
||||
template <typename StreamT>
|
||||
void write(StreamT& ar, const IgnoreContact& data) {
|
||||
write(ar, data.ignored->GetName());
|
||||
write(ar, data.ignored->GetAddress());
|
||||
}
|
||||
@@ -0,0 +1,245 @@
|
||||
|
||||
#include "GatewayClient.hpp"
|
||||
|
||||
#include "ChatAvatarService.hpp"
|
||||
#include "ChatEnums.hpp"
|
||||
#include "ChatRoomService.hpp"
|
||||
#include "GatewayNode.hpp"
|
||||
#include "Message.hpp"
|
||||
#include "PersistentMessageService.hpp"
|
||||
#include "SQLite3.hpp"
|
||||
#include "StationChatConfig.hpp"
|
||||
#include "UdpLibrary.hpp"
|
||||
|
||||
#include "protocol/AddBan.hpp"
|
||||
#include "protocol/AddFriend.hpp"
|
||||
#include "protocol/AddIgnore.hpp"
|
||||
#include "protocol/AddInvite.hpp"
|
||||
#include "protocol/AddModerator.hpp"
|
||||
#include "protocol/CreateRoom.hpp"
|
||||
#include "protocol/DestroyRoom.hpp"
|
||||
#include "protocol/EnterRoom.hpp"
|
||||
#include "protocol/FailoverReLoginAvatar.hpp"
|
||||
#include "protocol/FriendStatus.hpp"
|
||||
#include "protocol/GetAnyAvatar.hpp"
|
||||
#include "protocol/GetPersistentHeaders.hpp"
|
||||
#include "protocol/GetPersistentMessage.hpp"
|
||||
#include "protocol/GetRoom.hpp"
|
||||
#include "protocol/GetRoomSummaries.hpp"
|
||||
#include "protocol/IgnoreStatus.hpp"
|
||||
#include "protocol/KickAvatar.hpp"
|
||||
#include "protocol/LeaveRoom.hpp"
|
||||
#include "protocol/LoginAvatar.hpp"
|
||||
#include "protocol/LogoutAvatar.hpp"
|
||||
#include "protocol/RemoveBan.hpp"
|
||||
#include "protocol/RemoveFriend.hpp"
|
||||
#include "protocol/RemoveIgnore.hpp"
|
||||
#include "protocol/RemoveInvite.hpp"
|
||||
#include "protocol/RemoveModerator.hpp"
|
||||
#include "protocol/SendInstantMessage.hpp"
|
||||
#include "protocol/SendPersistentMessage.hpp"
|
||||
#include "protocol/SendRoomMessage.hpp"
|
||||
#include "protocol/SetApiVersion.hpp"
|
||||
#include "protocol/SetAvatarAttributes.hpp"
|
||||
#include "protocol/UpdatePersistentMessage.hpp"
|
||||
|
||||
#include "easylogging++.h"
|
||||
|
||||
GatewayClient::GatewayClient(UdpConnection* connection, GatewayNode* node)
|
||||
: NodeClient(connection)
|
||||
, node_{node}
|
||||
, avatarService_{node->GetAvatarService()}
|
||||
, roomService_{node->GetRoomService()}
|
||||
, messageService_{node->GetMessageService()} {
|
||||
connection->SetHandler(this);
|
||||
}
|
||||
|
||||
GatewayClient::~GatewayClient() {}
|
||||
|
||||
void GatewayClient::OnIncoming(std::istringstream& istream) {
|
||||
ChatRequestType request_type = ::read<ChatRequestType>(istream);
|
||||
|
||||
switch (request_type) {
|
||||
case ChatRequestType::LOGINAVATAR:
|
||||
HandleIncomingMessage<LoginAvatar>(istream);
|
||||
break;
|
||||
case ChatRequestType::LOGOUTAVATAR:
|
||||
HandleIncomingMessage<LogoutAvatar>(istream);
|
||||
break;
|
||||
case ChatRequestType::CREATEROOM:
|
||||
HandleIncomingMessage<CreateRoom>(istream);
|
||||
break;
|
||||
case ChatRequestType::DESTROYROOM:
|
||||
HandleIncomingMessage<DestroyRoom>(istream);
|
||||
break;
|
||||
case ChatRequestType::SENDINSTANTMESSAGE:
|
||||
HandleIncomingMessage<SendInstantMessage>(istream);
|
||||
break;
|
||||
case ChatRequestType::SENDROOMMESSAGE:
|
||||
HandleIncomingMessage<SendRoomMessage>(istream);
|
||||
break;
|
||||
case ChatRequestType::ADDFRIEND:
|
||||
HandleIncomingMessage<AddFriend>(istream);
|
||||
break;
|
||||
case ChatRequestType::REMOVEFRIEND:
|
||||
HandleIncomingMessage<RemoveFriend>(istream);
|
||||
break;
|
||||
case ChatRequestType::FRIENDSTATUS:
|
||||
HandleIncomingMessage<FriendStatus>(istream);
|
||||
break;
|
||||
case ChatRequestType::ADDIGNORE:
|
||||
HandleIncomingMessage<AddIgnore>(istream);
|
||||
break;
|
||||
case ChatRequestType::REMOVEIGNORE:
|
||||
HandleIncomingMessage<RemoveIgnore>(istream);
|
||||
break;
|
||||
case ChatRequestType::ENTERROOM:
|
||||
HandleIncomingMessage<EnterRoom>(istream);
|
||||
break;
|
||||
case ChatRequestType::LEAVEROOM:
|
||||
HandleIncomingMessage<LeaveRoom>(istream);
|
||||
break;
|
||||
case ChatRequestType::ADDMODERATOR:
|
||||
HandleIncomingMessage<AddModerator>(istream);
|
||||
break;
|
||||
case ChatRequestType::REMOVEMODERATOR:
|
||||
HandleIncomingMessage<RemoveModerator>(istream);
|
||||
break;
|
||||
case ChatRequestType::ADDBAN:
|
||||
HandleIncomingMessage<AddBan>(istream);
|
||||
break;
|
||||
case ChatRequestType::REMOVEBAN:
|
||||
HandleIncomingMessage<RemoveBan>(istream);
|
||||
break;
|
||||
case ChatRequestType::ADDINVITE:
|
||||
HandleIncomingMessage<AddInvite>(istream);
|
||||
break;
|
||||
case ChatRequestType::REMOVEINVITE:
|
||||
HandleIncomingMessage<RemoveInvite>(istream);
|
||||
break;
|
||||
case ChatRequestType::KICKAVATAR:
|
||||
HandleIncomingMessage<KickAvatar>(istream);
|
||||
break;
|
||||
case ChatRequestType::GETROOM:
|
||||
HandleIncomingMessage<GetRoom>(istream);
|
||||
break;
|
||||
case ChatRequestType::GETROOMSUMMARIES:
|
||||
HandleIncomingMessage<GetRoomSummaries>(istream);
|
||||
break;
|
||||
case ChatRequestType::SENDPERSISTENTMESSAGE:
|
||||
HandleIncomingMessage<SendPersistentMessage>(istream);
|
||||
break;
|
||||
case ChatRequestType::GETPERSISTENTHEADERS:
|
||||
HandleIncomingMessage<GetPersistentHeaders>(istream);
|
||||
break;
|
||||
case ChatRequestType::GETPERSISTENTMESSAGE:
|
||||
HandleIncomingMessage<GetPersistentMessage>(istream);
|
||||
break;
|
||||
case ChatRequestType::UPDATEPERSISTENTMESSAGE:
|
||||
HandleIncomingMessage<UpdatePersistentMessage>(istream);
|
||||
break;
|
||||
case ChatRequestType::IGNORESTATUS:
|
||||
HandleIncomingMessage<IgnoreStatus>(istream);
|
||||
break;
|
||||
case ChatRequestType::FAILOVER_RELOGINAVATAR:
|
||||
HandleIncomingMessage<FailoverReLoginAvatar>(istream);
|
||||
break;
|
||||
case ChatRequestType::SETAPIVERSION:
|
||||
HandleIncomingMessage<SetApiVersion>(istream);
|
||||
break;
|
||||
case ChatRequestType::SETAVATARATTRIBUTES:
|
||||
HandleIncomingMessage<SetAvatarAttributes>(istream);
|
||||
break;
|
||||
case ChatRequestType::GETANYAVATAR:
|
||||
HandleIncomingMessage<GetAnyAvatar>(istream);
|
||||
break;
|
||||
default:
|
||||
LOG(INFO) << "Unknown request type received: " << static_cast<uint16_t>(request_type);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void GatewayClient::SendFriendLoginUpdate(
|
||||
const ChatAvatar* srcAvatar, const ChatAvatar* destAvatar) {
|
||||
node_->SendTo(
|
||||
srcAvatar->GetAddress(), MFriendLogin{destAvatar, destAvatar->GetAddress(),
|
||||
srcAvatar->GetAvatarId(), destAvatar->GetStatusMessage()});
|
||||
}
|
||||
|
||||
void GatewayClient::SendFriendLoginUpdates(const ChatAvatar* avatar) {
|
||||
auto as = node_->GetAvatarService();
|
||||
auto& onlineAvatars = as->GetOnlineAvatars();
|
||||
for (auto onlineAvatar : onlineAvatars) {
|
||||
if (onlineAvatar->IsFriend(avatar)) {
|
||||
SendFriendLoginUpdate(onlineAvatar, avatar);
|
||||
}
|
||||
}
|
||||
|
||||
for (auto& contact : avatar->GetFriendList()) {
|
||||
if (contact.frnd->IsOnline()) {
|
||||
Send(MFriendLogin{contact.frnd, contact.frnd->GetAddress(), avatar->GetAvatarId(),
|
||||
contact.frnd->GetStatusMessage()});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GatewayClient::SendFriendLogoutUpdates(const ChatAvatar* avatar) {
|
||||
auto& onlineAvatars = avatarService_->GetOnlineAvatars();
|
||||
for (auto onlineAvatar : onlineAvatars) {
|
||||
if (onlineAvatar->IsFriend(avatar)) {
|
||||
node_->SendTo(onlineAvatar->GetAddress(),
|
||||
MFriendLogout{avatar, avatar->GetAddress(), onlineAvatar->GetAvatarId()});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GatewayClient::SendDestroyRoomUpdate(
|
||||
const ChatAvatar* srcAvatar, uint32_t roomId, std::vector<std::u16string> targets) {
|
||||
for (auto& address : targets) {
|
||||
node_->SendTo(address, MDestroyRoom{srcAvatar, roomId});
|
||||
}
|
||||
}
|
||||
|
||||
void GatewayClient::SendInstantMessageUpdate(const ChatAvatar* srcAvatar,
|
||||
const ChatAvatar* destAvatar, const std::u16string& message, const std::u16string& oob) {
|
||||
node_->SendTo(destAvatar->GetAddress(),
|
||||
MInstantMessage{srcAvatar, destAvatar->GetAvatarId(), message, oob});
|
||||
}
|
||||
|
||||
void GatewayClient::SendRoomMessageUpdate(const ChatAvatar* srcAvatar, const ChatRoom* room,
|
||||
uint32_t messageId, const std::u16string& message, const std::u16string& oob) {
|
||||
auto connectedAddresses = room->GetConnectedAddresses();
|
||||
for (auto& address : connectedAddresses) {
|
||||
node_->SendTo(address, MRoomMessage{srcAvatar, room->GetRoomId(), room->GetAvatarIds(),
|
||||
message, oob, messageId});
|
||||
}
|
||||
}
|
||||
|
||||
void GatewayClient::SendEnterRoomUpdate(const ChatAvatar* srcAvatar, const ChatRoom* room) {
|
||||
for (const auto& address : room->GetConnectedAddresses()) {
|
||||
node_->SendTo(address, MEnterRoom{srcAvatar, room->GetRoomId()});
|
||||
}
|
||||
}
|
||||
|
||||
void GatewayClient::SendLeaveRoomUpdate(
|
||||
const std::vector<std::u16string>& addresses, uint32_t srcAvatarId, uint32_t roomId) {
|
||||
for (const auto& address : addresses) {
|
||||
node_->SendTo(address, MLeaveRoom{srcAvatarId, roomId});
|
||||
}
|
||||
}
|
||||
|
||||
void GatewayClient::SendPersistentMessageUpdate(
|
||||
const ChatAvatar* destAvatar, const PersistentHeader& header) {
|
||||
if (destAvatar) {
|
||||
node_->SendTo(
|
||||
destAvatar->GetAddress(), MPersistentMessage{destAvatar->GetAvatarId(), header});
|
||||
}
|
||||
}
|
||||
|
||||
void GatewayClient::SendKickAvatarUpdate(const std::vector<std::u16string>& addresses,
|
||||
const ChatAvatar* srcAvatar, const ChatAvatar* destAvatar, const ChatRoom* room) {
|
||||
for (const auto& address : addresses) {
|
||||
node_->SendTo(address,
|
||||
MKickAvatar{srcAvatar, destAvatar, room->GetRoomName(), room->GetRoomAddress()});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "ChatEnums.hpp"
|
||||
#include "NodeClient.hpp"
|
||||
#include "SQLite3.hpp"
|
||||
#include "easylogging++.h"
|
||||
|
||||
class ChatAvatar;
|
||||
class ChatAvatarService;
|
||||
class ChatRoom;
|
||||
class ChatRoomService;
|
||||
class GatewayNode;
|
||||
class PersistentMessageService;
|
||||
class UdpConnection;
|
||||
|
||||
struct PersistentHeader;
|
||||
|
||||
struct ReqSetAvatarAttributes;
|
||||
struct ReqGetAnyAvatar;
|
||||
|
||||
class GatewayClient : public NodeClient {
|
||||
public:
|
||||
GatewayClient(UdpConnection* connection, GatewayNode* node);
|
||||
virtual ~GatewayClient();
|
||||
|
||||
GatewayNode* GetNode() { return node_; }
|
||||
|
||||
void SendFriendLoginUpdate(const ChatAvatar* srcAvatar, const ChatAvatar* destAvatar);
|
||||
void SendFriendLoginUpdates(const ChatAvatar* avatar);
|
||||
void SendFriendLogoutUpdates(const ChatAvatar* avatar);
|
||||
void SendDestroyRoomUpdate(const ChatAvatar* srcAvatar, uint32_t roomId, std::vector<std::u16string> targets);
|
||||
void SendInstantMessageUpdate(const ChatAvatar* srcAvatar, const ChatAvatar* destAvatar, const std::u16string& message, const std::u16string& oob);
|
||||
void SendRoomMessageUpdate(const ChatAvatar* srcAvatar, const ChatRoom* room, uint32_t messageId, const std::u16string& message, const std::u16string& oob);
|
||||
void SendEnterRoomUpdate(const ChatAvatar* srcAvatar, const ChatRoom* room);
|
||||
void SendLeaveRoomUpdate(const std::vector<std::u16string>& addresses, uint32_t srcAvatarId, uint32_t roomId);
|
||||
void SendPersistentMessageUpdate(const ChatAvatar* destAvatar, const PersistentHeader& header);
|
||||
void SendKickAvatarUpdate(const std::vector<std::u16string>& addresses, const ChatAvatar* srcAvatar, const ChatAvatar* destAvatar, const ChatRoom* room);
|
||||
|
||||
private:
|
||||
void OnIncoming(std::istringstream& istream) override;
|
||||
|
||||
template<typename HandlerT, typename StreamT>
|
||||
void HandleIncomingMessage(StreamT& istream) {
|
||||
typedef typename HandlerT::RequestType RequestT;
|
||||
typedef typename HandlerT::ResponseType ResponseT;
|
||||
|
||||
RequestT request;
|
||||
read(istream, request);
|
||||
ResponseT response(request.track);
|
||||
|
||||
try {
|
||||
HandlerT(this, request, response);
|
||||
} catch (const ChatResultException& e) {
|
||||
response.result = e.code;
|
||||
LOG(ERROR) << "ChatAPI Error: [" << ToString(e.code) << "] " << e.message;
|
||||
} catch (const SQLite3Exception& e) {
|
||||
response.result = ChatResultCode::DATABASE;
|
||||
LOG(ERROR) << "Database Error: [" << e.code << "] " << e.message;
|
||||
}
|
||||
|
||||
Send(response);
|
||||
}
|
||||
|
||||
GatewayNode* node_;
|
||||
ChatAvatarService* avatarService_;
|
||||
ChatRoomService* roomService_;
|
||||
PersistentMessageService* messageService_;
|
||||
};
|
||||
@@ -0,0 +1,39 @@
|
||||
|
||||
#include "GatewayNode.hpp"
|
||||
|
||||
#include "ChatAvatarService.hpp"
|
||||
#include "ChatRoomService.hpp"
|
||||
#include "PersistentMessageService.hpp"
|
||||
#include "StationChatConfig.hpp"
|
||||
|
||||
#include <sqlite3.h>
|
||||
|
||||
GatewayNode::GatewayNode(StationChatConfig& config)
|
||||
: Node(this, config.gatewayAddress, config.gatewayPort)
|
||||
, config_{config} {
|
||||
if (sqlite3_open(config.chatDatabasePath.c_str(), &db_) != SQLITE_OK) {
|
||||
throw std::runtime_error("Can't open database: " + std::string{sqlite3_errmsg(db_)});
|
||||
}
|
||||
|
||||
avatarService_ = std::make_unique<ChatAvatarService>(db_);
|
||||
roomService_ = std::make_unique<ChatRoomService>(avatarService_.get(), db_);
|
||||
messageService_ = std::make_unique<PersistentMessageService>(db_);
|
||||
}
|
||||
|
||||
GatewayNode::~GatewayNode() { sqlite3_close(db_); }
|
||||
|
||||
ChatAvatarService* GatewayNode::GetAvatarService() { return avatarService_.get(); }
|
||||
|
||||
ChatRoomService* GatewayNode::GetRoomService() { return roomService_.get(); }
|
||||
|
||||
PersistentMessageService* GatewayNode::GetMessageService() {
|
||||
return messageService_.get();
|
||||
}
|
||||
|
||||
StationChatConfig& GatewayNode::GetConfig() { return config_; }
|
||||
|
||||
void GatewayNode::RegisterClientAddress(const std::u16string & address, GatewayClient * client) {
|
||||
clientAddressMap_[address] = client;
|
||||
}
|
||||
|
||||
void GatewayNode::OnTick() {}
|
||||
@@ -0,0 +1,45 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Node.hpp"
|
||||
#include "GatewayClient.hpp"
|
||||
|
||||
#include <map>
|
||||
#include <memory>
|
||||
|
||||
class ChatAvatarService;
|
||||
class ChatRoomService;
|
||||
class PersistentMessageService;
|
||||
struct StationChatConfig;
|
||||
struct sqlite3;
|
||||
|
||||
class GatewayNode : public Node<GatewayNode, GatewayClient> {
|
||||
public:
|
||||
explicit GatewayNode(StationChatConfig& config);
|
||||
~GatewayNode();
|
||||
|
||||
ChatAvatarService* GetAvatarService();
|
||||
ChatRoomService* GetRoomService();
|
||||
PersistentMessageService* GetMessageService();
|
||||
StationChatConfig& GetConfig();
|
||||
|
||||
void RegisterClientAddress(const std::u16string& address, GatewayClient* client);
|
||||
|
||||
template<typename MessageT>
|
||||
void SendTo(const std::u16string& address, const MessageT& message) {
|
||||
auto find_iter = clientAddressMap_.find(address);
|
||||
if (find_iter != std::end(clientAddressMap_)) {
|
||||
find_iter->second->Send(message);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
void OnTick() override;
|
||||
|
||||
std::unique_ptr<ChatAvatarService> avatarService_;
|
||||
std::unique_ptr<ChatRoomService> roomService_;
|
||||
std::unique_ptr<PersistentMessageService> messageService_;
|
||||
std::map<std::u16string, GatewayClient*> clientAddressMap_;
|
||||
StationChatConfig& config_;
|
||||
sqlite3* db_;
|
||||
};
|
||||
+298
@@ -0,0 +1,298 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "ChatAvatar.hpp"
|
||||
#include "PersistentMessage.hpp"
|
||||
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
|
||||
enum class ChatMessageType : uint16_t {
|
||||
// ChatAvatar message types
|
||||
INSTANTMESSAGE = 0, // 0
|
||||
ROOMMESSAGE,
|
||||
BROADCASTMESSAGE,
|
||||
FRIENDLOGIN,
|
||||
FRIENDLOGOUT,
|
||||
KICKROOM, // 5
|
||||
|
||||
// ChatRoom message types
|
||||
ADDMODERATORROOM,
|
||||
REMOVEMODERATORROOM,
|
||||
REMOVEMODERATORAVATAR,
|
||||
ADDBANROOM,
|
||||
REMOVEBANROOM, // 10
|
||||
REMOVEBANAVATAR,
|
||||
ADDINVITEROOM,
|
||||
ADDINVITEAVATAR,
|
||||
REMOVEINVITEROOM,
|
||||
REMOVEINVITEAVATAR, // 15
|
||||
ENTERROOM,
|
||||
LEAVEROOM,
|
||||
DESTROYROOM,
|
||||
SETROOMPARAMS,
|
||||
PERSISTENTMESSAGE, // 20
|
||||
FORCEDLOGOUT,
|
||||
UNREGISTERROOMREADY,
|
||||
KICKAVATAR,
|
||||
ADDMODERATORAVATAR,
|
||||
ADDBANAVATAR, // 25
|
||||
ADDADMIN,
|
||||
REMOVEADMIN,
|
||||
FRIENDCONFIRMREQUEST,
|
||||
FRIENDCONFIRMRESPONSE,
|
||||
CHANGEROOMOWNER, // 30
|
||||
FORCEROOMFAILOVER,
|
||||
ADDTEMPORARYMODERATORROOM,
|
||||
ADDTEMPORARYMODERATORAVATAR,
|
||||
REMOVETEMPORARYMODERATORROOM,
|
||||
REMOVETEMPORARYMODERATORAVATAR, // 35
|
||||
GRANTVOICEROOM,
|
||||
GRANTVOICEAVATAR,
|
||||
REVOKEVOICEROOM,
|
||||
REVOKEVOICEAVATAR,
|
||||
SNOOP, // 40
|
||||
UIDLIST,
|
||||
REQUESTROOMENTRY,
|
||||
DELAYEDROOMENTRY,
|
||||
DENIEDROOMENTRY,
|
||||
FRIENDSTATUS, // 45
|
||||
FRIENDCONFIRMRECIPROCATE_REQUEST,
|
||||
FRIENDCONFIRMRECIPROCATE_RESPONSE,
|
||||
FILTERMESSAGE,
|
||||
FAILOVER_AVATAR_LIST,
|
||||
NOTIFY_FRIENDS_LIST_CHANGE, // 50
|
||||
NOTIFY_FRIEND_IS_REMOVED
|
||||
};
|
||||
|
||||
/** Begin INSTANTMESSAGE */
|
||||
|
||||
struct MInstantMessage {
|
||||
MInstantMessage(const ChatAvatar* srcAvatar_, uint32_t destAvatarId_,
|
||||
const std::u16string& message_, const std::u16string& oob_)
|
||||
: srcAvatar{srcAvatar_}
|
||||
, destAvatarId{destAvatarId_}
|
||||
, message{message_}
|
||||
, oob{oob_} {}
|
||||
|
||||
const ChatMessageType type = ChatMessageType::INSTANTMESSAGE;
|
||||
const uint32_t track = 0;
|
||||
const ChatAvatar* srcAvatar;
|
||||
uint32_t destAvatarId;
|
||||
std::u16string message;
|
||||
std::u16string oob;
|
||||
};
|
||||
|
||||
template <typename StreamT>
|
||||
void write(StreamT& ar, const MInstantMessage& data) {
|
||||
write(ar, data.type);
|
||||
write(ar, data.track);
|
||||
write(ar, data.srcAvatar);
|
||||
write(ar, data.destAvatarId);
|
||||
write(ar, data.message);
|
||||
write(ar, data.oob);
|
||||
}
|
||||
|
||||
/** Begin ROOMMESSAGE */
|
||||
|
||||
struct MRoomMessage {
|
||||
MRoomMessage(const ChatAvatar* srcAvatar_, uint32_t roomId_, std::vector<uint32_t> destList_,
|
||||
const std::u16string& message_, const std::u16string& oob_, uint32_t messageId_)
|
||||
: srcAvatar{srcAvatar_}
|
||||
, roomId{roomId_}
|
||||
, destList{destList_}
|
||||
, message{message_}
|
||||
, oob{oob_}
|
||||
, messageId{messageId_} {}
|
||||
|
||||
const ChatMessageType type = ChatMessageType::ROOMMESSAGE;
|
||||
const uint32_t track = 0;
|
||||
const ChatAvatar* srcAvatar;
|
||||
uint32_t roomId;
|
||||
std::vector<uint32_t> destList; // list of destination avatars to see the message
|
||||
std::u16string message;
|
||||
std::u16string oob;
|
||||
uint32_t messageId = 0;
|
||||
};
|
||||
|
||||
template <typename StreamT>
|
||||
void write(StreamT& ar, const MRoomMessage& data) {
|
||||
write(ar, data.type);
|
||||
write(ar, data.track);
|
||||
write(ar, data.srcAvatar);
|
||||
write(ar, data.roomId);
|
||||
|
||||
write(ar, static_cast<uint32_t>(data.destList.size()));
|
||||
for (auto destAvatarId : data.destList) {
|
||||
write(ar, destAvatarId);
|
||||
}
|
||||
|
||||
write(ar, data.message);
|
||||
write(ar, data.oob);
|
||||
write(ar, data.messageId);
|
||||
}
|
||||
|
||||
/** Begin FRIENDLOGIN */
|
||||
|
||||
struct MFriendLogin {
|
||||
MFriendLogin(const ChatAvatar* avatar_, const std::u16string& friendAddress_,
|
||||
uint32_t destAvatarId_, const std::u16string& friendStatus_)
|
||||
: avatar{avatar_}
|
||||
, friendAddress{friendAddress_}
|
||||
, destAvatarId{destAvatarId_}
|
||||
, friendStatus{friendStatus_} {}
|
||||
|
||||
const ChatMessageType type = ChatMessageType::FRIENDLOGIN;
|
||||
const uint32_t track = 0;
|
||||
const ChatAvatar* avatar;
|
||||
std::u16string friendAddress;
|
||||
uint32_t destAvatarId;
|
||||
std::u16string friendStatus;
|
||||
};
|
||||
|
||||
template <typename StreamT>
|
||||
void write(StreamT& ar, const MFriendLogin& data) {
|
||||
write(ar, data.type);
|
||||
write(ar, data.track);
|
||||
write(ar, data.avatar);
|
||||
write(ar, data.friendAddress);
|
||||
write(ar, data.destAvatarId);
|
||||
write(ar, data.friendStatus);
|
||||
}
|
||||
|
||||
/** Begin FRIENDLOGOUT */
|
||||
|
||||
struct MFriendLogout {
|
||||
MFriendLogout(
|
||||
const ChatAvatar* avatar_, const std::u16string& friendAddress_, uint32_t destAvatarId_)
|
||||
: avatar{avatar_}
|
||||
, friendAddress{friendAddress_}
|
||||
, destAvatarId{destAvatarId_} {}
|
||||
|
||||
const ChatMessageType type = ChatMessageType::FRIENDLOGOUT;
|
||||
const uint32_t track = 0;
|
||||
const ChatAvatar* avatar;
|
||||
uint32_t destAvatarId;
|
||||
std::u16string friendAddress;
|
||||
};
|
||||
|
||||
template <typename StreamT>
|
||||
void write(StreamT& ar, const MFriendLogout& data) {
|
||||
write(ar, data.type);
|
||||
write(ar, data.track);
|
||||
write(ar, data.avatar);
|
||||
write(ar, data.friendAddress);
|
||||
write(ar, data.destAvatarId);
|
||||
}
|
||||
|
||||
/** Begin ENTERROOM */
|
||||
|
||||
struct MEnterRoom {
|
||||
MEnterRoom(const ChatAvatar* srcAvatar_, uint32_t roomId_)
|
||||
: srcAvatar{srcAvatar_}
|
||||
, roomId{roomId_} {}
|
||||
|
||||
const ChatMessageType type = ChatMessageType::ENTERROOM;
|
||||
const uint32_t track = 0;
|
||||
const ChatAvatar* srcAvatar;
|
||||
uint32_t roomId;
|
||||
};
|
||||
|
||||
template <typename StreamT>
|
||||
void write(StreamT& ar, const MEnterRoom& data) {
|
||||
write(ar, data.type);
|
||||
write(ar, data.track);
|
||||
write(ar, data.srcAvatar);
|
||||
write(ar, data.roomId);
|
||||
}
|
||||
|
||||
/** Begin LEAVEROOM */
|
||||
|
||||
struct MLeaveRoom {
|
||||
MLeaveRoom(uint32_t avatarId_, uint32_t roomId_)
|
||||
: avatarId{avatarId_}
|
||||
, roomId{roomId_} {}
|
||||
|
||||
const ChatMessageType type = ChatMessageType::LEAVEROOM;
|
||||
const uint32_t track = 0;
|
||||
uint32_t avatarId;
|
||||
uint32_t roomId;
|
||||
};
|
||||
|
||||
template <typename StreamT>
|
||||
void write(StreamT& ar, const MLeaveRoom& data) {
|
||||
write(ar, data.type);
|
||||
write(ar, data.track);
|
||||
write(ar, data.avatarId);
|
||||
write(ar, data.roomId);
|
||||
}
|
||||
|
||||
/** Begin DESTROYROOM */
|
||||
|
||||
struct MDestroyRoom {
|
||||
MDestroyRoom(const ChatAvatar* srcAvatar_, uint32_t roomId_)
|
||||
: srcAvatar{srcAvatar_}
|
||||
, roomId{roomId_} {}
|
||||
|
||||
const ChatMessageType type = ChatMessageType::DESTROYROOM;
|
||||
const uint32_t track = 0;
|
||||
const ChatAvatar* srcAvatar;
|
||||
uint32_t roomId;
|
||||
};
|
||||
|
||||
template <typename StreamT>
|
||||
void write(StreamT& ar, const MDestroyRoom& data) {
|
||||
write(ar, data.type);
|
||||
write(ar, data.track);
|
||||
write(ar, data.srcAvatar);
|
||||
write(ar, data.roomId);
|
||||
}
|
||||
|
||||
/** Begin PERSISTENTMESSAGE */
|
||||
|
||||
struct MPersistentMessage {
|
||||
MPersistentMessage(uint32_t destAvatarId_, PersistentHeader header_)
|
||||
: destAvatarId{destAvatarId_}
|
||||
, header{header_} {}
|
||||
|
||||
const ChatMessageType type = ChatMessageType::PERSISTENTMESSAGE;
|
||||
const uint32_t track = 0;
|
||||
uint32_t destAvatarId;
|
||||
PersistentHeader header;
|
||||
};
|
||||
|
||||
template <typename StreamT>
|
||||
void write(StreamT& ar, const MPersistentMessage& data) {
|
||||
write(ar, data.type);
|
||||
write(ar, data.track);
|
||||
write(ar, data.destAvatarId);
|
||||
write(ar, data.header);
|
||||
}
|
||||
|
||||
/** Begin KICKAVATAR */
|
||||
|
||||
struct MKickAvatar {
|
||||
MKickAvatar(const ChatAvatar* srcAvatar_, const ChatAvatar* destAvatar_,
|
||||
const std::u16string& roomName_, const std::u16string& roomAddress_)
|
||||
: srcAvatar{srcAvatar_}
|
||||
, destAvatar{destAvatar_}
|
||||
, roomName{roomName_}
|
||||
, roomAddress{roomAddress_} {}
|
||||
|
||||
const ChatMessageType type = ChatMessageType::KICKAVATAR;
|
||||
const uint32_t track = 0;
|
||||
const ChatAvatar* srcAvatar;
|
||||
const ChatAvatar* destAvatar;
|
||||
std::u16string roomName;
|
||||
std::u16string roomAddress;
|
||||
};
|
||||
|
||||
template <typename StreamT>
|
||||
void write(StreamT& ar, const MKickAvatar& data) {
|
||||
write(ar, data.type);
|
||||
write(ar, data.track);
|
||||
write(ar, data.srcAvatar);
|
||||
write(ar, data.destAvatar);
|
||||
write(ar, data.roomName);
|
||||
write(ar, data.roomAddress);
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "UdpLibrary.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
template <typename NodeT, typename ClientT>
|
||||
class Node : public UdpManagerHandler {
|
||||
public:
|
||||
explicit Node(NodeT* node, const std::string& listenAddress, uint16_t listenPort)
|
||||
: node_{node} {
|
||||
|
||||
UdpManager::Params params;
|
||||
params.handler = this;
|
||||
params.port = listenPort;
|
||||
|
||||
udpManager_ = new UdpManager(¶ms);
|
||||
}
|
||||
|
||||
virtual ~Node() { udpManager_->Release(); }
|
||||
|
||||
void Tick() {
|
||||
udpManager_->GiveTime();
|
||||
|
||||
auto remove_iter
|
||||
= std::remove_if(std::begin(clients_), std::end(clients_), [](auto& client) {
|
||||
return client->GetConnection()->GetStatus() == UdpConnection::cStatusDisconnected;
|
||||
});
|
||||
|
||||
if (remove_iter != std::end(clients_))
|
||||
clients_.erase(remove_iter);
|
||||
|
||||
OnTick();
|
||||
}
|
||||
|
||||
private:
|
||||
virtual void OnTick() = 0;
|
||||
|
||||
void OnConnectRequest(UdpConnection* connection) override {
|
||||
AddClient(std::make_unique<ClientT>(connection, node_));
|
||||
}
|
||||
|
||||
void AddClient(std::unique_ptr<ClientT> client) { clients_.push_back(std::move(client)); }
|
||||
|
||||
std::vector<std::unique_ptr<ClientT>> clients_;
|
||||
NodeT* node_;
|
||||
UdpManager* udpManager_;
|
||||
};
|
||||
@@ -0,0 +1,30 @@
|
||||
|
||||
#include "NodeClient.hpp"
|
||||
#include "StreamUtils.hpp"
|
||||
|
||||
NodeClient::NodeClient(UdpConnection* connection)
|
||||
: connection_{connection}
|
||||
, ostream_{std::stringstream::out | std::stringstream::binary}
|
||||
, istream_{std::stringstream::in | std::stringstream::binary} {
|
||||
connection_->AddRef();
|
||||
}
|
||||
|
||||
NodeClient::~NodeClient() {
|
||||
connection_->SetHandler(nullptr);
|
||||
connection_->Disconnect();
|
||||
connection_->Release();
|
||||
}
|
||||
|
||||
void NodeClient::Send(const char* data, uint32_t length) {
|
||||
logNetworkMessage(
|
||||
connection_, "Message To ->", reinterpret_cast<const unsigned char*>(data), length);
|
||||
connection_->Send(cUdpChannelReliable1, data, length);
|
||||
}
|
||||
|
||||
void NodeClient::OnRoutePacket(UdpConnection* connection, const uchar* data, int length) {
|
||||
logNetworkMessage(connection, "Message From <-", data, length);
|
||||
|
||||
istream_.clear();
|
||||
istream_.str({reinterpret_cast<const char*>(data), static_cast<uint32_t>(length)});
|
||||
OnIncoming(istream_);
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "UdpLibrary.hpp"
|
||||
|
||||
#include <sstream>
|
||||
|
||||
class NodeClient : public UdpConnectionHandler {
|
||||
public:
|
||||
explicit NodeClient(UdpConnection* connection);
|
||||
|
||||
virtual ~NodeClient();
|
||||
|
||||
template <typename T>
|
||||
void Send(const T& message) {
|
||||
ostream_.clear();
|
||||
ostream_.str("");
|
||||
write(ostream_, message);
|
||||
auto data = ostream_.str();
|
||||
Send(data.c_str(), data.length());
|
||||
}
|
||||
|
||||
UdpConnection* GetConnection() { return connection_; }
|
||||
|
||||
private:
|
||||
void Send(const char* data, uint32_t length);
|
||||
|
||||
virtual void OnIncoming(std::istringstream& istream) = 0;
|
||||
|
||||
void OnRoutePacket(UdpConnection* connection, const uchar* data, int length) override;
|
||||
|
||||
std::ostringstream ostream_;
|
||||
std::istringstream istream_;
|
||||
UdpConnection* connection_;
|
||||
};
|
||||
@@ -0,0 +1,51 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
|
||||
enum class PersistentState : uint32_t {
|
||||
NEW = 1,
|
||||
UNREAD,
|
||||
READ,
|
||||
TRASH,
|
||||
DELETED
|
||||
};
|
||||
|
||||
struct PersistentHeader {
|
||||
uint32_t messageId = 0;
|
||||
uint32_t avatarId;
|
||||
std::u16string fromName;
|
||||
std::u16string fromAddress;
|
||||
std::u16string subject;
|
||||
uint32_t sentTime = 0;
|
||||
PersistentState status = PersistentState::NEW;
|
||||
std::u16string folder = u"";
|
||||
std::u16string category = u"";
|
||||
};
|
||||
|
||||
struct PersistentMessage {
|
||||
PersistentHeader header;
|
||||
std::u16string message;
|
||||
std::u16string oob;
|
||||
};
|
||||
|
||||
|
||||
template <typename StreamT>
|
||||
void write(StreamT& ar, const PersistentHeader& data) {
|
||||
write(ar, data.messageId);
|
||||
write(ar, data.avatarId);
|
||||
write(ar, data.fromName);
|
||||
write(ar, data.fromAddress);
|
||||
write(ar, data.subject);
|
||||
write(ar, data.sentTime);
|
||||
write(ar, data.status);
|
||||
}
|
||||
|
||||
|
||||
template <typename StreamT>
|
||||
void write(StreamT& ar, const PersistentMessage& data) {
|
||||
write(ar, data.header);
|
||||
write(ar, data.message);
|
||||
write(ar, data.oob);
|
||||
}
|
||||
@@ -0,0 +1,210 @@
|
||||
#include "PersistentMessageService.hpp"
|
||||
|
||||
#include "SQLite3.hpp"
|
||||
#include "StringUtils.hpp"
|
||||
|
||||
|
||||
PersistentMessageService::PersistentMessageService(sqlite3* db)
|
||||
: db_{db} {}
|
||||
|
||||
PersistentMessageService::~PersistentMessageService() {}
|
||||
|
||||
void PersistentMessageService::StoreMessage(PersistentMessage& message) {
|
||||
sqlite3_stmt* stmt;
|
||||
|
||||
char sql[] = "INSERT INTO persistent_message (avatar_id, from_name, from_address, subject, "
|
||||
"sent_time, status, "
|
||||
"folder, category, message, oob) VALUES (@avatar_id, @from_name, @from_address, "
|
||||
"@subject, @sent_time, @status, @folder, @category, @message, @oob)";
|
||||
|
||||
auto result = sqlite3_prepare_v2(db_, sql, -1, &stmt, 0);
|
||||
if (result != SQLITE_OK) {
|
||||
throw SQLite3Exception{result, sqlite3_errmsg(db_)};
|
||||
}
|
||||
|
||||
int avatarIdIdx = sqlite3_bind_parameter_index(stmt, "@avatar_id");
|
||||
int fromNameIdx = sqlite3_bind_parameter_index(stmt, "@from_name");
|
||||
int fromAddressIdx = sqlite3_bind_parameter_index(stmt, "@from_address");
|
||||
int subjectIdx = sqlite3_bind_parameter_index(stmt, "@subject");
|
||||
int sentTimeIdx = sqlite3_bind_parameter_index(stmt, "@sent_time");
|
||||
int statusIdx = sqlite3_bind_parameter_index(stmt, "@status");
|
||||
int folderIdx = sqlite3_bind_parameter_index(stmt, "@folder");
|
||||
int categoryIdx = sqlite3_bind_parameter_index(stmt, "@category");
|
||||
int messageIdx = sqlite3_bind_parameter_index(stmt, "@message");
|
||||
int oobIdx = sqlite3_bind_parameter_index(stmt, "@oob");
|
||||
|
||||
sqlite3_bind_int(stmt, avatarIdIdx, message.header.avatarId);
|
||||
|
||||
std::string fromName = FromWideString(message.header.fromName);
|
||||
sqlite3_bind_text(stmt, fromNameIdx, fromName.c_str(), -1, 0);
|
||||
|
||||
std::string fromAddress = FromWideString(message.header.fromAddress);
|
||||
sqlite3_bind_text(stmt, fromAddressIdx, fromAddress.c_str(), -1, 0);
|
||||
|
||||
std::string subject = FromWideString(message.header.subject);
|
||||
sqlite3_bind_text(stmt, subjectIdx, subject.c_str(), -1, 0);
|
||||
|
||||
sqlite3_bind_int(stmt, sentTimeIdx, message.header.sentTime);
|
||||
sqlite3_bind_int(stmt, statusIdx, static_cast<uint32_t>(message.header.status));
|
||||
|
||||
std::string folder = FromWideString(message.header.folder);
|
||||
sqlite3_bind_text(stmt, folderIdx, folder.c_str(), -1, 0);
|
||||
|
||||
std::string category = FromWideString(message.header.category);
|
||||
sqlite3_bind_text(stmt, categoryIdx, category.c_str(), -1, 0);
|
||||
|
||||
std::string msg = FromWideString(message.message);
|
||||
sqlite3_bind_text(stmt, messageIdx, msg.c_str(), -1, 0);
|
||||
|
||||
sqlite3_bind_blob(stmt, oobIdx, reinterpret_cast<const uint8_t*>(message.oob.data()), message.oob.size() * 2, SQLITE_STATIC);
|
||||
|
||||
result = sqlite3_step(stmt);
|
||||
if (result != SQLITE_DONE) {
|
||||
throw SQLite3Exception{result, sqlite3_errmsg(db_)};
|
||||
}
|
||||
|
||||
message.header.messageId = static_cast<uint32_t>(sqlite3_last_insert_rowid(db_));
|
||||
}
|
||||
|
||||
std::vector<PersistentHeader> PersistentMessageService::GetMessageHeaders(uint32_t avatarId) {
|
||||
std::vector<PersistentHeader> headers;
|
||||
sqlite3_stmt* stmt;
|
||||
|
||||
char sql[] = "SELECT id, avatar_id, from_name, from_address, subject, sent_time, status, "
|
||||
"folder, category, message, oob FROM persistent_message WHERE avatar_id = "
|
||||
"@avatar_id AND status IN (1, 2, 3)";
|
||||
|
||||
auto result = sqlite3_prepare_v2(db_, sql, -1, &stmt, 0);
|
||||
if (result != SQLITE_OK) {
|
||||
throw SQLite3Exception{result, sqlite3_errmsg(db_)};
|
||||
}
|
||||
|
||||
int avatarIdIdx = sqlite3_bind_parameter_index(stmt, "@avatar_id");
|
||||
|
||||
sqlite3_bind_int(stmt, avatarIdIdx, avatarId);
|
||||
|
||||
while (sqlite3_step(stmt) == SQLITE_ROW) {
|
||||
PersistentHeader header;
|
||||
|
||||
header.messageId = sqlite3_column_int(stmt, 0);
|
||||
header.avatarId = sqlite3_column_int(stmt, 1);
|
||||
|
||||
auto tmp = std::string(reinterpret_cast<const char*>(sqlite3_column_text(stmt, 2)));
|
||||
header.fromName = std::u16string(std::begin(tmp), std::end(tmp));
|
||||
|
||||
tmp = std::string(reinterpret_cast<const char*>(sqlite3_column_text(stmt, 3)));
|
||||
header.fromAddress = std::u16string(std::begin(tmp), std::end(tmp));
|
||||
|
||||
tmp = std::string(reinterpret_cast<const char*>(sqlite3_column_text(stmt, 4)));
|
||||
header.subject = std::u16string(std::begin(tmp), std::end(tmp));
|
||||
|
||||
header.sentTime = sqlite3_column_int(stmt, 5);
|
||||
header.status = static_cast<PersistentState>(sqlite3_column_int(stmt, 6));
|
||||
|
||||
tmp = std::string(reinterpret_cast<const char*>(sqlite3_column_text(stmt, 7)));
|
||||
header.folder = std::u16string(std::begin(tmp), std::end(tmp));
|
||||
|
||||
tmp = std::string(reinterpret_cast<const char*>(sqlite3_column_text(stmt, 8)));
|
||||
header.category = std::u16string(std::begin(tmp), std::end(tmp));
|
||||
|
||||
headers.push_back(std::move(header));
|
||||
}
|
||||
|
||||
return headers;
|
||||
}
|
||||
|
||||
PersistentMessage PersistentMessageService::GetPersistentMessage(
|
||||
uint32_t avatarId, uint32_t messageId) {
|
||||
sqlite3_stmt* stmt;
|
||||
|
||||
char sql[] = "SELECT id, avatar_id, from_name, from_address, subject, sent_time, status, "
|
||||
"folder, category, message, oob FROM persistent_message WHERE id = @message_id "
|
||||
"AND avatar_id = @avatar_id";
|
||||
|
||||
auto result = sqlite3_prepare_v2(db_, sql, -1, &stmt, 0);
|
||||
if (result != SQLITE_OK) {
|
||||
throw SQLite3Exception{result, sqlite3_errmsg(db_)};
|
||||
}
|
||||
|
||||
int messageIdIdx = sqlite3_bind_parameter_index(stmt, "@message_id");
|
||||
int avatarIdIdx = sqlite3_bind_parameter_index(stmt, "@avatar_id");
|
||||
|
||||
sqlite3_bind_int(stmt, messageIdIdx, messageId);
|
||||
sqlite3_bind_int(stmt, avatarIdIdx, avatarId);
|
||||
|
||||
if (sqlite3_step(stmt) != SQLITE_ROW) {
|
||||
throw ChatResultException{ChatResultCode::PMSGNOTFOUND};
|
||||
}
|
||||
|
||||
std::string tmp;
|
||||
|
||||
PersistentMessage message;
|
||||
message.header.messageId = messageId;
|
||||
message.header.avatarId = avatarId;
|
||||
|
||||
tmp = std::string(reinterpret_cast<const char*>(sqlite3_column_text(stmt, 2)));
|
||||
message.header.fromName = std::u16string(std::begin(tmp), std::end(tmp));
|
||||
|
||||
tmp = std::string(reinterpret_cast<const char*>(sqlite3_column_text(stmt, 3)));
|
||||
message.header.fromAddress = std::u16string(std::begin(tmp), std::end(tmp));
|
||||
|
||||
tmp = std::string(reinterpret_cast<const char*>(sqlite3_column_text(stmt, 4)));
|
||||
message.header.subject = std::u16string(std::begin(tmp), std::end(tmp));
|
||||
|
||||
message.header.sentTime = sqlite3_column_int(stmt, 5);
|
||||
message.header.status = static_cast<PersistentState>(sqlite3_column_int(stmt, 6));
|
||||
|
||||
tmp = std::string(reinterpret_cast<const char*>(sqlite3_column_text(stmt, 7)));
|
||||
message.header.folder = std::u16string(std::begin(tmp), std::end(tmp));
|
||||
|
||||
tmp = std::string(reinterpret_cast<const char*>(sqlite3_column_text(stmt, 8)));
|
||||
message.header.category = std::u16string(std::begin(tmp), std::end(tmp));
|
||||
|
||||
tmp = std::string(reinterpret_cast<const char*>(sqlite3_column_text(stmt, 9)));
|
||||
message.message = std::u16string(std::begin(tmp), std::end(tmp));
|
||||
|
||||
int size = sqlite3_column_bytes(stmt, 10);
|
||||
const uint8_t* data = reinterpret_cast<const uint8_t*>(sqlite3_column_blob(stmt, 10));
|
||||
|
||||
message.oob.resize(size / 2);
|
||||
for (int i = 0; i < size/2; ++i) {
|
||||
message.oob[i] = *reinterpret_cast<const uint16_t*>(data + i*2);
|
||||
}
|
||||
|
||||
sqlite3_finalize(stmt);
|
||||
|
||||
if (message.header.status == PersistentState::NEW) {
|
||||
UpdateMessageStatus(
|
||||
message.header.avatarId, message.header.messageId, PersistentState::READ);
|
||||
}
|
||||
|
||||
return message;
|
||||
}
|
||||
|
||||
void PersistentMessageService::UpdateMessageStatus(
|
||||
uint32_t avatarId, uint32_t messageId, PersistentState status) {
|
||||
sqlite3_stmt* stmt;
|
||||
|
||||
char sql[] = "UPDATE persistent_message SET status = @status WHERE id = @message_id AND "
|
||||
"avatar_id = @avatar_id";
|
||||
|
||||
auto result = sqlite3_prepare_v2(db_, sql, -1, &stmt, 0);
|
||||
if (result != SQLITE_OK) {
|
||||
throw SQLite3Exception{result, sqlite3_errmsg(db_)};
|
||||
}
|
||||
|
||||
int statusIdx = sqlite3_bind_parameter_index(stmt, "@status");
|
||||
int messageIdIdx = sqlite3_bind_parameter_index(stmt, "@message_id");
|
||||
int avatarIdIdx = sqlite3_bind_parameter_index(stmt, "@avatar_id");
|
||||
|
||||
sqlite3_bind_int(stmt, statusIdx, static_cast<uint32_t>(status));
|
||||
sqlite3_bind_int(stmt, messageIdIdx, messageId);
|
||||
sqlite3_bind_int(stmt, avatarIdIdx, avatarId);
|
||||
|
||||
result = sqlite3_step(stmt);
|
||||
if (result != SQLITE_DONE) {
|
||||
throw SQLite3Exception{result, sqlite3_errmsg(db_)};
|
||||
}
|
||||
|
||||
sqlite3_finalize(stmt);
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "ChatEnums.hpp"
|
||||
#include "PersistentMessage.hpp"
|
||||
|
||||
#include <boost/optional.hpp>
|
||||
|
||||
#include <cstdint>
|
||||
#include <vector>
|
||||
|
||||
struct sqlite3;
|
||||
|
||||
class PersistentMessageService {
|
||||
public:
|
||||
explicit PersistentMessageService(sqlite3* db);
|
||||
~PersistentMessageService();
|
||||
|
||||
void StoreMessage(PersistentMessage& message);
|
||||
|
||||
std::vector<PersistentHeader> GetMessageHeaders(uint32_t avatarId);
|
||||
|
||||
PersistentMessage GetPersistentMessage(uint32_t avatarId, uint32_t messageId);
|
||||
|
||||
void UpdateMessageStatus(
|
||||
uint32_t avatarId, uint32_t messageId, PersistentState status);
|
||||
|
||||
private:
|
||||
sqlite3* db_;
|
||||
};
|
||||
@@ -0,0 +1,45 @@
|
||||
#include "RegistrarClient.hpp"
|
||||
|
||||
#include "ChatEnums.hpp"
|
||||
#include "RegistrarNode.hpp"
|
||||
#include "Serialization.hpp"
|
||||
#include "StationChatConfig.hpp"
|
||||
#include "StringUtils.hpp"
|
||||
|
||||
#include "protocol/RegistrarGetChatServer.hpp"
|
||||
|
||||
#include "easylogging++.h"
|
||||
|
||||
RegistrarClient::RegistrarClient(UdpConnection* connection, RegistrarNode* node)
|
||||
: NodeClient(connection)
|
||||
, node_{node} {
|
||||
connection->SetHandler(this);
|
||||
}
|
||||
|
||||
RegistrarClient::~RegistrarClient() {}
|
||||
|
||||
RegistrarNode* RegistrarClient::GetNode() { return node_; }
|
||||
|
||||
void RegistrarClient::OnIncoming(std::istringstream& istream) {
|
||||
ChatRequestType request_type = ::read<ChatRequestType>(istream);
|
||||
|
||||
switch (request_type) {
|
||||
case ChatRequestType::REGISTRAR_GETCHATSERVER: {
|
||||
auto request = ::read<ReqRegistrarGetChatServer>(istream);
|
||||
RegistrarGetChatServer::ResponseType response{request.track};
|
||||
|
||||
try {
|
||||
RegistrarGetChatServer(this, request, response);
|
||||
} catch (const ChatResultException& e) {
|
||||
response.result = e.code;
|
||||
LOG(ERROR) << "ChatAPI Error: [" << static_cast<uint32_t>(e.code) << "] " << e.message;
|
||||
}
|
||||
|
||||
Send(response);
|
||||
} break;
|
||||
default:
|
||||
LOG(ERROR) << "Invalid registrar message type received: "
|
||||
<< static_cast<uint16_t>(request_type);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "NodeClient.hpp"
|
||||
|
||||
class RegistrarNode;
|
||||
class UdpConnection;
|
||||
|
||||
struct ReqRegistrarGetChatServer;
|
||||
|
||||
class RegistrarClient : public NodeClient {
|
||||
public:
|
||||
RegistrarClient(UdpConnection* connection, RegistrarNode* node);
|
||||
virtual ~RegistrarClient();
|
||||
|
||||
RegistrarNode* GetNode();
|
||||
|
||||
private:
|
||||
void OnIncoming(std::istringstream& istream) override;
|
||||
|
||||
RegistrarNode* node_;
|
||||
};
|
||||
@@ -0,0 +1,17 @@
|
||||
|
||||
#include "RegistrarNode.hpp"
|
||||
|
||||
#include "StationChatConfig.hpp"
|
||||
|
||||
RegistrarNode::RegistrarNode(StationChatConfig& config)
|
||||
: Node(this, config.registrarAddress, config.registrarPort)
|
||||
, config_{config} {}
|
||||
|
||||
RegistrarNode::~RegistrarNode() {}
|
||||
|
||||
StationChatConfig& RegistrarNode::GetConfig() {
|
||||
return config_;
|
||||
}
|
||||
|
||||
void RegistrarNode::OnTick() {}
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Node.hpp"
|
||||
#include "RegistrarClient.hpp"
|
||||
|
||||
struct StationChatConfig;
|
||||
|
||||
class RegistrarNode : public Node<RegistrarNode, RegistrarClient> {
|
||||
public:
|
||||
explicit RegistrarNode(StationChatConfig& config);
|
||||
~RegistrarNode();
|
||||
|
||||
StationChatConfig& GetConfig();
|
||||
|
||||
private:
|
||||
void OnTick() override;
|
||||
|
||||
StationChatConfig& config_;
|
||||
};
|
||||
@@ -0,0 +1,14 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <sqlite3.h>
|
||||
|
||||
struct SQLite3Exception {
|
||||
int code;
|
||||
std::string message;
|
||||
|
||||
SQLite3Exception(const int result, char const * text)
|
||||
: code{result}
|
||||
, message{text} {}
|
||||
};
|
||||
@@ -0,0 +1,119 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
|
||||
// integral types
|
||||
|
||||
template <typename StreamT, typename T,
|
||||
typename std::enable_if_t<std::is_integral<T>::value, int> = 0>
|
||||
void read(StreamT& istream, T& value) {
|
||||
istream.read(reinterpret_cast<char*>(&value), sizeof(T));
|
||||
}
|
||||
|
||||
template <typename StreamT, typename T,
|
||||
typename std::enable_if_t<std::is_integral<T>::value, int> = 0>
|
||||
void write(StreamT& ostream, const T& value) {
|
||||
ostream.write(reinterpret_cast<const char*>(&value), sizeof(T));
|
||||
}
|
||||
|
||||
// enumeration types with integral underlying types
|
||||
|
||||
template <typename StreamT, typename T,
|
||||
typename std::enable_if_t<std::is_enum<T>::value, int> = 0>
|
||||
void read(StreamT& istream, T& value) {
|
||||
istream.read(reinterpret_cast<char*>(&value), sizeof(T));
|
||||
}
|
||||
|
||||
template <typename StreamT, typename T,
|
||||
typename std::enable_if_t<std::is_enum<T>::value, int> = 0>
|
||||
void write(StreamT& ostream, const T& value) {
|
||||
ostream.write(reinterpret_cast<const char*>(&value), sizeof(T));
|
||||
}
|
||||
|
||||
// boolean types
|
||||
|
||||
template <typename StreamT>
|
||||
void read(StreamT& istream, bool& value) {
|
||||
uint8_t boolAsInt;
|
||||
read(istream, boolAsInt);
|
||||
value = (boolAsInt != 0);
|
||||
}
|
||||
|
||||
template <typename StreamT>
|
||||
void write(StreamT& ostream, const bool& value) {
|
||||
uint8_t boolAsInt = value ? 1 : 0;
|
||||
write(ostream, boolAsInt);
|
||||
}
|
||||
|
||||
// std::string types
|
||||
|
||||
template <typename StreamT>
|
||||
void read(StreamT& istream, std::string& value) {
|
||||
uint16_t length;
|
||||
read(istream, length);
|
||||
|
||||
value.resize(length);
|
||||
|
||||
istream.read(&value[0], length);
|
||||
}
|
||||
|
||||
template <typename StreamT>
|
||||
void write(StreamT& ostream, const std::string& value) {
|
||||
uint16_t length = static_cast<uint16_t>(value.length());
|
||||
write(ostream, length);
|
||||
|
||||
ostream.write(&value[0], length);
|
||||
}
|
||||
|
||||
// std::u16string types
|
||||
|
||||
template <typename StreamT>
|
||||
void read(StreamT& istream, std::u16string& value) {
|
||||
uint32_t length;
|
||||
read(istream, length);
|
||||
|
||||
value.resize(length);
|
||||
uint16_t tmp;
|
||||
for (uint32_t i = 0; i < length; ++i) {
|
||||
istream.read(reinterpret_cast<char*>(&tmp), sizeof(uint16_t));
|
||||
value[i] = tmp;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename StreamT>
|
||||
void write(StreamT& ostream, const std::u16string& value) {
|
||||
uint32_t length = static_cast<uint32_t>(value.length());
|
||||
write(ostream, length);
|
||||
|
||||
uint16_t tmp;
|
||||
for (uint32_t i = 0; i < length; ++i) {
|
||||
tmp = static_cast<uint16_t>(value[i]);
|
||||
ostream.write(reinterpret_cast<const char*>(&tmp), sizeof(uint16_t));
|
||||
}
|
||||
}
|
||||
|
||||
// Specialized Read Types
|
||||
|
||||
template <typename T, typename StreamT>
|
||||
T read(StreamT& istream) {
|
||||
T tmp;
|
||||
read(istream, tmp);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
template <typename T, typename StreamT>
|
||||
T readAt(StreamT& istream, size_t offset) {
|
||||
istream.seekg(offset);
|
||||
return read<T>(istream);
|
||||
}
|
||||
|
||||
// Similar to readAt, but preserves the read position of the stream
|
||||
template <typename T, typename StreamT>
|
||||
T peekAt(StreamT& istream, size_t offset) {
|
||||
auto pos = istream.tellg();
|
||||
T val = readAt<T>(istream, offset);
|
||||
istream.seekg(pos);
|
||||
return val;
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
#include "StationChatApp.hpp"
|
||||
|
||||
#include "easylogging++.h"
|
||||
|
||||
StationChatApp::StationChatApp(StationChatConfig config)
|
||||
: config_{std::move(config)} {
|
||||
registrarNode_ = std::make_unique<RegistrarNode>(config_);
|
||||
LOG(INFO) << "Registrar listening @" << config_.registrarAddress << ":" << config_.registrarPort;
|
||||
|
||||
gatewayNode_ = std::make_unique<GatewayNode>(config_);
|
||||
LOG(INFO) << "Gateway listening @" << config_.gatewayAddress << ":" << config_.gatewayPort;
|
||||
}
|
||||
|
||||
void StationChatApp::Tick() {
|
||||
registrarNode_->Tick();
|
||||
gatewayNode_->Tick();
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "GatewayNode.hpp"
|
||||
#include "RegistrarNode.hpp"
|
||||
#include "StationChatConfig.hpp"
|
||||
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
class StationChatApp {
|
||||
public:
|
||||
explicit StationChatApp(StationChatConfig config);
|
||||
|
||||
bool IsRunning() const { return isRunning_; }
|
||||
|
||||
void Tick();
|
||||
|
||||
private:
|
||||
StationChatConfig config_;
|
||||
bool isRunning_ = true;
|
||||
std::unique_ptr<GatewayNode> gatewayNode_;
|
||||
std::unique_ptr<RegistrarNode> registrarNode_;
|
||||
};
|
||||
@@ -0,0 +1,24 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
|
||||
struct StationChatConfig {
|
||||
StationChatConfig() = default;
|
||||
StationChatConfig(const std::string& gatewayAddress_, uint16_t gatewayPort_,
|
||||
const std::string& registrarAddress_, uint16_t registrarPort_, const std::string& chatDatabasePath_)
|
||||
: gatewayAddress{gatewayAddress_}
|
||||
, gatewayPort{gatewayPort_}
|
||||
, registrarAddress{registrarAddress_}
|
||||
, registrarPort{registrarPort_}
|
||||
, chatDatabasePath{chatDatabasePath_} {}
|
||||
|
||||
const uint32_t version = 2;
|
||||
std::string gatewayAddress;
|
||||
uint16_t gatewayPort;
|
||||
std::string registrarAddress;
|
||||
uint16_t registrarPort;
|
||||
std::string chatDatabasePath;
|
||||
std::string loggerConfig;
|
||||
};
|
||||
@@ -0,0 +1,75 @@
|
||||
|
||||
#include "StreamUtils.hpp"
|
||||
#include "UdpLibrary.hpp"
|
||||
|
||||
#include "easylogging++.h"
|
||||
|
||||
#include <iomanip>
|
||||
|
||||
std::ostream& operator<<(std::ostream& os, const BinaryData& bd) {
|
||||
auto length = bd.length();
|
||||
auto data = bd.data();
|
||||
|
||||
if (length == 0)
|
||||
return os;
|
||||
|
||||
// Calculate the number of lines and extra bits.
|
||||
auto lines = static_cast<int16_t>(length / 16);
|
||||
auto extra = static_cast<int16_t>(length % 16);
|
||||
|
||||
// Save the formatting state of the stream.
|
||||
auto flags = os.flags(os.hex);
|
||||
auto fill = os.fill('0');
|
||||
auto width = os.width(2);
|
||||
|
||||
// The byte buffer should be printed out in lines of 16 characters and display
|
||||
// both hex and ascii values for each character, see most hex editors for
|
||||
// reference.
|
||||
char ascii[17] = {0};
|
||||
unsigned char c;
|
||||
for (int16_t i = 0; i <= lines; i++) {
|
||||
// Print out a line number.
|
||||
os << std::setw(4) << (i * 16) << ": ";
|
||||
|
||||
for (int16_t j = 0; j < 16; ++j) { // Loop through the characters of this line (max 16)
|
||||
// For the last line there may not be 16 characters. In this case filler
|
||||
// whitespace should be added to keep column widths consistent.
|
||||
if (i == lines && j >= extra) {
|
||||
os << " ";
|
||||
ascii[j] = ' ';
|
||||
} else {
|
||||
c = data[(i * 16) + j];
|
||||
|
||||
os << std::setw(2) << static_cast<unsigned>(c) << " ";
|
||||
|
||||
// If an ascii char print it, otherwise print a . instead of gibberish
|
||||
ascii[j] = (c < ' ' || c > '~') ? '.' : c;
|
||||
}
|
||||
}
|
||||
|
||||
os << " " << ascii << "\n";
|
||||
}
|
||||
|
||||
// Return formatting of stream to its previous state.
|
||||
os.flags(flags);
|
||||
os.fill(fill);
|
||||
os.width(width);
|
||||
|
||||
return os;
|
||||
}
|
||||
|
||||
void logNetworkMessage(
|
||||
UdpConnection* connection, std::string message, const unsigned char* data, int length) {
|
||||
char hold[256];
|
||||
|
||||
VLOG(1) << "\n"
|
||||
<< message << " " << connection->GetDestinationIp().GetAddress(hold) << ":"
|
||||
<< connection->GetDestinationPort() << " length: " << length << "\n"
|
||||
<< BinaryData{data, length};
|
||||
}
|
||||
|
||||
std::ostream& operator<<(std::ostream& os, const std::u16string& data) {
|
||||
os << std::string{std::begin(data), std::end(data)};
|
||||
|
||||
return os;
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ostream>
|
||||
#include <string>
|
||||
|
||||
class UdpConnection;
|
||||
|
||||
class BinaryData {
|
||||
public:
|
||||
BinaryData(const unsigned char* data, int length)
|
||||
: data_{ data }
|
||||
, length_{ length }
|
||||
{}
|
||||
|
||||
const unsigned char* data() const { return data_; }
|
||||
int length() const { return length_; }
|
||||
|
||||
private:
|
||||
const unsigned char* data_;
|
||||
int length_;
|
||||
};
|
||||
|
||||
std::ostream& operator<<(std::ostream& os, const BinaryData& data);
|
||||
|
||||
std::ostream& operator<<(std::ostream& os, const std::u16string& data);
|
||||
|
||||
void logNetworkMessage(UdpConnection* connection, std::string message, const unsigned char* data, int length);
|
||||
@@ -0,0 +1,10 @@
|
||||
|
||||
#include "StreamUtils.hpp"
|
||||
|
||||
std::string FromWideString(const std::u16string& str) {
|
||||
return std::string{std::begin(str), std::end(str)};
|
||||
}
|
||||
|
||||
std::u16string ToWideString(const std::string& str) {
|
||||
return std::u16string{std::begin(str), std::end(str)};
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
std::string FromWideString(const std::u16string& str);
|
||||
|
||||
std::u16string ToWideString(const std::string& str);
|
||||
@@ -0,0 +1,91 @@
|
||||
|
||||
|
||||
#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>
|
||||
|
||||
INITIALIZE_EASYLOGGINGPP
|
||||
|
||||
StationChatConfig BuildConfiguration(int argc, char* argv[]);
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
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"),
|
||||
"setspath 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;
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
#include "AddBan.hpp"
|
||||
|
||||
#include "ChatAvatarService.hpp"
|
||||
#include "ChatRoomService.hpp"
|
||||
#include "GatewayClient.hpp"
|
||||
#include "GatewayNode.hpp"
|
||||
#include "StringUtils.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);
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "ChatEnums.hpp"
|
||||
|
||||
class ChatAvatarService;
|
||||
class ChatRoomService;
|
||||
class GatewayClient;
|
||||
|
||||
/** Begin ADDBAN */
|
||||
|
||||
struct ReqAddBan {
|
||||
const ChatRequestType type = ChatRequestType::ADDBAN;
|
||||
uint32_t track;
|
||||
uint32_t srcAvatarId;
|
||||
std::u16string destAvatarName;
|
||||
std::u16string destAvatarAddress;
|
||||
std::u16string destRoomAddress;
|
||||
std::u16string srcAddress;
|
||||
};
|
||||
|
||||
template <typename StreamT>
|
||||
void read(StreamT& ar, ReqAddBan& data) {
|
||||
read(ar, data.track);
|
||||
read(ar, data.srcAvatarId);
|
||||
read(ar, data.destAvatarName);
|
||||
read(ar, data.destAvatarAddress);
|
||||
read(ar, data.destRoomAddress);
|
||||
read(ar, data.srcAddress);
|
||||
}
|
||||
|
||||
/** Begin ADDBAN */
|
||||
|
||||
struct ResAddBan {
|
||||
explicit ResAddBan(uint32_t track_)
|
||||
: track{track_}
|
||||
, result{ChatResultCode::SUCCESS} {}
|
||||
|
||||
const ChatResponseType type = ChatResponseType::ADDBAN;
|
||||
uint32_t track;
|
||||
ChatResultCode result;
|
||||
uint32_t destRoomId;
|
||||
};
|
||||
|
||||
template <typename StreamT>
|
||||
void write(StreamT& ar, const ResAddBan& data) {
|
||||
write(ar, data.type);
|
||||
write(ar, data.track);
|
||||
write(ar, data.result);
|
||||
write(ar, data.destRoomId);
|
||||
}
|
||||
|
||||
class AddBan {
|
||||
public:
|
||||
using RequestType = ReqAddBan;
|
||||
using ResponseType = ResAddBan;
|
||||
|
||||
AddBan(GatewayClient* client, const RequestType& request, ResponseType& response);
|
||||
|
||||
private:
|
||||
ChatAvatarService* avatarService_;
|
||||
ChatRoomService* roomService_;
|
||||
};
|
||||
@@ -0,0 +1,30 @@
|
||||
#include "AddFriend.hpp"
|
||||
|
||||
#include "ChatAvatarService.hpp"
|
||||
#include "GatewayClient.hpp"
|
||||
#include "GatewayNode.hpp"
|
||||
#include "StringUtils.hpp"
|
||||
|
||||
#include "easylogging++.h"
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "ChatEnums.hpp"
|
||||
|
||||
class ChatAvatarService;
|
||||
class ChatRoomService;
|
||||
class GatewayClient;
|
||||
|
||||
/** Begin ADDFRIEND */
|
||||
|
||||
struct ReqAddFriend {
|
||||
const ChatRequestType type = ChatRequestType::ADDFRIEND;
|
||||
uint32_t track;
|
||||
uint32_t srcAvatarId;
|
||||
std::u16string destName;
|
||||
std::u16string destAddress;
|
||||
std::u16string comment;
|
||||
bool confirm;
|
||||
std::u16string srcAddress;
|
||||
};
|
||||
|
||||
template <typename StreamT>
|
||||
void read(StreamT& ar, ReqAddFriend& data) {
|
||||
read(ar, data.track);
|
||||
read(ar, data.srcAvatarId);
|
||||
read(ar, data.destName);
|
||||
read(ar, data.destAddress);
|
||||
read(ar, data.comment);
|
||||
read(ar, data.confirm);
|
||||
read(ar, data.srcAddress);
|
||||
}
|
||||
|
||||
/** Begin ADDFRIEND */
|
||||
|
||||
struct ResAddFriend {
|
||||
ResAddFriend(uint32_t track_)
|
||||
: track{track_}
|
||||
, result{ChatResultCode::SUCCESS} {}
|
||||
|
||||
const ChatResponseType type = ChatResponseType::ADDFRIEND;
|
||||
uint32_t track;
|
||||
ChatResultCode result;
|
||||
};
|
||||
|
||||
template <typename StreamT>
|
||||
void write(StreamT& ar, const ResAddFriend& data) {
|
||||
write(ar, data.type);
|
||||
write(ar, data.track);
|
||||
write(ar, data.result);
|
||||
}
|
||||
|
||||
class AddFriend {
|
||||
public:
|
||||
using RequestType = ReqAddFriend;
|
||||
using ResponseType = ResAddFriend;
|
||||
|
||||
AddFriend(GatewayClient* client, const RequestType& request, ResponseType& response);
|
||||
|
||||
private:
|
||||
ChatAvatarService* avatarService_;
|
||||
};
|
||||
@@ -0,0 +1,26 @@
|
||||
#include "AddIgnore.hpp"
|
||||
|
||||
#include "ChatAvatarService.hpp"
|
||||
#include "GatewayClient.hpp"
|
||||
#include "GatewayNode.hpp"
|
||||
#include "StringUtils.hpp"
|
||||
|
||||
#include "easylogging++.h"
|
||||
|
||||
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);
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "ChatEnums.hpp"
|
||||
|
||||
class ChatAvatarService;
|
||||
class ChatRoomService;
|
||||
class GatewayClient;
|
||||
|
||||
/** Begin ADDIGNORE */
|
||||
|
||||
struct ReqAddIgnore {
|
||||
const ChatRequestType type = ChatRequestType::ADDIGNORE;
|
||||
uint32_t track;
|
||||
uint32_t srcAvatarId;
|
||||
std::u16string destName;
|
||||
std::u16string destAddress;
|
||||
std::u16string srcAddress;
|
||||
};
|
||||
|
||||
template <typename StreamT>
|
||||
void read(StreamT& ar, ReqAddIgnore& data) {
|
||||
read(ar, data.track);
|
||||
read(ar, data.srcAvatarId);
|
||||
read(ar, data.destName);
|
||||
read(ar, data.destAddress);
|
||||
read(ar, data.srcAddress);
|
||||
}
|
||||
|
||||
/** Begin ADDIGNORE */
|
||||
|
||||
struct ResAddIgnore {
|
||||
ResAddIgnore(uint32_t track_)
|
||||
: track{track_}
|
||||
, result{ChatResultCode::SUCCESS} {}
|
||||
|
||||
const ChatResponseType type = ChatResponseType::ADDIGNORE;
|
||||
uint32_t track;
|
||||
ChatResultCode result;
|
||||
};
|
||||
|
||||
template <typename StreamT>
|
||||
void write(StreamT& ar, const ResAddIgnore& data) {
|
||||
write(ar, data.type);
|
||||
write(ar, data.track);
|
||||
write(ar, data.result);
|
||||
}
|
||||
|
||||
class AddIgnore {
|
||||
public:
|
||||
using RequestType = ReqAddIgnore;
|
||||
using ResponseType = ResAddIgnore;
|
||||
|
||||
AddIgnore(GatewayClient* client, const RequestType& request, ResponseType& response);
|
||||
|
||||
private:
|
||||
ChatAvatarService* avatarService_;
|
||||
};
|
||||
@@ -0,0 +1,38 @@
|
||||
#include "AddInvite.hpp"
|
||||
|
||||
#include "ChatAvatarService.hpp"
|
||||
#include "ChatRoomService.hpp"
|
||||
#include "GatewayClient.hpp"
|
||||
#include "GatewayNode.hpp"
|
||||
#include "StringUtils.hpp"
|
||||
|
||||
#include "easylogging++.h"
|
||||
|
||||
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);
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "ChatEnums.hpp"
|
||||
|
||||
class ChatAvatarService;
|
||||
class ChatRoomService;
|
||||
class GatewayClient;
|
||||
|
||||
/** Begin ADDINVITE */
|
||||
|
||||
struct ReqAddInvite {
|
||||
const ChatRequestType type = ChatRequestType::ADDINVITE;
|
||||
uint32_t track;
|
||||
uint32_t srcAvatarId;
|
||||
std::u16string destAvatarName;
|
||||
std::u16string destAvatarAddress;
|
||||
std::u16string destRoomAddress;
|
||||
std::u16string srcAddress;
|
||||
};
|
||||
|
||||
template <typename StreamT>
|
||||
void read(StreamT& ar, ReqAddInvite& data) {
|
||||
read(ar, data.track);
|
||||
read(ar, data.srcAvatarId);
|
||||
read(ar, data.destAvatarName);
|
||||
read(ar, data.destAvatarAddress);
|
||||
read(ar, data.destRoomAddress);
|
||||
read(ar, data.srcAddress);
|
||||
}
|
||||
|
||||
/** Begin ADDINVITE */
|
||||
|
||||
struct ResAddInvite {
|
||||
explicit ResAddInvite(uint32_t track_)
|
||||
: track{track_}
|
||||
, result{ChatResultCode::SUCCESS} {}
|
||||
|
||||
const ChatResponseType type = ChatResponseType::ADDINVITE;
|
||||
uint32_t track;
|
||||
ChatResultCode result;
|
||||
uint32_t destRoomId;
|
||||
};
|
||||
|
||||
template <typename StreamT>
|
||||
void write(StreamT& ar, const ResAddInvite& data) {
|
||||
write(ar, data.type);
|
||||
write(ar, data.track);
|
||||
write(ar, data.result);
|
||||
write(ar, data.destRoomId);
|
||||
}
|
||||
|
||||
class AddInvite {
|
||||
public:
|
||||
using RequestType = ReqAddInvite;
|
||||
using ResponseType = ResAddInvite;
|
||||
|
||||
AddInvite(GatewayClient* client, const RequestType& request, ResponseType& response);
|
||||
|
||||
private:
|
||||
ChatAvatarService* avatarService_;
|
||||
ChatRoomService* roomService_;
|
||||
};
|
||||
@@ -0,0 +1,39 @@
|
||||
#include "AddModerator.hpp"
|
||||
|
||||
#include "ChatAvatarService.hpp"
|
||||
#include "ChatRoomService.hpp"
|
||||
#include "GatewayClient.hpp"
|
||||
#include "GatewayNode.hpp"
|
||||
#include "StringUtils.hpp"
|
||||
|
||||
#include "easylogging++.h"
|
||||
|
||||
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);
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "ChatEnums.hpp"
|
||||
|
||||
class ChatAvatarService;
|
||||
class ChatRoomService;
|
||||
class GatewayClient;
|
||||
|
||||
/** Begin ADDMODERATOR */
|
||||
|
||||
struct ReqAddModerator {
|
||||
const ChatRequestType type = ChatRequestType::ADDMODERATOR;
|
||||
uint32_t track;
|
||||
uint32_t srcAvatarId;
|
||||
std::u16string destAvatarName;
|
||||
std::u16string destAvatarAddress;
|
||||
std::u16string destRoomAddress;
|
||||
std::u16string srcAddress;
|
||||
};
|
||||
|
||||
template <typename StreamT>
|
||||
void read(StreamT& ar, ReqAddModerator& data) {
|
||||
read(ar, data.track);
|
||||
read(ar, data.srcAvatarId);
|
||||
read(ar, data.destAvatarName);
|
||||
read(ar, data.destAvatarAddress);
|
||||
read(ar, data.destRoomAddress);
|
||||
read(ar, data.srcAddress);
|
||||
}
|
||||
|
||||
/** Begin ADDMODERATOR */
|
||||
|
||||
struct ResAddModerator {
|
||||
ResAddModerator(uint32_t track_)
|
||||
: track{track_}
|
||||
, result{ChatResultCode::SUCCESS} {}
|
||||
|
||||
const ChatResponseType type = ChatResponseType::ADDMODERATOR;
|
||||
uint32_t track;
|
||||
ChatResultCode result;
|
||||
uint32_t destRoomId;
|
||||
};
|
||||
|
||||
template <typename StreamT>
|
||||
void write(StreamT& ar, const ResAddModerator& data) {
|
||||
write(ar, data.type);
|
||||
write(ar, data.track);
|
||||
write(ar, data.result);
|
||||
write(ar, data.destRoomId);
|
||||
}
|
||||
|
||||
class AddModerator {
|
||||
public:
|
||||
using RequestType = ReqAddModerator;
|
||||
using ResponseType = ResAddModerator;
|
||||
|
||||
AddModerator(GatewayClient* client, const RequestType& request, ResponseType& response);
|
||||
|
||||
private:
|
||||
ChatAvatarService* avatarService_;
|
||||
ChatRoomService* roomService_;
|
||||
};
|
||||
@@ -0,0 +1,21 @@
|
||||
#include "CreateRoom.hpp"
|
||||
|
||||
#include "ChatAvatarService.hpp"
|
||||
#include "ChatRoomService.hpp"
|
||||
#include "GatewayClient.hpp"
|
||||
#include "GatewayNode.hpp"
|
||||
#include "StringUtils.hpp"
|
||||
|
||||
#include "easylogging++.h"
|
||||
|
||||
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);
|
||||
}
|
||||
@@ -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,29 @@
|
||||
#include "DestroyAvatar.hpp"
|
||||
|
||||
#include "ChatAvatarService.hpp"
|
||||
#include "ChatRoomService.hpp"
|
||||
#include "GatewayClient.hpp"
|
||||
#include "GatewayNode.hpp"
|
||||
|
||||
#include "easylogging++.h"
|
||||
|
||||
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 : avatar->GetJoinedRooms()) {
|
||||
auto addresses = room->GetConnectedAddresses();
|
||||
room->LeaveRoom(avatar);
|
||||
|
||||
client->SendLeaveRoomUpdate(addresses, avatar->GetAvatarId(), room->GetRoomId());
|
||||
}
|
||||
|
||||
// Destroy avatar
|
||||
avatarService_->DestroyAvatar(avatar);
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "ChatEnums.hpp"
|
||||
|
||||
class ChatAvatarService;
|
||||
class ChatRoomService;
|
||||
class GatewayClient;
|
||||
|
||||
/** Begin DESTROYAVATAR */
|
||||
|
||||
struct ReqDestroyAvatar {
|
||||
const ChatRequestType type = ChatRequestType::LOGOUTAVATAR;
|
||||
uint32_t track;
|
||||
uint32_t avatarId;
|
||||
std::u16string address;
|
||||
};
|
||||
|
||||
template <typename StreamT>
|
||||
void read(StreamT& ar, ReqDestroyAvatar& data) {
|
||||
read(ar, data.track);
|
||||
read(ar, data.avatarId);
|
||||
read(ar, data.address);
|
||||
}
|
||||
|
||||
/** Begin DESTROYAVATAR */
|
||||
|
||||
struct ResDestroyAvatar {
|
||||
explicit ResDestroyAvatar(uint32_t track_)
|
||||
: track{track_}
|
||||
, result{ChatResultCode::SUCCESS} {}
|
||||
|
||||
const ChatResponseType type = ChatResponseType::DESTROYAVATAR;
|
||||
uint32_t track;
|
||||
ChatResultCode result;
|
||||
};
|
||||
|
||||
template <typename StreamT>
|
||||
void write(StreamT& ar, const ResDestroyAvatar& data) {
|
||||
write(ar, data.type);
|
||||
write(ar, data.track);
|
||||
write(ar, data.result);
|
||||
}
|
||||
|
||||
class DestroyAvatar {
|
||||
public:
|
||||
using RequestType = ReqDestroyAvatar;
|
||||
using ResponseType = ResDestroyAvatar;
|
||||
|
||||
DestroyAvatar(GatewayClient* client, const RequestType& request, ResponseType& response);
|
||||
|
||||
private:
|
||||
ChatAvatarService* avatarService_;
|
||||
ChatRoomService* roomService_;
|
||||
};
|
||||
@@ -0,0 +1,42 @@
|
||||
#include "DestroyRoom.hpp"
|
||||
|
||||
#include "ChatAvatarService.hpp"
|
||||
#include "ChatRoomService.hpp"
|
||||
#include "GatewayClient.hpp"
|
||||
#include "GatewayNode.hpp"
|
||||
#include "StringUtils.hpp"
|
||||
|
||||
#include "easylogging++.h"
|
||||
|
||||
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;
|
||||
|
||||
for (auto roomAvatar : room->GetAvatars()) {
|
||||
auto roomAddresses = room->GetConnectedAddresses();
|
||||
room->LeaveRoom(roomAvatar);
|
||||
client->SendLeaveRoomUpdate(roomAddresses, roomAvatar->GetAvatarId(), roomId);
|
||||
}
|
||||
|
||||
roomService_->DestroyRoom(room);
|
||||
|
||||
client->SendDestroyRoomUpdate(srcAvatar, roomId, addresses);
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "ChatEnums.hpp"
|
||||
|
||||
class ChatAvatarService;
|
||||
class ChatRoomService;
|
||||
class GatewayClient;
|
||||
|
||||
/** Begin DESTROYROOM */
|
||||
|
||||
struct ReqDestroyRoom {
|
||||
const ChatRequestType type = ChatRequestType::DESTROYROOM;
|
||||
uint32_t track;
|
||||
uint32_t srcAvatarId;
|
||||
std::u16string roomAddress;
|
||||
std::u16string srcAddress;
|
||||
};
|
||||
|
||||
template <typename StreamT>
|
||||
void read(StreamT& ar, ReqDestroyRoom& data) {
|
||||
read(ar, data.track);
|
||||
read(ar, data.srcAvatarId);
|
||||
read(ar, data.roomAddress);
|
||||
read(ar, data.srcAddress);
|
||||
}
|
||||
|
||||
/** Begin DESTROYROOM */
|
||||
|
||||
struct ResDestroyRoom {
|
||||
explicit ResDestroyRoom(uint32_t track_)
|
||||
: track{track_}
|
||||
, result{ChatResultCode::SUCCESS} {}
|
||||
|
||||
const ChatResponseType type = ChatResponseType::DESTROYROOM;
|
||||
uint32_t track;
|
||||
ChatResultCode result;
|
||||
uint32_t roomId;
|
||||
};
|
||||
|
||||
template <typename StreamT>
|
||||
void write(StreamT& ar, const ResDestroyRoom& data) {
|
||||
write(ar, data.type);
|
||||
write(ar, data.track);
|
||||
write(ar, data.result);
|
||||
write(ar, data.roomId);
|
||||
}
|
||||
|
||||
class DestroyRoom {
|
||||
public:
|
||||
using RequestType = ReqDestroyRoom;
|
||||
using ResponseType = ResDestroyRoom;
|
||||
|
||||
DestroyRoom(GatewayClient* client, const RequestType& request, ResponseType& response);
|
||||
|
||||
private:
|
||||
ChatAvatarService* avatarService_;
|
||||
ChatRoomService* roomService_;
|
||||
};
|
||||
@@ -0,0 +1,33 @@
|
||||
#include "EnterRoom.hpp"
|
||||
|
||||
#include "ChatAvatarService.hpp"
|
||||
#include "ChatRoom.hpp"
|
||||
#include "ChatRoomService.hpp"
|
||||
#include "GatewayClient.hpp"
|
||||
#include "GatewayNode.hpp"
|
||||
#include "StringUtils.hpp"
|
||||
|
||||
#include "easylogging++.h"
|
||||
|
||||
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);
|
||||
}
|
||||
@@ -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,38 @@
|
||||
#include "FailoverReLoginAvatar.hpp"
|
||||
|
||||
#include "ChatAvatarService.hpp"
|
||||
#include "ChatRoomService.hpp"
|
||||
#include "GatewayClient.hpp"
|
||||
#include "GatewayNode.hpp"
|
||||
#include "StringUtils.hpp"
|
||||
|
||||
#include "easylogging++.h"
|
||||
|
||||
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 : avatar->GetJoinedRooms()) {
|
||||
client->SendEnterRoomUpdate(avatar, room);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "ChatEnums.hpp"
|
||||
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
|
||||
class ChatAvatarService;
|
||||
class ChatRoomService;
|
||||
class GatewayClient;
|
||||
|
||||
struct ReqFailoverReLoginAvatar{
|
||||
const ChatRequestType type = ChatRequestType::FAILOVER_RELOGINAVATAR;
|
||||
uint32_t track;
|
||||
uint32_t avatarId;
|
||||
uint32_t userId;
|
||||
std::u16string name;
|
||||
std::u16string address;
|
||||
std::u16string loginLocation;
|
||||
int32_t loginPriority;
|
||||
uint32_t attributes;
|
||||
};
|
||||
|
||||
struct ResFailoverReLoginAvatar {
|
||||
ResFailoverReLoginAvatar(uint32_t track_)
|
||||
: track{track_}
|
||||
, result{ChatResultCode::SUCCESS} {}
|
||||
|
||||
const ChatResponseType type = ChatResponseType::FAILOVER_RELOGINAVATAR;
|
||||
uint32_t track;
|
||||
ChatResultCode result;
|
||||
};
|
||||
|
||||
class FailoverReLoginAvatar {
|
||||
public:
|
||||
using RequestType = ReqFailoverReLoginAvatar;
|
||||
using ResponseType = ResFailoverReLoginAvatar;
|
||||
|
||||
FailoverReLoginAvatar(GatewayClient* client, const RequestType& request, ResponseType& response);
|
||||
|
||||
private:
|
||||
ChatAvatarService* avatarService_;
|
||||
ChatRoomService* roomService_;
|
||||
};
|
||||
|
||||
template <typename StreamT>
|
||||
void read(StreamT& ar, ReqFailoverReLoginAvatar& data) {
|
||||
read(ar, data.track);
|
||||
read(ar, data.avatarId);
|
||||
read(ar, data.userId);
|
||||
read(ar, data.name);
|
||||
read(ar, data.address);
|
||||
read(ar, data.loginLocation);
|
||||
read(ar, data.loginPriority);
|
||||
read(ar, data.attributes);
|
||||
}
|
||||
|
||||
template <typename StreamT>
|
||||
void write(StreamT& ar, const ResFailoverReLoginAvatar& data) {
|
||||
write(ar, data.type);
|
||||
write(ar, data.track);
|
||||
write(ar, data.result);
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
#include "FriendStatus.hpp"
|
||||
|
||||
#include "ChatAvatarService.hpp"
|
||||
#include "GatewayClient.hpp"
|
||||
#include "GatewayNode.hpp"
|
||||
#include "StringUtils.hpp"
|
||||
|
||||
#include "easylogging++.h"
|
||||
|
||||
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;
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "ChatAvatar.hpp"
|
||||
#include "ChatEnums.hpp"
|
||||
|
||||
#include <string>
|
||||
|
||||
class ChatAvatarService;
|
||||
class ChatRoomService;
|
||||
class GatewayClient;
|
||||
|
||||
/** Begin FRIENDSTATUS */
|
||||
|
||||
struct ReqFriendStatus {
|
||||
const ChatRequestType type = ChatRequestType::FRIENDSTATUS;
|
||||
uint32_t track;
|
||||
uint32_t srcAvatarId;
|
||||
std::u16string srcAddress;
|
||||
};
|
||||
|
||||
template <typename StreamT>
|
||||
void read(StreamT& ar, ReqFriendStatus& data) {
|
||||
read(ar, data.track);
|
||||
read(ar, data.srcAvatarId);
|
||||
read(ar, data.srcAddress);
|
||||
}
|
||||
|
||||
/** Begin FRIENDSTATUS */
|
||||
|
||||
struct ResFriendStatus {
|
||||
ResFriendStatus(uint32_t track_)
|
||||
: track{track_}
|
||||
, result{ChatResultCode::SUCCESS} {}
|
||||
|
||||
const ChatResponseType type = ChatResponseType::FRIENDSTATUS;
|
||||
uint32_t track;
|
||||
ChatResultCode result;
|
||||
const ChatAvatar* srcAvatar;
|
||||
};
|
||||
|
||||
template <typename StreamT>
|
||||
void write(StreamT& ar, const ResFriendStatus& data) {
|
||||
write(ar, data.type);
|
||||
write(ar, data.track);
|
||||
write(ar, data.result);
|
||||
|
||||
if (data.result == ChatResultCode::SUCCESS && data.srcAvatar) {
|
||||
const auto& friends = data.srcAvatar->GetFriendList();
|
||||
|
||||
write(ar, static_cast<uint32_t>(friends.size()));
|
||||
for (auto& friendContact : friends) {
|
||||
write(ar, friendContact);
|
||||
}
|
||||
} else {
|
||||
write(ar, static_cast<uint32_t>(0));
|
||||
}
|
||||
}
|
||||
|
||||
class FriendStatus {
|
||||
public:
|
||||
using RequestType = ReqFriendStatus;
|
||||
using ResponseType = ResFriendStatus;
|
||||
|
||||
FriendStatus(GatewayClient* client, const RequestType& request, ResponseType& response);
|
||||
|
||||
private:
|
||||
ChatAvatarService* avatarService_;
|
||||
ChatRoomService* roomService_;
|
||||
};
|
||||
@@ -0,0 +1,24 @@
|
||||
#include "GetAnyAvatar.hpp"
|
||||
|
||||
#include "ChatAvatarService.hpp"
|
||||
#include "ChatRoomService.hpp"
|
||||
#include "GatewayClient.hpp"
|
||||
#include "GatewayNode.hpp"
|
||||
#include "StringUtils.hpp"
|
||||
|
||||
#include "easylogging++.h"
|
||||
|
||||
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;
|
||||
}
|
||||
@@ -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,17 @@
|
||||
#include "GetPersistentHeaders.hpp"
|
||||
|
||||
#include "GatewayClient.hpp"
|
||||
#include "GatewayNode.hpp"
|
||||
#include "PersistentMessageService.hpp"
|
||||
#include "StringUtils.hpp"
|
||||
|
||||
#include "easylogging++.h"
|
||||
|
||||
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);
|
||||
}
|
||||
@@ -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,17 @@
|
||||
#include "GetPersistentMessage.hpp"
|
||||
|
||||
#include "GatewayClient.hpp"
|
||||
#include "GatewayNode.hpp"
|
||||
#include "PersistentMessageService.hpp"
|
||||
|
||||
#include "easylogging++.h"
|
||||
|
||||
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);
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "ChatEnums.hpp"
|
||||
#include "PersistentMessage.hpp"
|
||||
|
||||
class PersistentMessageService;
|
||||
class GatewayClient;
|
||||
|
||||
/** Begin GETPERSISTENTMESSAGE */
|
||||
|
||||
struct ReqGetPersistentMessage {
|
||||
const ChatRequestType type = ChatRequestType::GETPERSISTENTMESSAGE;
|
||||
uint32_t track;
|
||||
uint32_t srcAvatarId;
|
||||
uint32_t messageId;
|
||||
};
|
||||
|
||||
template <typename StreamT>
|
||||
void read(StreamT& ar, ReqGetPersistentMessage& data) {
|
||||
read(ar, data.track);
|
||||
read(ar, data.srcAvatarId);
|
||||
read(ar, data.messageId);
|
||||
}
|
||||
|
||||
/** Begin GETPERSISTENTMESSAGE */
|
||||
|
||||
struct ResGetPersistentMessage {
|
||||
ResGetPersistentMessage(
|
||||
uint32_t track_)
|
||||
: track{track_}
|
||||
, result{ChatResultCode::SUCCESS} {}
|
||||
|
||||
const ChatResponseType type = ChatResponseType::GETPERSISTENTMESSAGE;
|
||||
uint32_t track;
|
||||
ChatResultCode result;
|
||||
PersistentMessage message;
|
||||
};
|
||||
|
||||
template <typename StreamT>
|
||||
void write(StreamT& ar, const ResGetPersistentMessage& data) {
|
||||
write(ar, data.type);
|
||||
write(ar, data.track);
|
||||
write(ar, data.result);
|
||||
|
||||
if (data.result == ChatResultCode::SUCCESS) {
|
||||
write(ar, data.message);
|
||||
}
|
||||
}
|
||||
|
||||
class GetPersistentMessage {
|
||||
public:
|
||||
using RequestType = ReqGetPersistentMessage;
|
||||
using ResponseType = ResGetPersistentMessage;
|
||||
|
||||
GetPersistentMessage(GatewayClient* client, const RequestType& request, ResponseType& response);
|
||||
|
||||
private:
|
||||
PersistentMessageService* messageService_;
|
||||
};
|
||||
@@ -0,0 +1,20 @@
|
||||
#include "GetRoom.hpp"
|
||||
|
||||
#include "ChatRoomService.hpp"
|
||||
#include "GatewayClient.hpp"
|
||||
#include "GatewayNode.hpp"
|
||||
#include "StringUtils.hpp"
|
||||
|
||||
#include "easylogging++.h"
|
||||
|
||||
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;
|
||||
}
|
||||
@@ -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,18 @@
|
||||
#include "GetRoomSummaries.hpp"
|
||||
|
||||
#include "ChatRoomService.hpp"
|
||||
#include "GatewayClient.hpp"
|
||||
#include "GatewayNode.hpp"
|
||||
#include "StringUtils.hpp"
|
||||
|
||||
#include "easylogging++.h"
|
||||
|
||||
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);
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "ChatEnums.hpp"
|
||||
#include "ChatRoom.hpp"
|
||||
|
||||
#include <vector>
|
||||
|
||||
class ChatAvatarService;
|
||||
class ChatRoomService;
|
||||
class GatewayClient;
|
||||
|
||||
/** Begin GETROOMSUMMARIES */
|
||||
|
||||
struct ReqGetRoomSummaries {
|
||||
const ChatRequestType type = ChatRequestType::GETROOMSUMMARIES;
|
||||
uint32_t track;
|
||||
std::u16string startNodeAddress;
|
||||
std::u16string roomFilter;
|
||||
};
|
||||
|
||||
template <typename StreamT>
|
||||
void read(StreamT& ar, ReqGetRoomSummaries& data) {
|
||||
read(ar, data.track);
|
||||
read(ar, data.startNodeAddress);
|
||||
read(ar, data.roomFilter);
|
||||
}
|
||||
|
||||
/** Begin GETROOMSUMMARIES */
|
||||
|
||||
struct ResGetRoomSummaries {
|
||||
ResGetRoomSummaries(uint32_t track_)
|
||||
: track{track_}
|
||||
, result{ChatResultCode::SUCCESS} {}
|
||||
|
||||
const ChatResponseType type = ChatResponseType::GETROOMSUMMARIES;
|
||||
uint32_t track;
|
||||
ChatResultCode result;
|
||||
std::vector<ChatRoom*> rooms;
|
||||
};
|
||||
|
||||
template <typename StreamT>
|
||||
void write(StreamT& ar, const ResGetRoomSummaries& data) {
|
||||
write(ar, data.type);
|
||||
write(ar, data.track);
|
||||
write(ar, data.result);
|
||||
|
||||
write(ar, static_cast<uint32_t>(data.rooms.size()));
|
||||
for (auto room : data.rooms) {
|
||||
write(ar, room->GetRoomAddress());
|
||||
write(ar, room->GetRoomTopic());
|
||||
write(ar, room->GetRoomAttributes());
|
||||
write(ar, room->GetCurrentRoomSize());
|
||||
write(ar, room->GetMaxRoomSize());
|
||||
}
|
||||
}
|
||||
|
||||
class GetRoomSummaries {
|
||||
public:
|
||||
using RequestType = ReqGetRoomSummaries;
|
||||
using ResponseType = ResGetRoomSummaries;
|
||||
|
||||
GetRoomSummaries(GatewayClient* client, const RequestType& request, ResponseType& response);
|
||||
|
||||
private:
|
||||
ChatRoomService* roomService_;
|
||||
};
|
||||
@@ -0,0 +1,22 @@
|
||||
#include "IgnoreStatus.hpp"
|
||||
|
||||
#include "ChatAvatarService.hpp"
|
||||
#include "GatewayClient.hpp"
|
||||
#include "GatewayNode.hpp"
|
||||
#include "StringUtils.hpp"
|
||||
|
||||
#include "easylogging++.h"
|
||||
|
||||
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;
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "ChatAvatar.hpp"
|
||||
#include "ChatEnums.hpp"
|
||||
|
||||
class ChatAvatarService;
|
||||
class ChatRoomService;
|
||||
class GatewayClient;
|
||||
|
||||
/** Begin IGNORESTATUS */
|
||||
|
||||
struct ReqIgnoreStatus {
|
||||
const ChatRequestType type = ChatRequestType::IGNORESTATUS;
|
||||
uint32_t track;
|
||||
uint32_t srcAvatarId;
|
||||
std::u16string srcAddress;
|
||||
};
|
||||
|
||||
template <typename StreamT>
|
||||
void read(StreamT& ar, ReqIgnoreStatus& data) {
|
||||
read(ar, data.track);
|
||||
read(ar, data.srcAvatarId);
|
||||
read(ar, data.srcAddress);
|
||||
}
|
||||
|
||||
/** Begin IGNORESTATUS */
|
||||
|
||||
struct ResIgnoreStatus {
|
||||
ResIgnoreStatus(uint32_t track_)
|
||||
: track{track_}
|
||||
, result{ChatResultCode::SUCCESS} {}
|
||||
|
||||
const ChatResponseType type = ChatResponseType::IGNORESTATUS;
|
||||
uint32_t track;
|
||||
ChatResultCode result;
|
||||
const ChatAvatar* srcAvatar;
|
||||
};
|
||||
|
||||
template <typename StreamT>
|
||||
void write(StreamT& ar, const ResIgnoreStatus& data) {
|
||||
write(ar, data.type);
|
||||
write(ar, data.track);
|
||||
write(ar, data.result);
|
||||
|
||||
if (data.result == ChatResultCode::SUCCESS && data.srcAvatar) {
|
||||
const auto& ignored = data.srcAvatar->GetIgnoreList();
|
||||
|
||||
write(ar, static_cast<uint32_t>(ignored.size()));
|
||||
for (auto& ignoredContact : ignored) {
|
||||
write(ar, ignoredContact);
|
||||
}
|
||||
} else {
|
||||
write(ar, static_cast<uint32_t>(0));
|
||||
}
|
||||
}
|
||||
|
||||
class IgnoreStatus {
|
||||
public:
|
||||
using RequestType = ReqIgnoreStatus;
|
||||
using ResponseType = ResIgnoreStatus;
|
||||
|
||||
IgnoreStatus(GatewayClient* client, const RequestType& request, ResponseType& response);
|
||||
|
||||
private:
|
||||
ChatAvatarService* avatarService_;
|
||||
};
|
||||
@@ -0,0 +1,39 @@
|
||||
#include "KickAvatar.hpp"
|
||||
|
||||
#include "ChatAvatarService.hpp"
|
||||
#include "ChatRoomService.hpp"
|
||||
#include "GatewayClient.hpp"
|
||||
#include "GatewayNode.hpp"
|
||||
#include "StringUtils.hpp"
|
||||
|
||||
#include "easylogging++.h"
|
||||
|
||||
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);
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "ChatEnums.hpp"
|
||||
|
||||
class ChatAvatarService;
|
||||
class ChatRoomService;
|
||||
class GatewayClient;
|
||||
|
||||
/** Begin KICKAVATAR */
|
||||
|
||||
struct ReqKickAvatar {
|
||||
const ChatRequestType type = ChatRequestType::KICKAVATAR;
|
||||
uint32_t track;
|
||||
uint32_t srcAvatarId;
|
||||
std::u16string destAvatarName;
|
||||
std::u16string destAvatarAddress;
|
||||
std::u16string destRoomAddress;
|
||||
std::u16string srcAddress;
|
||||
};
|
||||
|
||||
template <typename StreamT>
|
||||
void read(StreamT& ar, ReqKickAvatar& data) {
|
||||
read(ar, data.track);
|
||||
read(ar, data.srcAvatarId);
|
||||
read(ar, data.destAvatarName);
|
||||
read(ar, data.destAvatarAddress);
|
||||
read(ar, data.destRoomAddress);
|
||||
read(ar, data.srcAddress);
|
||||
}
|
||||
|
||||
/** Begin KICKAVATAR */
|
||||
|
||||
struct ResKickAvatar {
|
||||
ResKickAvatar(uint32_t track_)
|
||||
: track{track_}
|
||||
, result{ChatResultCode::SUCCESS} {}
|
||||
|
||||
const ChatResponseType type = ChatResponseType::KICKAVATAR;
|
||||
uint32_t track;
|
||||
ChatResultCode result;
|
||||
uint32_t destRoomId;
|
||||
};
|
||||
|
||||
template <typename StreamT>
|
||||
void write(StreamT& ar, const ResKickAvatar& data) {
|
||||
write(ar, data.type);
|
||||
write(ar, data.track);
|
||||
write(ar, data.result);
|
||||
write(ar, data.destRoomId);
|
||||
}
|
||||
|
||||
class KickAvatar {
|
||||
public:
|
||||
using RequestType = ReqKickAvatar;
|
||||
using ResponseType = ResKickAvatar;
|
||||
|
||||
KickAvatar(GatewayClient* client, const RequestType& request, ResponseType& response);
|
||||
|
||||
private:
|
||||
ChatAvatarService* avatarService_;
|
||||
ChatRoomService* roomService_;
|
||||
};
|
||||
@@ -0,0 +1,31 @@
|
||||
#include "LeaveRoom.hpp"
|
||||
|
||||
#include "ChatAvatarService.hpp"
|
||||
#include "ChatRoomService.hpp"
|
||||
#include "GatewayClient.hpp"
|
||||
#include "GatewayNode.hpp"
|
||||
|
||||
#include "easylogging++.h"
|
||||
|
||||
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());
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "ChatEnums.hpp"
|
||||
|
||||
class ChatAvatarService;
|
||||
class ChatRoomService;
|
||||
class GatewayClient;
|
||||
|
||||
/** Begin LEAVEROOM */
|
||||
|
||||
struct ReqLeaveRoom {
|
||||
const ChatRequestType type = ChatRequestType::LEAVEROOM;
|
||||
uint32_t track;
|
||||
uint32_t srcAvatarId;
|
||||
std::u16string roomAddress;
|
||||
std::u16string srcAddress;
|
||||
};
|
||||
|
||||
template <typename StreamT>
|
||||
void read(StreamT& ar, ReqLeaveRoom& data) {
|
||||
read(ar, data.track);
|
||||
read(ar, data.srcAvatarId);
|
||||
read(ar, data.roomAddress);
|
||||
read(ar, data.srcAddress);
|
||||
}
|
||||
|
||||
/** Begin LEAVEROOM */
|
||||
|
||||
struct ResLeaveRoom {
|
||||
ResLeaveRoom(uint32_t track_)
|
||||
: track{track_}
|
||||
, result{ChatResultCode::SUCCESS} {}
|
||||
|
||||
const ChatResponseType type = ChatResponseType::LEAVEROOM;
|
||||
uint32_t track;
|
||||
ChatResultCode result;
|
||||
uint32_t roomId;
|
||||
};
|
||||
|
||||
template <typename StreamT>
|
||||
void write(StreamT& ar, const ResLeaveRoom& data) {
|
||||
write(ar, data.type);
|
||||
write(ar, data.track);
|
||||
write(ar, data.result);
|
||||
write(ar, data.roomId);
|
||||
}
|
||||
|
||||
class LeaveRoom {
|
||||
public:
|
||||
using RequestType = ReqLeaveRoom;
|
||||
using ResponseType = ResLeaveRoom;
|
||||
|
||||
LeaveRoom(GatewayClient* client, const RequestType& request, ResponseType& response);
|
||||
|
||||
private:
|
||||
ChatAvatarService* avatarService_;
|
||||
ChatRoomService* roomService_;
|
||||
};
|
||||
@@ -0,0 +1,36 @@
|
||||
|
||||
#include "LoginAvatar.hpp"
|
||||
|
||||
#include "ChatAvatarService.hpp"
|
||||
#include "ChatRoomService.hpp"
|
||||
#include "GatewayClient.hpp"
|
||||
#include "GatewayNode.hpp"
|
||||
#include "StringUtils.hpp"
|
||||
|
||||
#include "easylogging++.h"
|
||||
|
||||
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;
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "ChatAvatar.hpp"
|
||||
#include "ChatEnums.hpp"
|
||||
|
||||
class ChatAvatarService;
|
||||
class ChatRoomService;
|
||||
class GatewayClient;
|
||||
|
||||
/** Begin LOGINAVATAR */
|
||||
|
||||
struct ReqLoginAvatar {
|
||||
const ChatRequestType type = ChatRequestType::LOGINAVATAR;
|
||||
uint32_t track;
|
||||
uint32_t userId;
|
||||
std::u16string name;
|
||||
std::u16string address;
|
||||
std::u16string loginLocation;
|
||||
int32_t loginPriority;
|
||||
int32_t loginAttributes;
|
||||
};
|
||||
|
||||
template <typename StreamT>
|
||||
void read(StreamT& ar, ReqLoginAvatar& data) {
|
||||
read(ar, data.track);
|
||||
read(ar, data.userId);
|
||||
read(ar, data.name);
|
||||
read(ar, data.address);
|
||||
read(ar, data.loginLocation);
|
||||
read(ar, data.loginPriority);
|
||||
read(ar, data.loginAttributes);
|
||||
}
|
||||
|
||||
/** Begin LOGINAVATAR */
|
||||
|
||||
struct ResLoginAvatar {
|
||||
explicit ResLoginAvatar(uint32_t track_)
|
||||
: track{track_}
|
||||
, result{ChatResultCode::SUCCESS} {}
|
||||
|
||||
const ChatResponseType type = ChatResponseType::LOGINAVATAR;
|
||||
uint32_t track;
|
||||
ChatResultCode result;
|
||||
const ChatAvatar* avatar;
|
||||
};
|
||||
|
||||
template <typename StreamT>
|
||||
void write(StreamT& ar, const ResLoginAvatar& data) {
|
||||
write(ar, data.type);
|
||||
write(ar, data.track);
|
||||
write(ar, data.result);
|
||||
|
||||
if (data.result == ChatResultCode::SUCCESS) {
|
||||
write(ar, data.avatar);
|
||||
}
|
||||
}
|
||||
|
||||
class LoginAvatar {
|
||||
public:
|
||||
using RequestType = ReqLoginAvatar;
|
||||
using ResponseType = ResLoginAvatar;
|
||||
|
||||
LoginAvatar(GatewayClient* client, const RequestType& request, ResponseType& response);
|
||||
|
||||
private:
|
||||
ChatAvatarService* avatarService_;
|
||||
ChatRoomService* roomService_;
|
||||
};
|
||||
@@ -0,0 +1,28 @@
|
||||
#include "LogoutAvatar.hpp"
|
||||
|
||||
#include "ChatAvatarService.hpp"
|
||||
#include "ChatRoomService.hpp"
|
||||
#include "GatewayClient.hpp"
|
||||
#include "GatewayNode.hpp"
|
||||
|
||||
#include "easylogging++.h"
|
||||
|
||||
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 : avatar->GetJoinedRooms()) {
|
||||
auto addresses = room->GetConnectedAddresses();
|
||||
room->LeaveRoom(avatar);
|
||||
|
||||
client->SendLeaveRoomUpdate(addresses, avatar->GetAvatarId(), room->GetRoomId());
|
||||
}
|
||||
|
||||
client->SendFriendLogoutUpdates(avatar);
|
||||
|
||||
avatarService_->LogoutAvatar(avatar);
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "ChatEnums.hpp"
|
||||
|
||||
class ChatAvatarService;
|
||||
class ChatRoomService;
|
||||
class GatewayClient;
|
||||
|
||||
/** Begin LOGOUTAVATAR */
|
||||
|
||||
struct ReqLogoutAvatar {
|
||||
const ChatRequestType type = ChatRequestType::LOGOUTAVATAR;
|
||||
uint32_t track;
|
||||
uint32_t avatarId;
|
||||
};
|
||||
|
||||
template <typename StreamT>
|
||||
void read(StreamT& ar, ReqLogoutAvatar& data) {
|
||||
read(ar, data.track);
|
||||
read(ar, data.avatarId);
|
||||
}
|
||||
|
||||
/** Begin LOGOUTAVATAR */
|
||||
|
||||
struct ResLogoutAvatar {
|
||||
explicit ResLogoutAvatar(uint32_t track_)
|
||||
: track{track_}
|
||||
, result{ChatResultCode::SUCCESS} {}
|
||||
|
||||
const ChatResponseType type = ChatResponseType::LOGOUTAVATAR;
|
||||
uint32_t track;
|
||||
ChatResultCode result;
|
||||
};
|
||||
|
||||
template <typename StreamT>
|
||||
void write(StreamT& ar, const ResLogoutAvatar& data) {
|
||||
write(ar, data.type);
|
||||
write(ar, data.track);
|
||||
write(ar, data.result);
|
||||
}
|
||||
|
||||
|
||||
class LogoutAvatar {
|
||||
public:
|
||||
using RequestType = ReqLogoutAvatar;
|
||||
using ResponseType = ResLogoutAvatar;
|
||||
|
||||
LogoutAvatar(GatewayClient* client, const RequestType& request, ResponseType& response);
|
||||
|
||||
private:
|
||||
ChatAvatarService* avatarService_;
|
||||
ChatRoomService* roomService_;
|
||||
};
|
||||
@@ -0,0 +1,18 @@
|
||||
#include "RegistrarGetChatServer.hpp"
|
||||
|
||||
#include "ChatAvatarService.hpp"
|
||||
#include "ChatRoomService.hpp"
|
||||
#include "RegistrarClient.hpp"
|
||||
#include "RegistrarNode.hpp"
|
||||
#include "StationChatConfig.hpp"
|
||||
#include "StringUtils.hpp"
|
||||
|
||||
#include "easylogging++.h"
|
||||
|
||||
|
||||
RegistrarGetChatServer::RegistrarGetChatServer(RegistrarClient* client, const RequestType & request, ResponseType & response) {
|
||||
auto& config = client->GetNode()->GetConfig();
|
||||
|
||||
response.hostname = ToWideString(config.gatewayAddress);
|
||||
response.port = config.gatewayPort;
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "ChatEnums.hpp"
|
||||
|
||||
class RegistrarClient;
|
||||
|
||||
/** Begin REGISTRAR_GETCHATSERVER */
|
||||
|
||||
struct ReqRegistrarGetChatServer {
|
||||
const ChatRequestType type = ChatRequestType::REGISTRAR_GETCHATSERVER;
|
||||
uint32_t track;
|
||||
std::u16string hostname;
|
||||
uint16_t port;
|
||||
};
|
||||
|
||||
template <typename StreamT>
|
||||
void read(StreamT& ar, ReqRegistrarGetChatServer& data) {
|
||||
read(ar, data.track);
|
||||
read(ar, data.hostname);
|
||||
read(ar, data.port);
|
||||
}
|
||||
|
||||
/** Begin REGISTRAR_GETCHATSERVER */
|
||||
|
||||
struct ResRegistrarGetChatServer {
|
||||
ResRegistrarGetChatServer(
|
||||
uint32_t track_)
|
||||
: track{track_}
|
||||
, result{ChatResultCode::SUCCESS} {}
|
||||
|
||||
const ChatResponseType type = ChatResponseType::REGISTRAR_GETCHATSERVER;
|
||||
uint32_t track;
|
||||
ChatResultCode result;
|
||||
std::u16string hostname;
|
||||
uint16_t port;
|
||||
};
|
||||
|
||||
template <typename StreamT>
|
||||
void write(StreamT& ar, const ResRegistrarGetChatServer& data) {
|
||||
write(ar, data.type);
|
||||
write(ar, data.track);
|
||||
write(ar, data.result);
|
||||
write(ar, data.hostname);
|
||||
write(ar, data.port);
|
||||
}
|
||||
|
||||
class RegistrarGetChatServer {
|
||||
public:
|
||||
using RequestType = ReqRegistrarGetChatServer;
|
||||
using ResponseType = ResRegistrarGetChatServer;
|
||||
|
||||
RegistrarGetChatServer(RegistrarClient* client, const RequestType& request, ResponseType& response);
|
||||
};
|
||||
@@ -0,0 +1,38 @@
|
||||
#include "RemoveBan.hpp"
|
||||
|
||||
#include "ChatAvatarService.hpp"
|
||||
#include "ChatRoomService.hpp"
|
||||
#include "GatewayClient.hpp"
|
||||
#include "GatewayNode.hpp"
|
||||
#include "StringUtils.hpp"
|
||||
|
||||
#include "easylogging++.h"
|
||||
|
||||
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());
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "ChatEnums.hpp"
|
||||
|
||||
class ChatAvatarService;
|
||||
class ChatRoomService;
|
||||
class GatewayClient;
|
||||
|
||||
/** Begin REMOVEBAN */
|
||||
|
||||
struct ReqRemoveBan {
|
||||
const ChatRequestType type = ChatRequestType::REMOVEBAN;
|
||||
uint32_t track;
|
||||
uint32_t srcAvatarId;
|
||||
std::u16string destAvatarName;
|
||||
std::u16string destAvatarAddress;
|
||||
std::u16string destRoomAddress;
|
||||
std::u16string srcAddress;
|
||||
};
|
||||
|
||||
template <typename StreamT>
|
||||
void read(StreamT& ar, ReqRemoveBan& data) {
|
||||
read(ar, data.track);
|
||||
read(ar, data.srcAvatarId);
|
||||
read(ar, data.destAvatarName);
|
||||
read(ar, data.destAvatarAddress);
|
||||
read(ar, data.destRoomAddress);
|
||||
read(ar, data.srcAddress);
|
||||
}
|
||||
|
||||
/** Begin REMOVEBAN */
|
||||
|
||||
struct ResRemoveBan {
|
||||
explicit ResRemoveBan(uint32_t track_)
|
||||
: track{track_}
|
||||
, result{ChatResultCode::SUCCESS} {}
|
||||
|
||||
const ChatResponseType type = ChatResponseType::REMOVEBAN;
|
||||
uint32_t track;
|
||||
ChatResultCode result;
|
||||
uint32_t destRoomId;
|
||||
};
|
||||
|
||||
template <typename StreamT>
|
||||
void write(StreamT& ar, const ResRemoveBan& data) {
|
||||
write(ar, data.type);
|
||||
write(ar, data.track);
|
||||
write(ar, data.result);
|
||||
write(ar, data.destRoomId);
|
||||
}
|
||||
|
||||
class RemoveBan {
|
||||
public:
|
||||
using RequestType = ReqRemoveBan;
|
||||
using ResponseType = ResRemoveBan;
|
||||
|
||||
RemoveBan(GatewayClient* client, const RequestType& request, ResponseType& response);
|
||||
|
||||
private:
|
||||
ChatAvatarService* avatarService_;
|
||||
ChatRoomService* roomService_;
|
||||
};
|
||||
@@ -0,0 +1,28 @@
|
||||
#include "RemoveFriend.hpp"
|
||||
|
||||
#include "ChatAvatarService.hpp"
|
||||
#include "GatewayClient.hpp"
|
||||
#include "GatewayNode.hpp"
|
||||
#include "StringUtils.hpp"
|
||||
|
||||
#include "easylogging++.h"
|
||||
|
||||
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);
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "ChatEnums.hpp"
|
||||
|
||||
class ChatAvatarService;
|
||||
class ChatRoomService;
|
||||
class GatewayClient;
|
||||
|
||||
/** Begin REMOVEFRIEND */
|
||||
|
||||
struct ReqRemoveFriend {
|
||||
const ChatRequestType type = ChatRequestType::REMOVEFRIEND;
|
||||
uint32_t track;
|
||||
uint32_t srcAvatarId;
|
||||
std::u16string destName;
|
||||
std::u16string destAddress;
|
||||
std::u16string srcAddress;
|
||||
};
|
||||
|
||||
template <typename StreamT>
|
||||
void read(StreamT& ar, ReqRemoveFriend& data) {
|
||||
read(ar, data.track);
|
||||
read(ar, data.srcAvatarId);
|
||||
read(ar, data.destName);
|
||||
read(ar, data.destAddress);
|
||||
read(ar, data.srcAddress);
|
||||
}
|
||||
|
||||
/** Begin REMOVEFRIEND */
|
||||
|
||||
struct ResRemoveFriend {
|
||||
ResRemoveFriend(uint32_t track_)
|
||||
: track{track_}
|
||||
, result{ChatResultCode::SUCCESS} {}
|
||||
|
||||
const ChatResponseType type = ChatResponseType::REMOVEFRIEND;
|
||||
uint32_t track;
|
||||
ChatResultCode result;
|
||||
};
|
||||
|
||||
template <typename StreamT>
|
||||
void write(StreamT& ar, const ResRemoveFriend& data) {
|
||||
write(ar, data.type);
|
||||
write(ar, data.track);
|
||||
write(ar, data.result);
|
||||
}
|
||||
|
||||
class RemoveFriend {
|
||||
public:
|
||||
using RequestType = ReqRemoveFriend;
|
||||
using ResponseType = ResRemoveFriend;
|
||||
|
||||
RemoveFriend(GatewayClient* client, const RequestType& request, ResponseType& response);
|
||||
|
||||
private:
|
||||
ChatAvatarService* avatarService_;
|
||||
};
|
||||
@@ -0,0 +1,27 @@
|
||||
#include "RemoveIgnore.hpp"
|
||||
|
||||
#include "ChatAvatarService.hpp"
|
||||
#include "GatewayClient.hpp"
|
||||
#include "GatewayNode.hpp"
|
||||
#include "StringUtils.hpp"
|
||||
|
||||
#include "easylogging++.h"
|
||||
|
||||
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);
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user