mirror of
https://github.com/SWG-Source/stationapi.git
synced 2026-07-14 23:07:34 -04:00
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
489 lines
16 KiB
C++
489 lines
16 KiB
C++
#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;
|
|
}
|