#include "commandinterface.h" #include "workerbase.h" #include "tcpserver.h" #include "tcpserver_logger.h" #include #include #include class CommandInterface::Private { public: explicit Private(unsigned short port_, const QByteArray &command_) : command(command_) , port(port_) {} QByteArray m_connString; QByteArray command; QAbstractSocket *dev = nullptr; WorkerBase *wb = nullptr; int writeTimeout = 1000; unsigned short port; bool autoWriteEOL = true; bool bWriteError = false; bool closeConnection = false; static QByteArray defaultSuccessMessage; static QByteArray defaultErrorMessage; }; QByteArray CommandInterface::Private::defaultSuccessMessage("OK"); QByteArray CommandInterface::Private::defaultErrorMessage("ERROR"); CommandInterface::CommandInterface(unsigned short port, const QByteArray &command) : d(new Private(port, command)) {} CommandInterface::~CommandInterface() { delete d; } void CommandInterface::handleCommand(const QVector &args) { Q_ASSERT(d->dev); d->bWriteError = false; d->closeConnection = false; d->m_connString = WorkerBase::formatForDebug(d->dev); handleCommandInternal(args); if (d->autoWriteEOL) writeEOL(); d->dev->flush(); if (d->closeConnection) { d->dev->disconnectFromHost(); d->dev = nullptr; } } void CommandInterface::newPlainData() { Q_ASSERT(false); TCPSERVER_ERROR("CommandInterface::newData called which should never happen!"); } void CommandInterface::writeData(const char *payload) { writeData(QByteArray::fromRawData(payload, strlen(payload))); } void CommandInterface::writeData(const QByteArray &payload) { Q_ASSERT(d->dev); if (!d->dev->isOpen()) return; if (!payload.size()) return; TCPSERVER_DEBUG("Sending \'" << WorkerBase::formatForDebug(payload).constData() << "\' (" << payload.size() << " Bytes) to " << d->m_connString.constData()) qint64 bytesToWrite = payload.size(); qint64 bytesWritten = 0; do { bytesWritten += d->dev->write(&payload.data()[bytesWritten], bytesToWrite - bytesWritten); if (!d->dev->waitForBytesWritten(d->writeTimeout)) { TCPSERVER_ERROR("waitForBytesWritten returned false for connection " << d->m_connString.constData() << " " << d->dev->error() << " " << d->dev->errorString()) d->bWriteError = true; return; } } while (bytesToWrite != bytesWritten); } void CommandInterface::writeData(const QString &payload) { writeData(payload.toUtf8()); } void CommandInterface::writeData(const QList &payload) { QByteArray cmd; for (QByteArray s : payload) { s.replace('\"', "\\\""); if (s.contains(' ')) s = '"' + s + '"'; cmd += s + ' '; } writeData(cmd); } void CommandInterface::writeData(const QStringList &payload) { QList baList; baList.reserve(payload.size()); for (const QString &ba : payload) baList += ba.toUtf8(); writeData(baList); } void CommandInterface::writeOk(const QString &additionalMsg) { writeData(Private::defaultSuccessMessage); if (!additionalMsg.isEmpty()) { writeData(" "); writeData(additionalMsg); } } void CommandInterface::writeError(const QString &additionalMsg) { writeData(Private::defaultErrorMessage); if (!additionalMsg.isEmpty()) { writeData(" "); writeData(additionalMsg); } } void CommandInterface::writeEOL() { writeData("\n"); Q_ASSERT(d->dev); d->dev->flush(); } QByteArray CommandInterface::quote(const QByteArray &payload) { static const QByteArray escapedQuote("\""); int idx = payload.indexOf(' '); if (idx < 0) return payload; QByteArray ret = payload; return escapedQuote + ret.replace('\"', "\\\"") + escapedQuote; } QAbstractSocket *CommandInterface::socket() { return d->dev; } void CommandInterface::setSocket(QAbstractSocket *socket) { d->dev = socket; } WorkerBase *CommandInterface::workerBase() { return d->wb; } void CommandInterface::setWorkerBase(WorkerBase *wb) { d->wb = wb; } QByteArray CommandInterface::command() const { return d->command; } void CommandInterface::setWriteTimeout(int iMS) { d->writeTimeout = iMS < 0 ? 1000 : iMS; } void CommandInterface::setAutoWriteEOL(bool newAutoWriteEOL) { d->autoWriteEOL = newAutoWriteEOL; } bool CommandInterface::autoWriteEOL() const { return d->autoWriteEOL; } bool CommandInterface::errorOccured() const { return d->bWriteError; } void CommandInterface::setDefaultSuccessMessage(const QString &msg) { Private::defaultSuccessMessage = msg.isEmpty() ? "OK" : msg.toUtf8(); } void CommandInterface::setDefaultErrorMessage(const QString &msg) { Private::defaultErrorMessage = msg.isEmpty() ? "ERROR" : msg.toUtf8(); } unsigned short CommandInterface::port() const { return d->port; } void CommandInterface::closeConnection() { d->closeConnection = true; } bool CommandInterface::socketIsOpen() const { return d->dev && d->dev->isOpen(); } void CommandInterface::conversionError(const QByteArray &arg, const QByteArray &type) { writeError(QLatin1String("Can not convert ") + QString::fromUtf8(arg) + QLatin1String(" to ") + QString::fromUtf8(type)); } bool CommandInterface::getValue(const QByteArray &arg, bool &value) { bool bOk; int intValue; if (arg.startsWith("0x")) intValue = arg.mid(2).toInt(&bOk, 16); else intValue = arg.toInt(&bOk); if (!bOk) conversionError(arg, "bool"); value = (intValue != 0); return bOk; } bool CommandInterface::getValue(const QByteArray &arg, long &value) { bool bOk; if (arg.startsWith("0x")) value = arg.mid(2).toLong(&bOk, 16); else value = arg.toLong(&bOk); if (!bOk) conversionError(arg, "long"); return bOk; } bool CommandInterface::getValue(const QByteArray &arg, unsigned long &value) { bool bOk; if (arg.startsWith("0x")) value = arg.mid(2).toULong(&bOk, 16); else value = arg.toUInt(&bOk); if (!bOk) conversionError(arg, "unsigned long"); return bOk; } bool CommandInterface::getValue(const QByteArray &arg, int &value) { bool bOk; if (arg.startsWith("0x")) value = arg.mid(2).toInt(&bOk, 16); else value = arg.toInt(&bOk); if (!bOk) conversionError(arg, "int"); return bOk; } bool CommandInterface::getValue(const QByteArray &arg, unsigned int &value) { bool bOk; if (arg.startsWith("0x")) value = arg.mid(2).toUInt(&bOk, 16); else value = arg.toUInt(&bOk); if (!bOk) conversionError(arg, "unsigned int"); return bOk; } bool CommandInterface::getValue(const QByteArray &arg, float &value) { bool bOk; value = arg.toFloat(&bOk); if (!bOk) conversionError(arg, "float"); return bOk; } bool CommandInterface::getValue(const QByteArray &arg, double &value) { bool bOk; value = arg.toDouble(&bOk); if (!bOk) conversionError(arg, "double"); return bOk; }