diff --git a/src/config.cpp b/src/config.cpp index ac321e4..04f2832 100644 --- a/src/config.cpp +++ b/src/config.cpp @@ -22,6 +22,7 @@ along with this program. If not, see . #include "logger.h" #include "versioninformation.h" #include "fsconstants.h" +#include "ircloggerlist.h" #include #include @@ -217,6 +218,8 @@ bool Config::initFromJson(const QJsonObject &config, QString* errorString) channel.push_front('#'); } network->channels.push_back(channel); + + IRCLoggerList::get(network->networkName, channel); // Create logger instanse for date indexing at start } if (network->channels.isEmpty()) { diff --git a/src/httpserver.cpp b/src/httpserver.cpp index 5b23c17..53fdef5 100644 --- a/src/httpserver.cpp +++ b/src/httpserver.cpp @@ -32,10 +32,10 @@ HttpServer::HttpServer(QObject *parent) : QTcpServer(parent) if (not listen(QHostAddress(Config::webUiAddress()), Config::webUiPort())) { - qFatal("%s", QString("HTTP server not binded at " + Config::webUiAddress() + ":" + QString::number(Config::webUiPort())).toStdString().c_str()); + qFatal("%s", QString("[WebUI] HTTP server not binded at " + Config::webUiAddress() + ":" + QString::number(Config::webUiPort())).toStdString().c_str()); } - qInfo().noquote() << "HTTP server started at" << Config::webUiAddress() + ":" + QString::number( Config::webUiPort() ); - qInfo().noquote() << "HTTP server threads:" << m_pool->maxThreadCount(); + qInfo().noquote() << "[WebUI] HTTP server started at" << Config::webUiAddress() + ":" + QString::number( Config::webUiPort() ); + qInfo().noquote() << "[WebUI] HTTP server threads:" << m_pool->maxThreadCount(); } HttpServer::~HttpServer() @@ -47,7 +47,7 @@ HttpServer::~HttpServer() m_pool->clear(); if (not m_pool->waitForDone(100)) { - qWarning() << "Thread pool of HTTP server not finished at 100ms"; + qWarning() << "[WebUI] Thread pool of HTTP server not finished at 100ms"; } m_pool->deleteLater(); } diff --git a/src/httpserversocket.cpp b/src/httpserversocket.cpp index c6ba3ba..6d98e78 100644 --- a/src/httpserversocket.cpp +++ b/src/httpserversocket.cpp @@ -27,8 +27,10 @@ along with this program. If not, see . #include -#define LOG_WARN qWarning().noquote() << "HttpServerSocket:" -#define LOG_DEBUG qDebug().noquote() << "HttpServerSocket:" +#define LOG_CRIT qCritical().noquote() << "[WebUI] HttpServerSocket:" +#define LOG_WARN qWarning().noquote() << "[WebUI] HttpServerSocket:" +#define LOG_INFO qInfo().noquote() << "[WebUI] HttpServerSocket:" +#define LOG_DEBUG qDebug().noquote() << "[WebUI] HttpServerSocket:" constexpr const int VALUE_BEFORE_SPACE_MAX_SIZE = 300; constexpr const int HEADERS_MAX_SIZE = 1000; @@ -55,7 +57,7 @@ void HttpServerSocket::run() { if (not m_socketDescriptor) { - qCritical() << "HttpServerSocket::run() called with invalid socket descriptor"; + LOG_CRIT << "run() called with invalid socket descriptor"; return; } diff --git a/src/irclogger.cpp b/src/irclogger.cpp index 254eb00..2b0939c 100644 --- a/src/irclogger.cpp +++ b/src/irclogger.cpp @@ -24,6 +24,8 @@ along with this program. If not, see . #include #include +#include +#include constexpr const int CACHE_SIZE = 64; @@ -40,6 +42,16 @@ IRCLogger::IRCLogger(const QString &network, const QString &channel) : qCritical() << "Can't create chat log directory:" << m_rootDir; } } + else + { + doDateIndex(); + } +} + +QList IRCLogger::dateIndex() const +{ + QMutexLocker lock (&m_dateIndexMtx); + return m_dateIndex; } void IRCLogger::addMessage(const QString &sender, const QString &message) @@ -59,6 +71,7 @@ void IRCLogger::addMessage(const QString &sender, const QString &message) qCritical() << "IRCLogger::addMessage can't create directory:" << dir; return; } + doDateIndex(); } QFile file (datePath(currentDate)); @@ -135,6 +148,78 @@ QList> IRCLogger::getMessages(const QDateTime return result; } +void IRCLogger::doDateIndex() +{ + QMutexLocker lock (&m_dateIndexMtx); + + qDebug().noquote() << "["+m_network+"] ["+m_channel+"]" << "Indexing log dates in" << m_rootDir; + + m_dateIndex.clear(); + + quint64 yearsCounter = 0; + quint64 monthCounter = 0; + quint64 daysCounter = 0; + + QDirIterator yearIterator(m_rootDir); + while (yearIterator.hasNext()) + { + auto year = QFileInfo(yearIterator.next()); + if (year.fileName() == "." or year.fileName() == ".." or not year.isDir()) continue; + bool converted = false; + int16_t yearNumber = year.fileName().toShort(&converted); + if (not converted) continue; + + m_dateIndex.push_front({yearNumber, {}}); + yearsCounter++; + } + std::sort(m_dateIndex.begin(), m_dateIndex.end()); + + for (auto indexIterator = m_dateIndex.begin(); indexIterator != m_dateIndex.end(); indexIterator++) + { + QDirIterator monthIterator(m_rootDir + "/" + QString::number(indexIterator->first)); + while (monthIterator.hasNext()) + { + auto month = QFileInfo(monthIterator.next()); + if (month.fileName() == "." or month.fileName() == ".." or not month.isDir()) continue; + bool converted = false; + int8_t monthNumber = month.fileName().toShort(&converted); + if (not converted) continue; + + indexIterator->second.push_back({monthNumber, {}}); + monthCounter++; + } + std::sort(indexIterator->second.begin(), indexIterator->second.end()); + } + + for (auto indexIterator = m_dateIndex.begin(); indexIterator != m_dateIndex.end(); indexIterator++) + { + for (auto monthIterator = indexIterator->second.begin(); monthIterator != indexIterator->second.end(); monthIterator++) + { + QString monthFolder = QString::number(monthIterator->first); + if (monthFolder.size() < 2) monthFolder.push_front('0'); + + QDirIterator dayIterator(m_rootDir + "/" + QString::number(indexIterator->first) + "/" + monthFolder); + while (dayIterator.hasNext()) + { + auto day = QFileInfo(dayIterator.next()); + if (not day.fileName().endsWith(".txt") or not day.isFile()) continue; + QString fileName = day.fileName(); + static const QRegularExpression rgxOnlyNumbers("[^0-9]"); + fileName.remove(rgxOnlyNumbers); + bool converted = false; + int8_t dayNumber = fileName.toShort(&converted); + if (not converted) continue; + + monthIterator->second.push_back(dayNumber); + daysCounter++; + } + std::sort(monthIterator->second.begin(), monthIterator->second.end()); + } + } + + qInfo().noquote() << "["+m_network+"] ["+m_channel+"]" << "Log contains" << yearsCounter << "years," << monthCounter << "months and" << daysCounter << "days"; +} + QString IRCLogger::dateDir(const QDateTime &date) { return m_rootDir + "/" + date.toString("yyyy/MM"); diff --git a/src/irclogger.h b/src/irclogger.h index 907fa65..b729f1e 100644 --- a/src/irclogger.h +++ b/src/irclogger.h @@ -114,22 +114,32 @@ public: }; + struct DateIndex + { + + }; + + using Month = QPair>; // Month number, days list + using Year = QPair>; // Year number, months list + IRCLogger(const QString& network, const QString& channel); QString network() const { return m_network; } QString channel() const { return m_channel; } + QList dateIndex() const; void addMessage(const QString& sender, const QString& message); QList> getMessages(const QDateTime& date, const quint64* beginId = nullptr, const quint64* endId = nullptr); private: + void doDateIndex(); QString dateDir(const QDateTime& date); QString datePath(const QDateTime& date); + mutable QMutex m_dateIndexMtx; + QList m_dateIndex; Cache m_cache; QMutex m_fileIOmtx; const QString m_network; const QString m_channel; const QString m_rootDir; - - }; diff --git a/src/ircloggerlist.cpp b/src/ircloggerlist.cpp index 89790fe..a36455b 100644 --- a/src/ircloggerlist.cpp +++ b/src/ircloggerlist.cpp @@ -34,6 +34,6 @@ QSharedPointer IRCLoggerList::get(const QString &network, const QStri QSharedPointer newLogger (new IRCLogger(network, channel)); m_data.insert(ident, newLogger); - qDebug().noquote() << "["+network+"]" << "Logger for" << channel << "initialized. Global total loggers count:" << m_data.size(); + qDebug().noquote() << "["+network+"] ["+channel+"] Logger initialized. Global loggers count:" << m_data.size(); return newLogger; }