This repository has been archived by the owner on Jun 15, 2020. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #24 from r52/client-log
Client log features
- Loading branch information
Showing
17 changed files
with
423 additions
and
40 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,179 @@ | ||
#include "clientmonitor.h" | ||
|
||
#include "pta_types.h" | ||
|
||
#include <QDebug> | ||
#include <QFileInfo> | ||
#include <QRegularExpression> | ||
#include <QSettings> | ||
#include <QTimer> | ||
|
||
using namespace std::chrono_literals; | ||
|
||
const std::chrono::milliseconds ClientMonitor::polling_rate = 350ms; | ||
|
||
ClientMonitor::ClientMonitor(QObject* parent) : QObject(parent), m_enabled(false), m_last_whisper(QString()) | ||
{ | ||
QSettings settings; | ||
|
||
QString logpath = settings.value(PTA_CONFIG_CLIENTLOG_PATH, QString()).toString(); | ||
|
||
if (logpath.isEmpty()) | ||
{ | ||
qInfo() << "Client.txt path not set. Client features disabled."; | ||
} | ||
else | ||
{ | ||
setPath(logpath); | ||
} | ||
} | ||
|
||
ClientMonitor::~ClientMonitor() | ||
{ | ||
m_watcher.reset(); | ||
} | ||
|
||
void ClientMonitor::setPath(QString logpath) | ||
{ | ||
if (logpath.isEmpty()) | ||
{ | ||
// If empty path, disable monitor | ||
m_enabled = false; | ||
|
||
// Clear file watcher | ||
if (m_watcher) | ||
{ | ||
m_watcher.reset(); | ||
} | ||
|
||
m_logpath.clear(); | ||
|
||
return; | ||
} | ||
|
||
if (!QFileInfo::exists(logpath)) | ||
{ | ||
qWarning() << "Client log file not found at" << logpath; | ||
return; | ||
} | ||
|
||
if (m_logpath == logpath) | ||
{ | ||
// Same file | ||
return; | ||
} | ||
|
||
m_logpath = logpath; | ||
|
||
// Pre-read size | ||
QFile log(m_logpath); | ||
|
||
if (!log.open(QIODevice::ReadOnly | QIODevice::Text)) | ||
{ | ||
qWarning() << "Cannot process client log file found at" << m_logpath; | ||
return; | ||
} | ||
|
||
m_lastpos = log.size(); | ||
|
||
log.close(); | ||
|
||
m_watcher.reset(new QTimer(this)); | ||
|
||
connect(m_watcher.get(), &QTimer::timeout, this, &ClientMonitor::processLogChange); | ||
m_watcher->start(polling_rate); | ||
|
||
m_enabled = true; | ||
|
||
qInfo() << "Client.txt set to" << m_logpath; | ||
} | ||
|
||
bool ClientMonitor::enabled() | ||
{ | ||
return m_enabled; | ||
} | ||
|
||
QString ClientMonitor::getLastWhisperer() | ||
{ | ||
return m_last_whisper; | ||
} | ||
|
||
void ClientMonitor::processLogLine(QString line) | ||
{ | ||
auto parts = line.splitRef("] ", QString::SkipEmptyParts); | ||
|
||
if (parts.size() < 2) | ||
{ | ||
// If not a game info line, skip | ||
return; | ||
} | ||
|
||
// Get last part | ||
auto ltxt = parts[parts.size() - 1].trimmed().toString(); | ||
|
||
if (ltxt.startsWith('@')) | ||
{ | ||
// Whisper | ||
|
||
// Remove whisper tags | ||
ltxt.remove(QRegularExpression("^@(From|To) (<\\S+> )?")); | ||
|
||
auto msgparts = ltxt.splitRef(": ", QString::SkipEmptyParts); | ||
|
||
if (msgparts.size() < 1) | ||
{ | ||
qWarning() << "Error parsing whisper text:" << ltxt; | ||
return; | ||
} | ||
|
||
auto pname = msgparts[0].toString(); | ||
|
||
m_last_whisper = pname; | ||
} | ||
} | ||
|
||
void ClientMonitor::processLogChange() | ||
{ | ||
if (!enabled()) | ||
{ | ||
// Shouldn't ever get here | ||
return; | ||
} | ||
|
||
QFile log(m_logpath); | ||
|
||
if (!log.open(QIODevice::ReadOnly | QIODevice::Text)) | ||
{ | ||
qWarning() << "Cannot process client log file found at" << m_logpath; | ||
return; | ||
} | ||
|
||
qint64 lastpos = log.size(); | ||
|
||
if (lastpos < m_lastpos) | ||
{ | ||
// File got reset, so reset our position too | ||
m_lastpos = lastpos; | ||
return; | ||
} | ||
|
||
if (lastpos == m_lastpos) | ||
{ | ||
// No change | ||
return; | ||
} | ||
|
||
// Start reading from | ||
log.seek(m_lastpos); | ||
|
||
QTextStream in(&log); | ||
while (!in.atEnd()) | ||
{ | ||
QString line = in.readLine(); | ||
processLogLine(line); | ||
} | ||
|
||
m_lastpos = lastpos; | ||
|
||
log.close(); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
#pragma once | ||
|
||
#include <chrono> | ||
|
||
#include <QObject> | ||
|
||
class QTimer; | ||
|
||
class ClientMonitor : public QObject | ||
{ | ||
Q_OBJECT | ||
|
||
public: | ||
ClientMonitor(QObject* parent = nullptr); | ||
~ClientMonitor(); | ||
|
||
void setPath(QString logpath); | ||
|
||
bool enabled(); | ||
|
||
QString getLastWhisperer(); | ||
|
||
private slots: | ||
void processLogChange(); | ||
void processLogLine(QString line); | ||
|
||
private: | ||
static const std::chrono::milliseconds polling_rate; | ||
|
||
// We are FORCED to use a polling technique for Client.txt because it doesn't flush AT ALL | ||
// unless the file is accessed externally. This renders functions like QFileSystemWatcher and | ||
// even the WinAPI ReadDirectoryChangesW UNUSABLE for our purposes :(. | ||
std::unique_ptr<QTimer> m_watcher; | ||
|
||
QString m_logpath; | ||
|
||
bool m_enabled; | ||
qint64 m_lastpos = -1; | ||
|
||
QString m_last_whisper; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.