Files
stationapi/src/ChatAvatarService.cpp
T
apathy 68b60ccb8b 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
2016-07-26 19:58:52 -07:00

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;
}