syncthingtray/connector/syncthingconnection_capture...

147 lines
4.3 KiB
C++

#include "./syncthingconnection.h"
#include <c++utilities/conversion/conversionexception.h>
#include <c++utilities/conversion/stringconversion.h>
#include <QFile>
namespace Data {
/// \cond
static QString readEnvVar(const char *name)
{
#if QT_VERSION >= QT_VERSION_CHECK(5, 10, 0)
return qEnvironmentVariable(name);
#else
return QString::fromLocal8Bit(qgetenv(name));
#endif
}
/// \endcond
/*!
* \brief Initializes capturing/replay if corresponding environment variables are set.
*/
void SyncthingConnection::initCaptureReplay()
{
const auto captureFilePath = readEnvVar("SYNCTHING_TRAY_CAPTURE_FILE");
if (!captureFilePath.isEmpty()) {
m_captureFile = new QFile(captureFilePath, this);
m_captureFile->open(QFile::WriteOnly); // TODO: error handling
}
const auto replyFilePath = readEnvVar("SYNCTHING_TRAY_REPLAY_FILE");
if (!replyFilePath.isEmpty()) {
m_replayFile = new QFile(replyFilePath, this);
m_replayFile->open(QFile::ReadOnly); // TODO: error handling
}
}
/*!
* \brief Records the responsive if a capture file is initialized.
*/
void SyncthingConnection::captureResponse(std::string_view context, const QByteArray &response)
{
if (!m_captureFile) {
return;
}
const char marker[] = "--- ";
const auto space = ' ', newLine = '\n';
const auto timeStamp = CppUtilities::DateTime::exactGmtNow().toIsoString();
const auto size = CppUtilities::numberToString(response.size());
m_captureFile->write(marker, 4);
m_captureFile->write(timeStamp.data(), timeStamp.size());
m_captureFile->write(&space, 1);
m_captureFile->write(context.data(), context.size());
m_captureFile->write(&space, 1);
m_captureFile->write(response);
m_captureFile->write(&newLine, 1);
m_captureFile->write(response);
m_captureFile->write(&newLine, 1);
// TODO: error handling
}
/*!
* \brief Replays the captured responses if a reply file is initialized.
*/
void SyncthingConnection::replyCapturedResponses()
{
if (!m_replayFile) {
return;
}
enum State {
Marker0, Marker1, Marker2, Marker3, TimeStamp, Size, Context,
} state = Marker0;
auto c = char();
auto timeStampChars = std::string();
auto timeStamp = CppUtilities::DateTime();
auto sizeFactor = 1ul;
auto size = 0ul;
auto context = std::string();
while (m_replayFile->getChar(&c)) { // TODO: error handling
switch (state) {
case Marker0:
case Marker1:
case Marker2:
switch (c) {
case '-':
state = static_cast<State>(state + 1);
break;
default:
state = Marker0;
}
break;
case Marker3:
switch (c) {
case ' ':
state = TimeStamp;
timeStampChars.clear();
break;
default:
state = Marker0;
}
break;
case TimeStamp:
switch (c) {
case ' ':
try {
timeStamp = CppUtilities::DateTime::fromIsoStringGmt(timeStampChars.data());
state = Size;
sizeFactor = 0ul, size = 0ul;
} catch (const CppUtilities::ConversionException &c) {
state = Marker0; // TODO: error handling
}
break;
default:
timeStampChars += c;
}
break;
case Size:
if (c >= '0' && c <= '9') {
size += static_cast<decltype(size)>(c) * sizeFactor;
sizeFactor *= 10ul;
} else if (c == ' ') {
state = Context;
context.clear();
} else {
state = Marker0; // TODO: error handling
}
break;
case Context:
switch (c) {
case '\n':
state = Marker0;
m_replayFile->read(size);
// TODO: error handling
// TODO: add to some kind of queue for replays (by context)
// TODO: return if queue has enough items
break;
default:
context += c;
}
break;
}
}
}
} // namespace Data