diff --git a/update.cpp b/update.cpp new file mode 100644 index 0000000..fe025c0 --- /dev/null +++ b/update.cpp @@ -0,0 +1,231 @@ +#include "update.h" + +#include +#include +#include +#include +#include +#include + +#include "interfaces.h" +#include "DCPlugin/include/hwapi.h" + +#include +#include +#include + +#define COLUMN_REQUEST (0) +#define COLUMN_NAME (1) +#define COLUMN_DATE_TIME (2) +#define COLUMN_RESULT (3) + +void ScopedPointerCustomDeleter::cleanup(Update *update) { + if (update->m_delete) { + delete update; + } +} + +Update::Update(QString update_ctrl_file, + QObject *parent, + hwinf *hw, + char const *serialInterface, + char const *baudrate) + : QObject(parent) + , m_hw(hw != nullptr ? hw : new hwapi()) + , m_serialInterface(serialInterface) + , m_baudrate(baudrate) + , m_update_ctrl_file(update_ctrl_file) + , m_update_ctrl_file_copy(update_ctrl_file + ".copy") + , m_init(true) + , m_delete(hw == nullptr) { + + if (!m_update_ctrl_file.exists()) { + qCritical() << "Update-file" << m_update_ctrl_file.fileName() + << "does not exist"; + m_init = false; + } + if (!m_update_ctrl_file_copy.exists()) { + qCritical() << "Update-file-copy" << m_update_ctrl_file_copy.fileName() + << "does not exist"; + m_init = false; + } + if (!m_update_ctrl_file.open(QIODevice::ReadWrite | QIODevice::Text)) { + qCritical() << "can not open " << m_update_ctrl_file.fileName(); + m_init = false; + } + qDebug() << "Opened" << m_update_ctrl_file.fileName(); + if (!m_update_ctrl_file_copy.open(QIODevice::ReadWrite | QIODevice::Text)) { + qCritical() << "can not open " << m_update_ctrl_file_copy.fileName(); + m_init = false; + } + qDebug() << "Opened" << m_update_ctrl_file_copy.fileName(); +} + +Update::~Update() { +} + +bool Update::updateBinary(char const *fileToSendToDC) { + return m_hw->dc_updateDC(fileToSendToDC, m_baudrate, m_serialInterface); +} + +bool Update::updatePrinterConf(int nrOfTemplate, char const *fileToSendToDC) { + QVector printTemplates{ nrOfTemplate }; + QVector filesToSend{ fileToSendToDC }; + return m_hw->dc_updatePrinterTemplate(hwapi::FileTypeJson::PRINTER, + printTemplates, filesToSend, + QString(m_baudrate), + QString(m_serialInterface)); +} + +QStringList Update::getOpenLines() { + QStringList openLines; + + QTextStream in(&m_update_ctrl_file); + while (!in.atEnd()) { + QString line = in.readLine().trimmed(); + if (line.startsWith("DONE")) { + m_update_ctrl_file_copy.write(line.toUtf8().constData()); + m_update_ctrl_file_copy.write("\n"); + } else { + openLines << line; + } + } + return openLines; +} + +QStringList Update::split(QString line) { + QStringList lst; + QString next; + int start = 0, end; + + while ((end = line.indexOf(QChar(','), start)) != -1) { + next = line.mid(start, end - start).trimmed(); + lst << next; + start = end + 1; + } + next = line.mid(start, end - start).trimmed(); + lst << next; + + return lst; +} + +bool Update::doUpdate() { + /* + The file referred to by 'update_data' has the following structure for + each line: + + # ====================================================================== + # REQUEST | NAME | DATE | RESULT + # ====================================================================== + # where + # + # STATUS: DOWNLOAD, EXECUTE or DONE + # NAME : If starting with 'opkg' it is an opkg-command to be executed. + # Otherwise its the name of a file which has to be updated. + # DATE : 0000-00-00T00:00:00 + # RESULT: SUCCESS or ERROR (possibly with description) + # + */ + if (!m_init) { + return false; + } + + QStringList openLines = getOpenLines(); + + QList::const_iterator it; + for (it = openLines.cbegin(); it != openLines.cend(); ++it) { + bool res = false; + QString line = (*it).trimmed(); + if (line.size() == 0 || line.startsWith(QChar('#'))) { + continue; + } + QStringList lst = split(line.trimmed()); + if (lst.size() != 4) { + qCritical() << "Parsing error for" << m_update_ctrl_file.fileName(); + return false; + } + QString const &request = lst[COLUMN_REQUEST]; + QString const &name = lst[COLUMN_NAME]; + // QString const &datetime = lst[COLUMN_DATE_TIME]; + QString const &result = lst[COLUMN_RESULT]; + if ((!request.contains("DOWNLOAD") && !request.contains("EXECUTE")) || + !result.contains("N/A")) { + qCritical() << "Parsing error for" << m_update_ctrl_file.fileName(); + return false; + } + if (name.contains("dc2c") && name.endsWith(".bin")) { + if ((res = updateBinary(name.toStdString().c_str())) == true) { + qInfo() << "Downloaded" << name; + } + } else + if (name.contains("DC2C_print") && name.endsWith(".json")) { + int i = name.indexOf("DC2C_print"); + int templateIdx = name.mid(i).midRef(10, 2).toInt(); + if ((res = updatePrinterConf(templateIdx, name.toStdString().c_str())) == true) { + qInfo() << "Downloaded" << name; + } + } else + if (name.contains("tariff") && name.endsWith(".json")) { + int i = name.indexOf("tariff"); + int templateIdx = name.mid(i).midRef(6, 2).toInt(); + if ((res = updatePrinterConf(templateIdx, name.toStdString().c_str())) == true) { + qInfo() << "Downloaded" << name; + } + } else + if (name.contains("opkg")) { + int i = name.indexOf("opkg "); + QString rest = name.mid(i+5).trimmed(); + QScopedPointer p(new QProcess(this)); + p->setProcessChannelMode(QProcess::MergedChannels); + p->start("opkg", QStringList() << rest); + if (p->waitForStarted(1000)) { + if (p->state() == QProcess::ProcessState::Running) { + if (p->waitForFinished(10000)) { + QByteArray output = p->readAllStandardOutput(); + qDebug() << output; + res = true; + qInfo() << "EXECUTED" << name; + } + } + } + } else { + // TODO + } + char buf[80]; + int const bytesWritten = + snprintf(buf, sizeof(buf)-1, "DONE, %*.*s, %*.*s, %*.*s\n", + 35, 35, name.toStdString().c_str(), + 20, 20, QDateTime::currentDateTime().toString(Qt::ISODate).toStdString().c_str(), + 10, 10, (res == true) ? "SUCCESS" : "ERROR"); + if (bytesWritten < 80) { + buf[bytesWritten] = '\0'; + } + m_update_ctrl_file_copy.write(buf); + } // for (it = openLines.cbegin(); it != openLines.end(); ++it) { + + return finishUpdate(openLines.size() > 0); +} + +bool Update::finishUpdate(bool swapCtrlFiles) { + if (swapCtrlFiles) { + m_update_ctrl_file.close(); + m_update_ctrl_file_copy.close(); + + QString const &fn = m_update_ctrl_file.fileName(); + QString const &fn_tmp = m_update_ctrl_file.fileName() + ".tmp"; + QString const &fn_copy = m_update_ctrl_file_copy.fileName(); + QFile tmp(fn_tmp); + + if (tmp.exists()) { + tmp.remove(); + } + + if (m_update_ctrl_file.rename(fn_tmp)) { + if (m_update_ctrl_file_copy.rename(fn)) { + return m_update_ctrl_file.rename(fn_copy); + } + } + return false; + } + return true; +}