diff --git a/worker.cpp b/worker.cpp index 910778b..7dc06f0 100644 --- a/worker.cpp +++ b/worker.cpp @@ -12,25 +12,20 @@ #include #include #include +#include +#include +#include + +#include #include "message_handler.h" #include "plugins/interfaces.h" #include "ismas/ismas_client.h" -#include "apism/apism_client.h" -int Worker::read1stLineOfFile(QString fileName) { - QFile f(fileName); - if (f.exists()) { - if (f.open(QIODevice::ReadOnly | QIODevice::Text)) { - QTextStream in(&f); - in.setCodec("UTF-8"); - while(!in.atEnd()) { - return in.readLine().toInt(); - } - } - } - return -1; -} +QString const Worker::UPDATE_STEP_OK(" [ ok]"); +QString const Worker::UPDATE_STEP_DONE(" [done]"); +QString const Worker::UPDATE_STEP_FAIL(" [fail]"); +QString const Worker::UPDATE_STEP_SUCCESS(" [SUCCESS]"); Worker::Worker(hwinf *hw, int customerNr, @@ -38,14 +33,12 @@ Worker::Worker(hwinf *hw, int zoneNr, QString branchName, QString workingDirectory, - bool maintenanceMode, bool dryRun, QObject *parent, char const *serialInterface, char const *baudrate) : m_hw(hw) , m_workerThread("workerThread") - , m_apismClient(0, 0, 0, this) // TODO , m_customerNr(customerNr) , m_customerNrStr(QString("customer_") + QString::number(m_customerNr).rightJustified(3, '0')) , m_machineNr(machineNr) @@ -54,8 +47,9 @@ Worker::Worker(hwinf *hw, , m_branchName(branchName) , m_customerRepositoryPath(QString("https://git.mimbach49.de/GerhardHoffmann/%1.git").arg(m_customerNrStr)) , m_customerRepository(QDir::cleanPath(m_workingDirectory + QDir::separator() + m_customerNrStr)) + , m_update(new Update(m_hw, this, m_customerRepository, m_customerNrStr, m_branchName, + m_workingDirectory, dryRun, parent, serialInterface, baudrate)) , m_gc(m_customerNrStr, m_customerRepository, m_workingDirectory, m_branchName, this) - , m_maintenanceMode(maintenanceMode) , m_osVersion(getOsVersion()) , m_atbqtVersion(getATBQTVersion()) , m_cpuSerial(getCPUSerial()) @@ -69,7 +63,9 @@ Worker::Worker(hwinf *hw, , m_pluginVersionPrmCalcConfig(getPluginVersion("/opt/app/ATBAPP/plugins/libPRM_CalculatePricePlugin_ConfigUi.so")) , m_pluginVersionTcpZvt(getPluginVersion("/opt/app/ATBAPP/plugins/libTCP_ZVT_CCPlugin.so")) , m_ismasUpdateRequests(ISMAS_UPDATE_REQUESTS) - , m_waitForNewUpdates(this) { + , m_waitForNewUpdates(this) + , m_filesToUpdate() + , m_updateProcessRunning(false) { QDir::setCurrent(m_workingDirectory); @@ -86,13 +82,6 @@ Worker::Worker(hwinf *hw, qInfo() << "BRANCH_NAME ................" << m_branchName; qInfo() << "WORKING_DIRECTORY .........." << m_workingDirectory; - //QProcess p; - //p.start("/bin/systemctl", {"restart", "apism"}); - //if (!p.waitForStarted(5000) || !p.waitForFinished(5000)) { - // qCritical() << "APISM-RESTART-FAILURE"; - // return; - //} - this->moveToThread(&m_workerThread); m_workerThread.start(); @@ -104,47 +93,6 @@ Worker::Worker(hwinf *hw, } QThread::sleep(1); } - - connect(&m_apismClient, SIGNAL(ismasResponseAvailable(QJsonObject)), this, - SLOT(onIsmasResponseReceived(QJsonObject))); - connect(this, SIGNAL(summarizeRepositoryStatus()), this, - SLOT(onSummarizeRepositoryStatus()), Qt::QueuedConnection); - connect(this, SIGNAL(sendCmdSendVersionToIsmas()), this, - SLOT(onSendCmdSendVersionToIsmas()), Qt::QueuedConnection); - connect(this, SIGNAL(summarizeUpload(QStringList)), this, - SLOT(onSummarizeUpload(QStringList)), Qt::QueuedConnection); - connect(this, SIGNAL(handleChangedFiles(QStringList)), this, - SLOT(onHandleChangedFiles(QStringList)), Qt::QueuedConnection); - connect(this, SIGNAL(finishUpdateProcess(bool)), this, - SLOT(onFinishUpdateProcess(bool)), Qt::QueuedConnection); - connect(this, SIGNAL(terminateUpdateProcess()), this, - SLOT(onTerminateUpdateProcess()), Qt::QueuedConnection); - - connect(&m_emergencyTimer, SIGNAL(timeout()), this, SLOT(onTerminateUpdateProcess()), Qt::QueuedConnection); - m_emergencyTimer.setSingleShot(true); - m_emergencyTimer.start(1000 * 60 * 10); - - QDir customerRepository(m_customerRepository); - if (!customerRepository.exists()) { - if (m_gc.gitCloneAndCheckoutBranch()) { - // do nothing else, not even executing opkg-commands - emit this->finishUpdateProcess(false); - } - } else { - m_update = new Update(m_hw, - m_customerRepository, - m_customerNrStr, - m_branchName, - m_workingDirectory, - dryRun, parent, serialInterface, baudrate); - - connect(&m_startUpdateProcess, SIGNAL(timeout()), this, SLOT(askIsmasForNewData()), Qt::QueuedConnection); - m_startUpdateProcess.setSingleShot(true); - m_startUpdateProcess.start(1000); - - connect(&m_waitForNewUpdates, SIGNAL(timeout()), this, SLOT(askIsmasForNewData()), Qt::QueuedConnection); - m_waitForNewUpdates.setSingleShot(false); - } } Worker::~Worker() { @@ -163,6 +111,428 @@ Worker::~Worker() { } } +static std::once_flag once; +void Worker::update() { + std::call_once(once, &Worker::privateUpdate, this); +} + +void Worker::privateUpdate() { + // user should not start the update process several times + QPushButton *start = qobject_cast(QObject::sender()); + start->setEnabled(false); + + emit stopStartTimer(); + m_updateProcessRunning = true; + + bool sentIsmasLastVersionNotification = false; + + QDir customerRepository(m_customerRepository); + if (!customerRepository.exists()) { + if (m_gc.gitCloneAndCheckoutBranch()) { + m_updateStatus = UpdateStatus(UPDATE_STATUS::UPDATE_PROCESS_SUCCESS, + QString("CLONED AND CHECKED OUT: ") + m_customerRepository); + + IsmasClient::sendRequestReceiveResponse(IsmasClient::APISM::DB_PORT, + QString("#M=APISM#C=CMD_EVENT#J=") + + m_ismasClient.cloneAndCheckoutCustomerRepository( + m_updateStatus.m_statusDescription)); + + IsmasClient::sendRequestReceiveResponse(IsmasClient::APISM::DB_PORT, + QString("#M=APISM#C=CMD_EVENT#J=") + + m_ismasClient.updateOfPSASucceeded("")); + + } + } else { + // checkout branch + if (m_gc.gitCheckoutBranch()) { + int progress = 10; + m_ismasClient.setProgressInPercent(progress); + m_updateStatus = UpdateStatus(UPDATE_STATUS::GIT_CHECKOUT_BRANCH, + QString("CHECKED OUT BRANCH: ") + m_gc.branchName()); + IsmasClient::sendRequestReceiveResponse(IsmasClient::APISM::DB_PORT, + QString("#M=APISM#C=CMD_EVENT#J=") + + m_ismasClient.checkoutBranch( + m_updateStatus.m_statusDescription, "")); + + emit setProgress(progress); + if (backendConnected()) { + progress = 20; + emit setProgress(progress); + m_ismasClient.setProgressInPercent(progress); + if (updateTriggerSet()) { + emit setProgress(progress); + m_ismasClient.setProgressInPercent(progress); + if (customerEnvironment()) { + emit setProgress(progress); + m_ismasClient.setProgressInPercent(progress); + if (filesToUpdate()) { + emit setProgress(progress); + m_ismasClient.setProgressInPercent(progress); + if (updateFiles(progress)) { + emit setProgress(progress); + m_ismasClient.setProgressInPercent(progress); + if (syncCustomerRepositoryAndFS()) { + emit setProgress(progress); + m_ismasClient.setProgressInPercent(progress); + if (sendIsmasLastVersionNotification()) { + emit setProgress(progress); + m_ismasClient.setProgressInPercent(progress); + sentIsmasLastVersionNotification = true; + if (saveLogFile()) { + emit setProgress(progress); + m_ismasClient.setProgressInPercent(progress); + emit appendText(QString(""), UPDATE_STEP_SUCCESS); + + // mark update as activated -> this resets the WAIT button + progress = 100; + emit setProgress(progress); + m_ismasClient.setProgressInPercent(progress); + IsmasClient::sendRequestReceiveResponse(IsmasClient::APISM::DB_PORT, + QString("#M=APISM#C=CMD_EVENT#J=") + + m_ismasClient.updateOfPSAActivated()); + } + } + } + } + } + } + } + } + } + } + if (!sentIsmasLastVersionNotification) { + // try even if the backend is not connected + sendIsmasLastVersionNotification(); + } + + m_updateProcessRunning = false; + emit restartExitTimer(); +} + +bool Worker::backendConnected() { + static int repeat = 0; + + if (repeat < 3) { + std::optional result + = IsmasClient::sendRequestReceiveResponse( + IsmasClient::APISM::DIRECT_PORT, "#M=APISM#C=REQ_SELF#J={}"); + if (result) { + QString msg = result.value(); + QJsonParseError parseError; + QJsonDocument document(QJsonDocument::fromJson(msg.toUtf8(), &parseError)); + if (parseError.error != QJsonParseError::NoError) { + qCritical() << "(2) INVALID JSON MSG: PARSING FAILED (msg=" << msg << "):" + << parseError.error << parseError.errorString(); + return false; + } + if (!document.isObject()) { + qCritical() << "FILE IS NOT A JSON OBJECT!"; + return false; + } + + QJsonObject obj = document.object(); + QStringList keys = obj.keys(); + for (QString const& key : keys ) { + if (key.contains("CMD_GET_APISMSTATUS_RESPONSE")) { + QJsonValue v = obj.value(key); + if (v.isObject()) { + obj = v.toObject(); + bool ismas = obj.value("ISMAS").toBool(); + QString status = obj.value("Broker").toString(); + + qCritical() << "XXXXXXXXXX STATUS" << status; + + if (ismas) { + if (status == "Connected") { + // do not send, as this would result in a corrupted wait button + // but update the user-interface + emit appendText("\nBackend connected", UPDATE_STEP_OK); + return true; + } + } + if (status.startsWith("Connecting") || status.startsWith("Re-Connecting")) { + QThread::sleep(1); + ++repeat; + return backendConnected(); + } + emit appendText("\nBackend connected", UPDATE_STEP_FAIL); + emit showErrorMessage("Error", "Backend not available"); + } + } + } + } + } + m_updateStatus = UpdateStatus(UPDATE_STATUS::BACKEND_NOT_CONNECTED, + QString("NO BACKEND CONNECTION")); + IsmasClient::sendRequestReceiveResponse(IsmasClient::APISM::DB_PORT, + QString("#M=APISM#C=CMD_EVENT#J=") + + m_ismasClient.errorBackendNotConnected(m_updateStatus.m_statusDescription, "")); + + return false; +} + +bool Worker::updateTriggerSet() { +// nmap -Pn 62.141.45.68 -p 8883 +// Host is up (0.053s latency). +// +// PORT STATE SERVICE +// 8883/tcp open secure-mqtt + + QString triggerValue(""); + + if (std::optional result + = IsmasClient::sendRequestReceiveResponse( + IsmasClient::APISM::DIRECT_PORT, "#M=APISM#C=REQ_ISMASPARAMETER#J={}")) { + QString msg = result.value(); + QJsonParseError parseError; + QJsonDocument document(QJsonDocument::fromJson(msg.toUtf8(), &parseError)); + if (parseError.error != QJsonParseError::NoError) { + qCritical() << "(2) INVALID JSON MSG: PARSING FAILED (msg=" << msg << "):" + << parseError.error << parseError.errorString(); + emit showErrorMessage("check update trigger", + QString("invalid json ") + msg.mid(0, 20)); + return false; + } + if (!document.isObject()) { + qCritical() << "FILE IS NOT A JSON OBJECT!"; + emit showErrorMessage("check update trigger", + QString("not a json object") + msg); + return false; + } + + QJsonObject obj = document.object(); + // sanity check: cust_nr and machine_nr of PSA correct ? + if (obj.contains("Dev_ID")) { + QJsonValue v = obj.value("Dev_ID"); + if (v.isObject()) { + QJsonObject obj = v.toObject(); + if (obj.contains("Custom_ID") && obj.contains("Device_ID")) { + QJsonValue const c = obj.value("Custom_ID"); + QJsonValue const m = obj.value("Device_ID"); + int customerNr = c.toInt(-1); + int machineNr = m.toInt(-1); + if (customerNr != m_customerNr) { + m_updateStatus = UpdateStatus(UPDATE_STATUS::ISMAS_WAIT_STATE_CHECK_FAILURE, + QString("CUSTOMER-NR (%1) != LOCAL CUSTOMER-NR (%2)") + .arg(customerNr).arg(m_customerNr)); + emit showErrorMessage("check update trigger", m_updateStatus.m_statusDescription); + + IsmasClient::sendRequestReceiveResponse(IsmasClient::APISM::DB_PORT, + QString("#M=APISM#C=CMD_EVENT#J=") + + m_ismasClient.sanityCheckFailed(IsmasClient::RESULT_CODE::INSTALL_ERROR, + m_updateStatus.m_statusDescription)); + return false; + } + if (machineNr != m_machineNr) { + m_updateStatus = UpdateStatus(UPDATE_STATUS::ISMAS_WAIT_STATE_CHECK_FAILURE, + QString("MACHINE-NR (%1) != LOCAL MACHINE-NR (%2)") + .arg(machineNr).arg(m_machineNr)); + emit showErrorMessage("check update trigger", m_updateStatus.m_statusDescription); + + IsmasClient::sendRequestReceiveResponse(IsmasClient::APISM::DB_PORT, + QString("#M=APISM#C=CMD_EVENT#J=") + + m_ismasClient.sanityCheckFailed(IsmasClient::RESULT_CODE::INSTALL_ERROR, + m_updateStatus.m_statusDescription)); + return false; + } + } + } + } + if (obj.contains("Fileupload")) { + QJsonValue v = obj.value("Fileupload"); + if (v.isObject()) { + obj = v.toObject(); + if (obj.contains("TRG")) { + v = obj.value("TRG"); + if (v.isString()) { + triggerValue = v.toString(); + if (triggerValue == "WAIT") { + emit appendText("\nUpdate trigger set", UPDATE_STEP_OK); + + m_updateStatus = UpdateStatus(UPDATE_STATUS::UPDATE_TRIGGER_SET, + QString("UPDATE TRIGGER SET. CONTINUE. ")); + + IsmasClient::sendRequestReceiveResponse(IsmasClient::APISM::DB_PORT, + QString("#M=APISM#C=CMD_EVENT#J=") + + m_ismasClient.updateTriggerSet(m_updateStatus.m_statusDescription, "")); + + return true; + } else { + emit showErrorMessage("check update trigger", + QString ("TRG key=<") + triggerValue + + ">\n(reset download button?)"); + } + } + } else { + emit showErrorMessage("check update trigger", "TRG key not contained"); + } + } else { + emit showErrorMessage("check update trigger", "Fileupload not a json-object"); + } + } + } else { + emit showErrorMessage("check update trigger", "no ISMAS response"); + } + + m_updateStatus = UpdateStatus(UPDATE_STATUS::UPDATE_TRIGGER_NOT_SET_OR_WRONG, + QString("UPDATE-TRIGGER-NOT-SET-OR-WRONG: VALUE=(") + + triggerValue + ")"); + IsmasClient::sendRequestReceiveResponse(IsmasClient::APISM::DB_PORT, + QString("#M=APISM#C=CMD_EVENT#J=") + + m_ismasClient.errorUpdateTrigger(m_updateStatus.m_statusDescription, "")); + return false; +} + +bool Worker::customerEnvironment() { + if (QDir(m_customerRepository).exists()) { + if (m_gc.gitCheckoutBranch()) { + emit appendText("\nPrepare customer environment", UPDATE_STEP_DONE); + m_updateStatus = UpdateStatus(UPDATE_STATUS::GIT_CHECKOUT_BRANCH, + QString("CHECKED-OUT BRANCH ") + m_gc.branchName()); + + IsmasClient::sendRequestReceiveResponse(IsmasClient::APISM::DB_PORT, + QString("#M=APISM#C=CMD_EVENT#J=") + + m_ismasClient.checkoutBranch(m_updateStatus.m_statusDescription, "")); + return true; + } else { + emit showErrorMessage("cust-env", + QString("Checkout ") + m_customerRepository + " failed"); + } + } else { + emit showErrorMessage("cust-env", m_customerRepository + " does not exist"); + } + return false; +} + +bool Worker::filesToUpdate() { + if (std::optional changes = m_gc.gitFetch()) { + m_updateStatus = UpdateStatus(UPDATE_STATUS::GIT_FETCH_UPDATES, + QString("FETCHING OF ") + m_customerRepositoryPath + + QString(" INTO ") + m_customerRepository); + + if (std::optional changedFileNames = m_gc.gitDiff(changes.value())) { + m_filesToUpdate = changedFileNames.value(); + int const size = m_filesToUpdate.size(); + if (size > 1) { + emit appendText(QString("\nFound %1 files to update ").arg(size), UPDATE_STEP_DONE); + } else { + emit appendText(QString("\nFound 1 file to update "), UPDATE_STEP_DONE); + } + return true; + } else { + emit showErrorMessage("files to update", "no files to update (checked-in any files?)"); + } + } else { + emit showErrorMessage("files to update", + QString("no changes in ") + m_customerRepository + + " (checked-in any files?)"); + } + return false; +} + +bool Worker::updateFiles(quint8 percent) { + QStringList filesToDownload; + m_displayIndex = 0; + for (int i = 0; i < m_filesToUpdate.size(); ++i) { + QString fName = m_filesToUpdate.at(i); + if (fName.contains("opkg_commands", Qt::CaseInsensitive)) { + // execute opkg commands + if (QDir::setCurrent(m_customerRepository)) { + QFile f(fName); + if (f.exists()) { + if (f.open(QIODevice::ReadOnly)) { + QTextStream in(&f); + int cmdCount = 0; + while (!in.atEnd()) { + QString line = in.readLine(); + static const QRegularExpression comment("^\\s*#.*$"); + if (line.indexOf(comment, 0) == -1) { + // found opkg command + QString opkgCommand = line.trimmed(); + executeOpkgCommand(opkgCommand); + ++cmdCount; + + m_ismasClient.setProgressInPercent(++percent); + m_updateStatus = UpdateStatus(UPDATE_STATUS::EXEC_OPKG_COMMAND, + QString("EXEC OPKG-COMMAND ") + opkgCommand); + IsmasClient::sendRequestReceiveResponse(IsmasClient::APISM::DB_PORT, + QString("#M=APISM#C=CMD_EVENT#J=") + + m_ismasClient.execOpkgCommand(m_updateStatus.m_statusDescription, "")); + } + } + f.close(); + if (cmdCount > 0) { + m_displayIndex = 1; + emit appendText(QString("\n(") + QString("%1").arg(m_displayIndex).rightJustified(2, ' ') + QString(")") + + QString(" Update opkg pakets "), UPDATE_STEP_DONE); + } + } + } + } + } else + if (fName.contains("print", Qt::CaseInsensitive)) { + filesToDownload << fName; // download printer-config-files + } else + if (fName == "dc2c.bin") { + filesToDownload << fName; // download device controller + } + } + + qCritical() << "XXXXXXXXXXXXXXXXXXX FILES_TO_WORK_ON" << filesToDownload; + + return m_update->doUpdate(m_displayIndex, filesToDownload); +} + +bool Worker::syncCustomerRepositoryAndFS() { + if (QDir(m_customerRepository).exists()) { + if (QDir::setCurrent(m_customerRepository)) { + QString const params("--recursive " + "--progress " + "--checksum " + "--exclude=.* " + "--include=*.bin " + "--include=*.json " + "--include=opkg_commands " + "--include=*.ini"); + QStringList cmds; + cmds << QString("rsync ") + params.simplified() + " etc/ /etc"; + cmds << QString("rsync ") + params.simplified() + " opt/ /opt"; + + QString cmd; + bool error = false; + foreach (cmd, cmds) { + if (!error) { + Command c("bash"); + qInfo() << "EXECUTING CMD..." << cmd; + if (c.execute(m_customerRepository, QStringList() << "-c" << cmd)) { + qCritical() << c.getCommandResult() << "SUCCESS"; + } else { + qCritical() << "CMD" << cmd << "FAILED"; + error = true; + } + } + } + if (!error) { + emit appendText(QString("\nSync customer environment with filesystem "), + UPDATE_STEP_DONE); + return true; + } + } + } + return false; +} + +bool Worker::sendIsmasLastVersionNotification() { + IsmasClient::sendRequestReceiveResponse(IsmasClient::APISM::DB_PORT, + QString("#M=APISM#C=CMD_SENDVERSION#J=") + + m_ismasClient.updateOfPSASendVersion(getPSAInstalled())); + emit appendText(QString("\nSend last version info "), UPDATE_STEP_DONE); + return true; +} + +bool Worker::saveLogFile() { + return true; +} QString Worker::getOsVersion() const { QString const cmd = QString("echo -n $(cat /etc/os-release | head -n 1 | cut -d'\"' -f2 | tr -d '\"')"); Command c("bash"); @@ -245,132 +615,7 @@ qint64 Worker::getFileSize(QString const &fileName) const { return fInfo.exists() ? fInfo.size() : -1; } -void Worker::onHandleChangedFiles(QStringList changedFiles) { - - QString opkg_commands; - static const QRegularExpression re("^.*opkg_commands\\s*$"); - static const QRegularExpression comment("^\\s*#.*$"); - int idx = changedFiles.indexOf(re); - if (idx != -1) { - opkg_commands = changedFiles.takeAt(idx); - - qInfo() << UpdateStatus(UPDATE_STATUS::EXEC_OPKG_COMMANDS, - QString("EXEC OPKG-COMMANDS FOR ") + opkg_commands); - - if (QDir::setCurrent(m_customerRepository)) { - QFile f(opkg_commands); - if (f.exists()) { - if (f.open(QIODevice::ReadOnly)) { - QTextStream in(&f); - while (!in.atEnd()) { - QString line = in.readLine(); - if (line.indexOf(comment, 0) == -1) { - // found opkg command - QString opkgCommand = line.trimmed(); - executeOpkgCommand(opkgCommand); - } - } - f.close(); - - qInfo() << UpdateStatus(UPDATE_STATUS::EXEC_OPKG_COMMANDS_SUCCESS, - QString("EXECUTING OPKG-COMMANDS OK")); - } - } - } - } - - if (m_update->doUpdate(changedFiles)) { // first update the hardware - // then sync the file-system - if (QDir(m_customerRepository).exists()) { - if (QDir::setCurrent(m_customerRepository)) { - QString const params("--recursive " - "--progress " - "--checksum " - "--exclude=.* " - "--include=*.bin " - "--include=*.json " - "--include=opkg_commands " - "--include=*.ini"); - QStringList cmds; - cmds << QString("rsync ") + params.simplified() + " etc/ /etc"; - cmds << QString("rsync ") + params.simplified() + " opt/ /opt"; - - QString cmd; - bool error = false; - foreach (cmd, cmds) { - if (!error) { - Command c("bash"); - qInfo() << "EXCUTING CMD..." << cmd; - if (c.execute(m_customerRepository, QStringList() << "-c" << cmd)) { - qDebug() << c.getCommandResult(); - } else { - qCritical() << "CMD" << cmd << "FAILED"; - error = true; - } - } - } - if (!error) { - emit this->finishUpdateProcess(true); - return; - } - } - } - } - onTerminateUpdateProcess(); -} - -void Worker::onSummarizeUpload(QStringList changedFiles) { - QDateTime const c = QDateTime::currentDateTime(); - QDate const d = c.date(); - QTime const t = c.time(); - - QString uploadHistoryFile = QString("upload_history_%1%2%3T%4%5%6.txt") - .arg(d.year()).arg(d.month()).arg(d.day()) - .arg(t.hour()).arg(t.minute()).arg(t.second()); - - QFile f(uploadHistoryFile); - if (f.open(QIODevice::WriteOnly | QIODevice::Text)) { - QTextStream out(&f); - QString fName; - foreach (fName, changedFiles) { - QString lastCommit = m_gc.gitLastCommit(fName); - out << fName << ":" << lastCommit << "\n"; - } - } else { - // TODO: error an ISMAS - } -} - -void Worker::onSummarizeRepositoryStatus() { - // TODO - QString dir("/opt/app/tools/atbupdate/customer_999"); - QDirIterator it(dir, QStringList() << "*.jpg", - QDir::Files, QDirIterator::Subdirectories); - while (it.hasNext()) { - qDebug() << it.next(); - if (m_gc.gitIsFileTracked(it.next())) { - QString lastCommit = m_gc.gitLastCommit(it.next()); - } - } - - /* - QString repoStatusHistoryFile = QString("repo_status_history_%1%2%3T%4%5%6.txt") - .arg(d.year()).arg(d.month()).arg(d.day()) - .arg(t.hour()).arg(t.minute()).arg(t.second()); - if (f.open(QIODevice::WriteOnly | QIODevice::Text)) { - QTextStream out(&f); - QString fName; - foreach (fName, changedFiles) { - QString lastCommit = m_gc.gitLastCommit(fName); - out << fName << ":" << lastCommit << "\n"; - } - } else { - // TODO: error an ISMAS - } - */ -} - -void Worker::executeOpkgCommand(QString opkgCommand) { +bool Worker::executeOpkgCommand(QString opkgCommand) { Command c(opkgCommand); if (c.execute(m_workingDirectory)) { QString const r = c.getCommandResult(); @@ -378,115 +623,92 @@ void Worker::executeOpkgCommand(QString opkgCommand) { QString("EXECUTE OPKG COMMAND %1 OK: %2") .arg(opkgCommand) .arg(c.getCommandResult())); + return true; } else { qCritical() << UpdateStatus(UPDATE_STATUS::EXEC_OPKG_COMMAND_FAILURE, QString("EXECUTE OPKG COMMAND %1 FAILED") .arg(opkgCommand)); - onTerminateUpdateProcess(); - return; } + return false; } -// sollte ParameterResponse heissen -void Worker::onIsmasResponseReceived(QJsonObject ismasResponse) { +PSAInstalled Worker::getPSAInstalled() { + QStringList const dcVersion = getDCVersion(); + QString const deviceControllerVersionHW = dcVersion.first(); + QString const deviceControllerVersionSW = dcVersion.last(); - qInfo() << "IN ON_ISMAS_RESPONSE_RECEIVED" << QThread::currentThread()->objectName(); + qInfo() << "CURRENT DC-HW-VERSION: " << deviceControllerVersionHW; + qInfo() << "CURRENT DC-SW-VERSION: " << deviceControllerVersionSW; - if (!ismasResponse.isEmpty()) { - QStringList const keys = ismasResponse.keys(); - qInfo() << UpdateStatus(UPDATE_STATUS::ISMAS_RESPONSE_RECEIVED, - QString("RECEIVED JSON WITH KEYS: ") + keys.join(",")); + QString const deviceControllerGitBlob = "N/A"; + QString const deviceControllerGitLastCommit = "N/A"; - static QRegularExpression re("^REQ_ISMASPARAMETER.*"); - if(keys.indexOf(re) >= 0) { - m_waitForNewUpdates.stop(); // stop asking ISMAS for updates + PSAInstalled psaInstalled; + QString printSysDir("/etc/psa_config"); + QString tariffSysDir("/etc/psa_tariff"); + QString absPathName; - // sanity check: cust_nr and machine_nr of PSA correct ? - if (keys.contains("Dev_ID", Qt::CaseInsensitive)) { - QJsonObject const devId = ismasResponse["Dev_ID"].toObject(); - QStringList const keys = devId.keys(); - if (keys.contains("Custom_ID") && keys.contains("Device_ID")) { - QJsonValue const c = devId.value("Custom_ID"); - QJsonValue const m = devId.value("Device_ID"); - int customerNr = c.toInt(-1); - int machineNr = m.toInt(-1); - if (customerNr != m_customerNr) { - m_updateStatus = UPDATE_STATUS::ISMAS_UPDATE_REQUEST_FAILURE; - m_statusDescription - = QString("CUSTOMER-NR (%1) != LOCAL CUSTOMER-NR (%2)") - .arg(customerNr).arg(m_customerNr); - return; - } - if (machineNr != m_machineNr) { - m_statusDescription - = QString("MACHINE-NR (%1) != LOCAL MACHINE-NR (%2)") - .arg(machineNr).arg(m_machineNr); - m_updateStatus = UPDATE_STATUS::ISMAS_UPDATE_REQUEST_FAILURE; - return; - } - } - } - // TODO: check if zone_nr is correct - - if (keys.contains("Fileupload", Qt::CaseInsensitive)) { - QJsonObject fileUpload = ismasResponse["Fileupload"].toObject(); - QJsonValue v = fileUpload.value("TRG"); - if (!v.isNull() && !v.isUndefined()) { - QString const s = v.toString(""); - if (s == "WAIT") { - m_ismasUpdateRequests = ISMAS_UPDATE_REQUESTS; - - qInfo() << UpdateStatus(UPDATE_STATUS::ISMAS_UPDATE_REQUEST_SUCCESS, - "DETECTED AVAILABLE ISMAS-DOWNLOAD"); - - QString const &data = m_ismasClient.updateOfPSAActivated(); - m_apismClient.onSendCmdEventToIsmas(data); - - emit m_gc.ismasUpdatesAvailable(); - } else { - // TODO: enorm wichtig - qCritical() << "DID NOT RECEIVE 'WAIT' BUT" << s; - onTerminateUpdateProcess(); - } - } - } else { - m_updateStatus = UPDATE_STATUS::ISMAS_UPDATE_REQUEST_FAILURE; - m_statusDescription = "NO FILEUPLOAD KEY AVAILABLE"; - return; - } - - } - } else { - m_updateStatus = UPDATE_STATUS::ISMAS_UPDATE_REQUEST_FAILURE; - m_statusDescription = "NO ISMAS RESPONSE AVAILABLE (EMPTY)"; + if (m_zoneNr != 0) { + QString const &n = QString("%1").arg(m_zoneNr).rightJustified(2, '0'); + psaInstalled.tariff.name = QString("tariff%1.json").arg(n); + absPathName = QDir::cleanPath(tariffSysDir + QDir::separator() + psaInstalled.tariff.name); + psaInstalled.tariff.blob = m_gc.gitBlob(absPathName); + psaInstalled.tariff.size = getFileSize(absPathName); + psaInstalled.tariff.zone = m_zoneNr; } + psaInstalled.tariff.project = "Szeged"; + psaInstalled.tariff.info = "N/A"; + psaInstalled.tariff.loadTime = "N/A"; // QDateTime::currentDateTime().toString(Qt::ISODateWithMs); + psaInstalled.tariff.version = "N/A"; + + psaInstalled.hw.linuxVersion = m_osVersion; + psaInstalled.hw.cpuSerial = m_cpuSerial; + + psaInstalled.dc.versionHW = deviceControllerVersionHW; + psaInstalled.dc.versionSW = deviceControllerVersionSW; + psaInstalled.dc.gitBlob = "N/A"; + psaInstalled.dc.gitLastCommit = "N/A"; + psaInstalled.dc.size = -1; + + psaInstalled.sw.raucVersion = m_raucVersion; + psaInstalled.sw.opkgVersion = m_opkgVersion; + psaInstalled.sw.atbQTVersion = m_atbqtVersion; + + psaInstalled.pluginVersion.deviceController = m_pluginVersionATBDeciceController; + psaInstalled.pluginVersion.ingenicoISelfCC = m_pluginVersionIngenicoISelf; + psaInstalled.pluginVersion.mobilisisCalculatePrice = m_pluginVersionMobilisisCalc; + psaInstalled.pluginVersion.mobilisisCalculatePriceConfigUi = m_pluginVersionMobilisisCalcConfig; + psaInstalled.pluginVersion.prmCalculatePrice = m_pluginVersionPrmCalc; + psaInstalled.pluginVersion.prmCalculatePriceConfigUi = m_pluginVersionPrmCalcConfig; + psaInstalled.pluginVersion.tcpZVT = m_pluginVersionTcpZvt; + + psaInstalled.cash.name = "DC2C_cash.json"; + absPathName = QDir::cleanPath(printSysDir + QDir::separator() + psaInstalled.cash.name); + psaInstalled.cash.blob = m_gc.gitBlob(absPathName); + psaInstalled.cash.size = getFileSize(absPathName); + + psaInstalled.conf.name = "DC2C_conf.json"; + absPathName = QDir::cleanPath(printSysDir + QDir::separator() + psaInstalled.conf.name); + psaInstalled.conf.blob = m_gc.gitBlob(absPathName); + psaInstalled.conf.size = getFileSize(absPathName); + + psaInstalled.device.name = "DC2C_device.json"; + absPathName = QDir::cleanPath(printSysDir + QDir::separator() + psaInstalled.device.name); + psaInstalled.device.blob = m_gc.gitBlob(absPathName); + psaInstalled.device.size = getFileSize(absPathName); + + for (int i=0; i < 32; ++i) { + QString const &n = QString("%1").arg(i+1).rightJustified(2, '0'); + psaInstalled.print[i].name = QString("DC2C_print%1.json").arg(n); + absPathName = QDir::cleanPath(printSysDir + QDir::separator() + psaInstalled.print[i].name); + psaInstalled.print[i].blob = m_gc.gitBlob(absPathName); + psaInstalled.print[i].size = getFileSize(absPathName); + } + + return psaInstalled; } -void Worker::onFinishUpdateProcess(bool changes) { - Q_UNUSED(changes); - - qInfo() << "ON FINISH UPDATE PROCESS" << QThread::currentThread()->objectName(); - // m_emergencyTimer.stop(); - - onSendCmdSendVersionToIsmas(); // final message to ISMAS - - m_workerThread.quit(); - QApplication::quit(); - exit(0); -} - - -void Worker::onTerminateUpdateProcess() { - qCritical() << "ON TERMINATE UPDATE PROCESS"; - - onSendCmdSendVersionToIsmas(); // final message to ISMAS - - m_workerThread.quit(); - QApplication::quit(); - exit(-1); -} - -void Worker::onSendCmdSendVersionToIsmas() { +QString Worker::sendCmdSendVersionToIsmas() { QStringList const dcVersion = getDCVersion(); QString const deviceControllerVersionHW = dcVersion.first(); @@ -560,37 +782,8 @@ void Worker::onSendCmdSendVersionToIsmas() { psaInstalled.print[i].size = getFileSize(absPathName); } - QString data = m_ismasClient.updateOfPSASendVersion(psaInstalled); - - // printf("data=%s\n", data.toStdString().c_str()); - - m_apismClient.onSendCmdSendVersionToIsmas(data); -} - -void Worker::askIsmasForNewData() { - if (m_maintenanceMode) { - m_updateStatus = UPDATE_STATUS::ISMAS_EMULATE_DATA_AVAILABLE; - QString data = m_ismasClient.setUpdatesAvailable(); - m_apismClient.emulateUpdatesAvailable(data); - } - - //m_updateStatus = UPDATE_STATUS::ISMAS_UPDATE_REQUEST_PENDING; - //m_statusDescription = "Ask ISMAS IF NEW DATA AVAILABLE"; - - qInfo() << UpdateStatus(UPDATE_STATUS::ISMAS_UPDATE_REQUEST_PENDING, - QString("ASK ISMAS IF NEW DATA AVAILABLE") + - QString(" (%1)").arg(m_ismasUpdateRequests)); - - m_apismClient.requestAvailableIsmasUpdates(); - - if (--m_ismasUpdateRequests > 0) { - // if the timer is already running, it will be stopped and restarted. - m_waitForNewUpdates.start(10000); - m_updateStatus = UPDATE_STATUS::ISMAS_UPDATE_REQUEST_PENDING; - } else { - m_updateStatus = UPDATE_STATUS::ISMAS_UPDATE_REQUEST_TIMEOUT; - onTerminateUpdateProcess(); - } + // QByteArray data = "#M=APISM#C=CMD_SENDVERSION#J="; + return m_ismasClient.updateOfPSASendVersion(psaInstalled); } /************************************************************************************************ @@ -598,16 +791,28 @@ void Worker::askIsmasForNewData() { */ QDebug operator<< (QDebug debug, UpdateStatus status) { switch(status.m_updateStatus) { - case UPDATE_STATUS::ISMAS_UPDATE_REQUEST_PENDING: - debug << QString("UPDATE_STATUS::ISMAS_UPDATE_REQUEST_PENDING: ") + case UPDATE_STATUS::UPDATE_PROCESS_SUCCESS: + debug << QString("UPDATE_STATUS::UPDATE_PROCESS_SUCCESS: ") << status.m_statusDescription; break; - case UPDATE_STATUS::ISMAS_UPDATE_REQUEST_SUCCESS: - debug << QString("UPDATE_STATUS::ISMAS_UPDATE_REQUEST_SUCCESS: ") + case UPDATE_STATUS::ISMAS_WAIT_STATE_CHECK_PENDING: + debug << QString("UPDATE_STATUS::ISMAS_WAIT_STATE_CHECK_PENDING: ") + << status.m_statusDescription; + break; + case UPDATE_STATUS::ISMAS_WAIT_STATE_CHECK_FAILURE: + debug << QString("UPDATE_STATUS::ISMAS_WAIT_STATE_CHECK_FAILURE: ") + << status.m_statusDescription; + break; + case UPDATE_STATUS::ISMAS_WAIT_STATE_CHECK_TIMEOUT: + debug << QString("UPDATE_STATUS::ISMAS_WAIT_STATE_CHECK_: ") + << status.m_statusDescription; + break; + case UPDATE_STATUS::ISMAS_WAIT_STATE_CHECK_SUCCESS: + debug << QString("UPDATE_STATUS::ISMAS_WAIT_STATE_CHECK_SUCCESS: ") << status.m_statusDescription; break; - case UPDATE_STATUS::GIT_FETCH_UPDATES_REQUEST: - debug << QString("UPDATE_STATUS::GIT_FETCH_UPDATES_REQUEST: ") + case UPDATE_STATUS::GIT_FETCH_UPDATES: + debug << QString("UPDATE_STATUS::GIT_FETCH_UPDATES: ") << status.m_statusDescription; break; case UPDATE_STATUS::GIT_FETCH_UPDATES_REQUEST_FAILURE: @@ -653,16 +858,20 @@ QDebug operator<< (QDebug debug, UpdateStatus status) { QString& operator<< (QString& str, UpdateStatus status) { switch(status.m_updateStatus) { - case UPDATE_STATUS::ISMAS_UPDATE_REQUEST_PENDING: - str = QString("UPDATE_STATUS::ISMAS_UPDATE_REQUEST_PENDING: "); + case UPDATE_STATUS::UPDATE_PROCESS_SUCCESS: + str = QString("UPDATE_STATUS::UPDATE_PROCESS_SUCCESS: "); + str += status.m_statusDescription; + break; + case UPDATE_STATUS::ISMAS_WAIT_STATE_CHECK_PENDING: + str = QString("UPDATE_STATUS::ISMAS_WAIT_STATE_CHECK_PENDING: "); str += status.m_statusDescription; break; - case UPDATE_STATUS::ISMAS_UPDATE_REQUEST_SUCCESS: - str = QString("UPDATE_STATUS::ISMAS_UPDATE_REQUEST_SUCCESS: "); + case UPDATE_STATUS::ISMAS_WAIT_STATE_CHECK_SUCCESS: + str = QString("UPDATE_STATUS::ISMAS_WAIT_STATE_CHECK_SUCCESS: "); str += status.m_statusDescription; break; - case UPDATE_STATUS::GIT_FETCH_UPDATES_REQUEST: - str = QString("UPDATE_STATUS::GIT_FETCH_UPDATES_REQUEST: "); + case UPDATE_STATUS::GIT_FETCH_UPDATES: + str = QString("UPDATE_STATUS::GIT_FETCH_UPDATES: "); str += status.m_statusDescription; break; case UPDATE_STATUS::GIT_FETCH_UPDATES_REQUEST_FAILURE: diff --git a/worker.h b/worker.h index b997e1a..4a4a371 100644 --- a/worker.h +++ b/worker.h @@ -13,7 +13,6 @@ #include "update.h" #include "git/git_client.h" #include "ismas/ismas_client.h" -#include "apism/apism_client.h" #ifdef PTU5 #define SERIAL_PORT "ttymxc2" @@ -23,21 +22,31 @@ enum class UPDATE_STATUS : quint8 { - ISMAS_EMULATE_DATA_AVAILABLE, - ISMAS_UPDATE_REQUEST_PENDING, - ISMAS_UPDATE_REQUEST_FAILURE, - ISMAS_UPDATE_REQUEST_TIMEOUT, - ISMAS_UPDATE_REQUEST_SUCCESS, + NOT_DEFINED, + STEP_OK, + STEP_DONE, + STEP_FAIL, + ISMAS_WAIT_STATE_CHECK_PENDING, + ISMAS_WAIT_STATE_CHECK_FAILURE, + ISMAS_WAIT_STATE_CHECK_TIMEOUT, + ISMAS_WAIT_STATE_CHECK_SUCCESS, ISMAS_RESPONSE_RECEIVED, - GIT_CHECKOUT_BRANCH_REQUEST, + BACKEND_CONNECTED, + BACKEND_NOT_CONNECTED, + UPDATE_TRIGGER_SET, + UPDATE_TRIGGER_NOT_SET_OR_WRONG, + GIT_CLONE_AND_CHECKOUT_SUCCESS, + GIT_CLONE_AND_CHECKOUT_FAILURE, + GIT_CHECKOUT_BRANCH, GIT_CHECKOUT_BRANCH_REQUEST_FAILURE, GIT_CHECKOUT_BRANCH_NOT_EXISTS, GIT_CHECKOUT_BRANCH_CHECKOUT_ERROR, - GIT_FETCH_UPDATES_REQUEST, + GIT_FETCH_UPDATES, GIT_FETCH_UPDATES_REQUEST_FAILURE, GIT_FETCH_UPDATES_REQUEST_SUCCESS, GIT_PULL_UPDATES_SUCCESS, GIT_PULL_UPDATES_FAILURE, + EXEC_OPKG_COMMAND, EXEC_OPKG_COMMANDS, EXEC_OPKG_COMMAND_FAILURE, EXEC_OPKG_COMMAND_SUCCESS, @@ -51,6 +60,8 @@ enum class UPDATE_STATUS : quint8 { JSON_UPDATE, JSON_UPDATE_FAILURE, JSON_UPDATE_SUCCESS, + UPDATE_PROCESS_SUCCESS, + UPDATE_PROCESS_FAILURE, ISMAS_UPDATE_INFO_CONFIRM, ISMAS_UPDATE_INFO_CONFIRM_FAILURE, ISMAS_UPDATE_INFO_CONFIRM_SUCCESS, @@ -63,7 +74,8 @@ struct UpdateStatus { UPDATE_STATUS m_updateStatus; QString m_statusDescription; - explicit UpdateStatus(UPDATE_STATUS s, QString const &d) + explicit UpdateStatus(UPDATE_STATUS s = UPDATE_STATUS::NOT_DEFINED, + QString const &d = QString("")) : m_updateStatus(s), m_statusDescription(d) {} }; @@ -78,10 +90,6 @@ class Worker : public QObject { hwinf *m_hw; WorkerThread m_workerThread; - QTimer m_startUpdateProcess; - QTimer m_emergencyTimer; - Update *m_update; - ApismClient m_apismClient; int const m_customerNr; QString const m_customerNrStr; int const m_machineNr; @@ -90,8 +98,9 @@ class Worker : public QObject { QString const m_branchName; QString const m_customerRepositoryPath; QString const m_customerRepository; + Update *m_update; + IsmasClient m_ismasClient; GitClient m_gc; - bool m_maintenanceMode; QString const m_osVersion; QString const m_atbqtVersion; QString const m_cpuSerial; @@ -107,12 +116,14 @@ class Worker : public QObject { int m_ismasUpdateRequests; QTimer m_waitForNewUpdates; - IsmasClient m_ismasClient; - UPDATE_STATUS m_updateStatus; - QString m_statusDescription; + UpdateStatus m_updateStatus; - void executeOpkgCommand(QString opkgCommand); + QStringList m_filesToUpdate; + bool m_updateProcessRunning; + int m_displayIndex; + + bool executeOpkgCommand(QString opkgCommand); QString getOsVersion() const; QString getATBQTVersion() const; QString getCPUSerial() const; @@ -124,21 +135,31 @@ class Worker : public QObject { qint64 getFileSize(QString const &fileName) const; public: + static const QString UPDATE_STEP_OK; + static const QString UPDATE_STEP_DONE; + static const QString UPDATE_STEP_FAIL; + static const QString UPDATE_STEP_SUCCESS; + explicit Worker(hwinf *hw, int customerNr, // 281 int machineNr, int zoneNr, QString branchName, QString workingDir = ".", - bool maintenanceMode = false, bool dryRun = false, QObject *parent = nullptr, char const *serialInterface = SERIAL_PORT, char const *baudrate = "115200"); ~Worker(); - void quit() { return m_workerThread.quit(); } - static int read1stLineOfFile(QString fileName); + IsmasClient &getIsmasClient() { return m_ismasClient; } + IsmasClient const &getIsmasClient() const { return m_ismasClient; } + + bool updateProcessRunning() const { return m_updateProcessRunning; } + + int machineNr() const { return m_machineNr; } + int customerNr() const { return m_customerNr; } + int zoneNr() const { return m_zoneNr; } //friend QDebug operator<<(QDebug debug, Worker const &w) { // Q_UNUSED(w); @@ -150,24 +171,29 @@ public: //} signals: - void handleChangedFiles(QStringList); - void summarizeUpload(QStringList); - void summarizeRepositoryStatus(); - void sendCmdSendVersionToIsmas(); - void finishUpdateProcess(bool changes); - void terminateUpdateProcess(); + void appendText(QString, QString); + void showErrorMessage(QString title, QString description); + void setProgress(quint8); + void stopStartTimer(); + void restartExitTimer(); public slots: - void onIsmasResponseReceived(QJsonObject ismasResponse); + void update(); private slots: - void askIsmasForNewData(); - void onSendCmdSendVersionToIsmas(); - void onSummarizeRepositoryStatus(); - void onFinishUpdateProcess(bool changes); - void onTerminateUpdateProcess(); - void onSummarizeUpload(QStringList); - void onHandleChangedFiles(QStringList); + bool backendConnected(); + bool updateTriggerSet(); + bool customerEnvironment(); + bool filesToUpdate(); + bool updateFiles(quint8 percent); + bool syncCustomerRepositoryAndFS(); + bool sendIsmasLastVersionNotification(); + bool saveLogFile(); + +private: + PSAInstalled getPSAInstalled(); + QString sendCmdSendVersionToIsmas(); + void privateUpdate(); }; #endif // WORKER_H_INCLUDED