TTW_Bot/user_manager.cpp

334 lines
8.6 KiB
C++
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "user_manager.h"
#include "twitchmessage.h"
#include <QFile>
#include <QJsonDocument>
#include <QJsonArray>
#include <QJsonObject>
#include <QDateTime>
#include <QDebug>
#include <QRandomGenerator>
UserManager::UserManager(QObject *parent)
: QObject(parent)
, m_totalMessages(0)
, m_maxUsers(10000)
, m_cleanupInterval(60)
, m_lastCleanup(QDateTime::currentDateTime())
{
}
UserManager::~UserManager()
{
clear();
}
QString UserManager::checkUser(const QString &displayName, const TwitchMessage &msg)
{
QString normalizedDisplayName = displayName.trimmed();
// Проверяем, есть ли пользователь
if (m_users.contains(normalizedDisplayName)) {
User &user = m_users[normalizedDisplayName];
// Обновляем из сообщения, если передано
if (!msg.displayName.isEmpty()) {
updateUserFromMessage(normalizedDisplayName, msg);
}
emit userMessageCountChanged(user.id, user.messageCount);
emit userUpdated(user);
return user.id;
}
// Пользователя нет - создаем нового
User newUser;
if (!msg.displayName.isEmpty()) {
// Заполняем из сообщения
newUser.updateFromTwitchMessage(msg);
} else {
// Минимальные данные
newUser.displayName = normalizedDisplayName;
newUser.login = normalizedDisplayName.toLower();
newUser.id = generateUserId();
}
// Добавляем в базу
addUser(newUser);
return newUser.id;
}
User* UserManager::findUser(const QString &displayName)
{
if (m_users.contains(displayName)) {
return &m_users[displayName];
}
// Пробуем найти по login
if (m_loginToDisplayName.contains(displayName.toLower())) {
QString actualDisplayName = m_loginToDisplayName[displayName.toLower()];
return &m_users[actualDisplayName];
}
return nullptr;
}
User* UserManager::findUserById(const QString &userId)
{
if (m_userIdToDisplayName.contains(userId)) {
QString displayName = m_userIdToDisplayName[userId];
return &m_users[displayName];
}
return nullptr;
}
void UserManager::updateUserFromMessage(const QString &displayName, const TwitchMessage &msg)
{
if (!m_users.contains(displayName)) {
return;
}
User &user = m_users[displayName];
// ВАЖНО: передаем displayName как параметр, а не берем из msg
// если displayName из параметра отличается от msg.displayName,
// нам нужно обновить ключ в map
QString newDisplayName = msg.displayName;
if (!newDisplayName.isEmpty() && newDisplayName != displayName) {
// Display name изменился - нужно переместить пользователя
User userCopy = user;
userCopy.updateFromTwitchMessage(msg);
// Удаляем старую запись
removeUser(displayName);
// Добавляем с новым displayName
userCopy.displayName = newDisplayName;
addUser(userCopy);
return;
}
// Display name не изменился - просто обновляем
user.updateFromTwitchMessage(msg);
// Обновляем индексы
updateIndexes(displayName, user);
emit userUpdated(user);
}
void UserManager::updateUserStatus(const QString &userId, bool isMod, bool isVIP, bool isSubscriber)
{
User* user = findUserById(userId);
if (user) {
user->isModerator = isMod;
user->isVIP = isVIP;
user->isSubscriber = isSubscriber;
emit userUpdated(*user);
}
}
void UserManager::addUser(const User &user)
{
QString displayName = user.displayName;
if (displayName.isEmpty()) {
qWarning() << "Cannot add user with empty display name";
return;
}
// Очистка старых пользователей, если нужно
if (m_users.size() >= m_maxUsers) {
cleanupOldUsers();
}
m_users[displayName] = user;
updateIndexes(displayName, user);
emit userAdded(user);
}
void UserManager::removeUser(const QString &displayName)
{
if (m_users.contains(displayName)) {
User user = m_users[displayName];
// Удаляем из индексов
m_userIdToDisplayName.remove(user.id);
m_loginToDisplayName.remove(user.login.toLower());
// Удаляем из основного списка
m_users.remove(displayName);
emit userRemoved(user.id, displayName); // Передаем и id, и displayName
}
}
void UserManager::clear()
{
m_users.clear();
m_userIdToDisplayName.clear();
m_loginToDisplayName.clear();
m_totalMessages = 0;
}
QVector<User*> UserManager::getModerators() const
{
QVector<User*> moderators;
for (auto it = m_users.begin(); it != m_users.end(); ++it) {
if (it.value().isModerator) {
moderators.append(const_cast<User*>(&it.value()));
}
}
return moderators;
}
QVector<User*> UserManager::getVIPs() const
{
QVector<User*> vips;
for (auto it = m_users.begin(); it != m_users.end(); ++it) {
if (it.value().isVIP) {
vips.append(const_cast<User*>(&it.value()));
}
}
return vips;
}
QVector<User*> UserManager::getSubscribers() const
{
QVector<User*> subscribers;
for (auto it = m_users.begin(); it != m_users.end(); ++it) {
if (it.value().isSubscriber) {
subscribers.append(const_cast<User*>(&it.value()));
}
}
return subscribers;
}
QVector<User*> UserManager::getActiveUsers(int minutes) const
{
QVector<User*> activeUsers;
QDateTime cutoff = QDateTime::currentDateTime().addSecs(-minutes * 60);
for (auto it = m_users.begin(); it != m_users.end(); ++it) {
if (it.value().lastMessageTime >= cutoff) {
activeUsers.append(const_cast<User*>(&it.value()));
}
}
return activeUsers;
}
void UserManager::updateIndexes(const QString &displayName, const User &user)
{
if (!user.id.isEmpty()) {
m_userIdToDisplayName[user.id] = displayName;
}
if (!user.login.isEmpty()) {
m_loginToDisplayName[user.login.toLower()] = displayName;
}
}
void UserManager::cleanupOldUsers()
{
QDateTime cutoff = QDateTime::currentDateTime().addDays(-7); // Удаляем неактивных неделю
QVector<QString> usersToRemove;
for (auto it = m_users.begin(); it != m_users.end(); ++it) {
// Удаляем если:
// 1. Не писал больше недели
// 2. Не модератор/VIP/подписчик
if (it.value().lastMessageTime < cutoff &&
!it.value().isModerator &&
!it.value().isVIP &&
!it.value().isSubscriber &&
it.value().messageCount < 5) { // И написано меньше 5 сообщений
usersToRemove.append(it.key());
}
}
for (const QString &displayName : usersToRemove) {
removeUser(displayName);
}
m_lastCleanup = QDateTime::currentDateTime();
}
int UserManager::getUserCount() const
{
return m_users.size();
}
int UserManager::getMessageCount() const
{
return m_totalMessages;
}
QVector<User*> UserManager::findUsersByLogin(const QString &login)
{
QVector<User*> result;
QString lowerLogin = login.toLower();
for (auto it = m_users.begin(); it != m_users.end(); ++it) {
if (it.value().login.toLower().contains(lowerLogin)) {
result.append(&it.value());
}
}
return result;
}
User* UserManager::getUserByIndex(const QString& userID)
{
auto it = m_users.find(userID);
if (it != m_users.end()) {
return &it.value();
}
return nullptr;
}
const User* UserManager::getRandomUser() const {
if (m_users.isEmpty()) {
return nullptr;
}
QList<QString> keys = m_users.keys();
int randomIndex = QRandomGenerator::global()->bounded(keys.size());
// Возвращаем указатель на существующий объект в контейнере
const auto it = m_users.constFind(keys[randomIndex]);
if (it != m_users.constEnd()) {
return &(it.value()); // Указатель на существующий объект
}
return nullptr;
}
const QMap<QString, User>& UserManager::getAllUsers() const
{
return m_users;
}
QString UserManager::generateUserId() const
{
return QString("user_%1").arg(QDateTime::currentMSecsSinceEpoch());
}