489 lines
16 KiB
C++
Executable File
489 lines
16 KiB
C++
Executable File
/**
|
|
* Handler for PDF download coordination
|
|
* $Id$
|
|
* $HeadURL$
|
|
* $Author$
|
|
* Created by Hannes Fritsche, NLE, 26-04-2019
|
|
*/
|
|
|
|
#include "handler_pdf_download.h"
|
|
|
|
#include "WebSocketInterface/Messages/reply_message.h"
|
|
#include <QUuid>
|
|
#include "pdf_downloader.h"
|
|
#include <ngldb/db_service_handler.h>
|
|
#include <nglsettings/nglsettings_connections.h>
|
|
#include <nglsettings/nglsettings_settings.h>
|
|
#include <ngldb/dbtransaction.h>
|
|
#include <ngldb/dbconnection.h>
|
|
#include <ngldb/ngldb_export.h>
|
|
#include <ngldb/nsqlquery.h>
|
|
#include <ngltools/ngltools_filesystem.h>
|
|
#include "main_handler.h"
|
|
#include "settings.h"
|
|
#include <QFileInfo>
|
|
#include <QDir>
|
|
|
|
namespace OcBaseDownload
|
|
{
|
|
|
|
HandlerPdfDownload::HandlerPdfDownload(MainHandler *mainHandler, QObject *parent)
|
|
: QObject(parent)
|
|
, Interface::Fts::GetPdfListRequestHandler(mainHandler->dds()->fts())
|
|
, Interface::Fts::StartPdfDownloadRequestHandler(mainHandler->dds()->fts())
|
|
, Interface::Fts::OcPdfDownloadRequestHandler(mainHandler->dds()->fts())
|
|
, m_fts(mainHandler->dds()->fts())
|
|
, m_webSocket(mainHandler->handlerWebSocket())
|
|
, m_mainHandler(mainHandler)
|
|
, m_exerciseId(0)
|
|
, m_hostname(NGL::Connections::hostName(NGL::Connections::eConnection::SCM_WEBSOCKET))
|
|
, m_remoteHostName(Settings::remoteDbHostName())
|
|
, m_currentPort(NGL::Connections::port(NGL::Connections::eConnection::SCM_WEBSOCKET))
|
|
, m_currentMode(Mode::PORT_REQUEST)
|
|
, m_downloader(nullptr)
|
|
, m_logger(getLogger("HandlerPdfDownload"))
|
|
{
|
|
}
|
|
|
|
HandlerPdfDownload::~HandlerPdfDownload()
|
|
{
|
|
m_fts = nullptr;
|
|
}
|
|
|
|
bool HandlerPdfDownload::init()
|
|
{
|
|
INFO_LOG(m_logger) << "HandlerPdfDownload initialised!";
|
|
|
|
return true;
|
|
}
|
|
|
|
void HandlerPdfDownload::handleServicePortsInformation(const QVector<WebSocketInterface::Messages::ServicePortsInformation::ExerciseInformation> &portsInformation)
|
|
{
|
|
m_webSocket->close();
|
|
int flmPort = 0;
|
|
|
|
for (const auto &exercise : portsInformation)
|
|
{
|
|
if (exercise.exerciseId == 0)
|
|
{
|
|
for (const auto &service : exercise.services)
|
|
{
|
|
if (service.abbreviation == QStringLiteral("flm"))
|
|
{
|
|
for (const auto &port : service.ports)
|
|
{
|
|
if (port.type == Core::PortType::WebSocketServer)
|
|
{
|
|
flmPort = port.number;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
m_currentMode = Mode::LIST_REQUEST;
|
|
|
|
if (flmPort)
|
|
m_webSocket->open(m_hostname, flmPort);
|
|
else
|
|
{
|
|
ERROR_LOG(m_logger) << "Could not connect to FileManagement WebSocket server.";
|
|
m_currentMode = Mode::PORT_REQUEST;
|
|
}
|
|
}
|
|
|
|
void HandlerPdfDownload::handlePdfListData(const WebSocketInterface::Messages::PdfListMessage::PdfListData &pdfListData)
|
|
{
|
|
m_webSocket->close();
|
|
|
|
PdfListReply rep;
|
|
|
|
auto &documentInformation = rep.documents();
|
|
documentInformation.reserve(pdfListData.pdfData.size());
|
|
for (const WebSocketInterface::Messages::PdfListMessage::PdfInformation ¤tInfo : pdfListData.pdfData)
|
|
documentInformation.emplace_back(currentInfo.id,
|
|
currentInfo.name.toStdString(),
|
|
false,
|
|
false);
|
|
|
|
disconnect(m_webSocket.get(), &WebSocketInterface::WebSocketInterfaceHandler::connected, this, &HandlerPdfDownload::onConnected);
|
|
disconnect(m_webSocket.get(), &WebSocketInterface::WebSocketInterfaceHandler::disconnected, this, &HandlerPdfDownload::onDisconnected);
|
|
|
|
m_fts->getPdfListReply(m_pdfListCookie, rep);
|
|
|
|
m_pdfData = pdfListData.pdfData;
|
|
m_currentMode = Mode::PORT_REQUEST;
|
|
m_webSocket->setCurrentDownload(WebSocketInterface::CurrentDownload::NOTHING);
|
|
}
|
|
|
|
void HandlerPdfDownload::onGetPdfListRequest(const rti::core::SampleIdentity &cookie, const GetPdfListRequest &request)
|
|
{
|
|
m_webSocket->setCurrentDownload(WebSocketInterface::CurrentDownload::PDF);
|
|
|
|
m_hostname = NGL::Connections::hostName(NGL::Connections::eConnection::SCM_WEBSOCKET);
|
|
m_currentPort = NGL::Connections::port(NGL::Connections::eConnection::SCM_WEBSOCKET);
|
|
|
|
m_pdfListCookie = cookie;
|
|
m_hostname = QString::fromStdString(request.hostname());
|
|
m_currentPort = request.portNumber();
|
|
m_exerciseId = request.exerciseId();
|
|
|
|
connect(m_webSocket.get(), &WebSocketInterface::WebSocketInterfaceHandler::connected, this, &HandlerPdfDownload::onConnected);
|
|
connect(m_webSocket.get(), &WebSocketInterface::WebSocketInterfaceHandler::disconnected, this, &HandlerPdfDownload::onDisconnected);
|
|
|
|
openWebSocket();
|
|
}
|
|
|
|
void HandlerPdfDownload::onStartPdfDownloadRequest(const rti::core::SampleIdentity &cookie, const StartPdfDownloadRequest &request)
|
|
{
|
|
|
|
ERROR_LOG(m_logger) <<" onOcPdfDownloadRequest START" ;
|
|
m_downloadReply = PdfDownloadReply();
|
|
m_downloadCookie = cookie;
|
|
|
|
if (m_logger.isDebugEnabled())
|
|
{
|
|
QString str = QStringLiteral("Got PDF download request for ids: ");
|
|
|
|
for (int32_t id : request.documentIds())
|
|
str.append(QString::number(id) + QStringLiteral(" "));
|
|
|
|
DEBUG_LOG(m_logger) << str;
|
|
}
|
|
|
|
if (m_hostname.isEmpty())
|
|
{
|
|
QString errorStr = QStringLiteral("Not able to start PDF download. Hostname not set.");
|
|
ERROR_LOG(m_logger) << errorStr;
|
|
m_downloadReply.errorString(errorStr.toStdString());
|
|
m_fts->startPdfDownloadReply(m_downloadCookie, m_downloadReply);
|
|
return;
|
|
}
|
|
|
|
typedef WebSocketInterface::Messages::PdfListMessage::PdfInformation pdfInfo;
|
|
|
|
const auto containsId = [](const std::vector<int> &cont, int idToSearch) -> bool
|
|
{
|
|
for (const int curId : cont)
|
|
if (curId == idToSearch)
|
|
return true;
|
|
return false;
|
|
};
|
|
QVector<pdfInfo> pdfInfoVec;
|
|
for (const auto ¤t : qAsConst(m_pdfData))
|
|
{
|
|
if (!containsId(request.documentIds(), current.id))
|
|
continue;
|
|
|
|
pdfInfoVec.append(current);
|
|
}
|
|
|
|
if (m_downloader)
|
|
{
|
|
disconnect(m_downloader);
|
|
delete m_downloader;
|
|
m_downloader = nullptr;
|
|
}
|
|
|
|
m_downloader = new PdfDownloader(pdfInfoVec, m_mainHandler, m_hostname, m_exerciseId, this);
|
|
|
|
connect(m_downloader, &PdfDownloader::newState,
|
|
this, &HandlerPdfDownload::onNewDownloadState);
|
|
|
|
connect(m_downloader, &PdfDownloader::allDownloadsFinished,
|
|
this, &HandlerPdfDownload::onAllDownloadsFinished);
|
|
|
|
m_downloader->startDownload();
|
|
}
|
|
|
|
void HandlerPdfDownload::onOcPdfDownloadRequest(const rti::core::SampleIdentity &cookie, const OcPdfDownloadRequest &request)
|
|
{
|
|
DEBUG_LOG(m_logger) <<LOGFUNCTION<<" START OcPdfDownloadRequest" ;
|
|
m_ocPdfDownloadCookie = cookie;
|
|
m_ocPdfDownloadReply = Core::FunctionReply();
|
|
|
|
if(openRemoteDbConnection(QStringLiteral("lts_ets_pro")) == false)
|
|
{
|
|
QString errorStr = QStringLiteral("Not able to open remote connection to DB");
|
|
ERROR_LOG(m_logger) << errorStr;
|
|
m_ocPdfDownloadReply.errorString(errorStr.toStdString());
|
|
m_fts->ocPdfDownloadReply(m_ocPdfDownloadCookie, m_ocPdfDownloadReply);
|
|
return;
|
|
}
|
|
|
|
DEBUG_LOG(m_logger) << "Got PDF download request for ids: "<< request.folderId();
|
|
|
|
m_folderId = request.folderId();
|
|
if(m_folderId == -1)
|
|
{
|
|
QString errorStr = QStringLiteral("Not able to start PDF download. Folder id not valid.");
|
|
ERROR_LOG(m_logger) << errorStr;
|
|
m_ocPdfDownloadReply.errorString(errorStr.toStdString());
|
|
m_fts->ocPdfDownloadReply(m_ocPdfDownloadCookie, m_ocPdfDownloadReply);
|
|
return;
|
|
}
|
|
m_operatorName = QString::fromStdString(request.matrixOperator());
|
|
if (m_hostname.isEmpty())
|
|
{
|
|
QString errorStr = QStringLiteral("Not able to start PDF download. Hostname not set.");
|
|
ERROR_LOG(m_logger) << errorStr;
|
|
m_ocPdfDownloadReply.errorString(errorStr.toStdString());
|
|
m_fts->ocPdfDownloadReply(m_ocPdfDownloadCookie, m_ocPdfDownloadReply);
|
|
return;
|
|
}
|
|
|
|
exportOcPdfFileContent();
|
|
|
|
m_fts->ocPdfDownloadReply(m_ocPdfDownloadCookie, m_ocPdfDownloadReply);
|
|
closeDb(m_remoteDbConnection);
|
|
|
|
}
|
|
|
|
void HandlerPdfDownload::exportOcPdfFileContent()
|
|
{
|
|
// handling FLM data
|
|
using namespace FileManagement;
|
|
auto remoteDb = std::unique_ptr<NGLDB::DbServiceHandler<DatabaseInterface>>(new NGLDB::DbServiceHandler<DatabaseInterface>());
|
|
if (!remoteDb->init(0, m_remoteDbConnection))
|
|
{
|
|
const QString err = tr("Can't open remote Database");
|
|
m_ocPdfDownloadReply.errorString(err.toStdString());
|
|
return;
|
|
}
|
|
|
|
auto remoteDbIfc = remoteDb->db();
|
|
const QString dir = QStringLiteral("%1/OcPdf/%2/").arg(QDir::tempPath()).arg(m_operatorName);
|
|
DEBUG_LOG(m_logger)<<" export path: "<<dir;
|
|
QDir directory(dir);
|
|
if(!directory.exists())
|
|
directory.mkpath(dir);
|
|
const QString fExts = QStringLiteral(".pdf");
|
|
|
|
|
|
//first we look up our username folder
|
|
QString strm = QStringLiteral("Select id from flm.flm_folder WHERE name = '" ) + m_operatorName + QStringLiteral("' and '") +
|
|
QString::number(m_folderId) + QStringLiteral("' = ANY(path) LIMIT 1;");
|
|
|
|
DEBUG_LOG(m_logger) << "folder content ID querry" << strm;
|
|
|
|
std::unique_ptr<NSqlQuery> query = std::unique_ptr<NSqlQuery>(new NSqlQuery(remoteDbIfc->database(), m_logger));
|
|
query->prepare(strm);
|
|
|
|
qlonglong folderId = -1;
|
|
if (query->exec())
|
|
{
|
|
while (query->next())
|
|
{
|
|
folderId = query->value(0).toLongLong();
|
|
}
|
|
}
|
|
|
|
if(folderId < 0)
|
|
{
|
|
const QString err = tr("Can't find user folder in remote Database");
|
|
m_ocPdfDownloadReply.errorString(err.toStdString());
|
|
return;
|
|
}
|
|
|
|
/// check first if the pdf file is not alreay exist and oudated without loading file content
|
|
/// get ids of pdf file matching the named condition
|
|
QString where = QStringLiteral(" WHERE folder_id =%1 ").arg(QString::number(folderId)) +
|
|
QStringLiteral(" AND file_type_id=%1 ").arg(FileManagement::FileType_def::Pdf);
|
|
QString tableName(QStringLiteral("flm.flm_file_content"));
|
|
|
|
|
|
QString stmt(QStringLiteral("SELECT id, name, last_modified "
|
|
" FROM ") + tableName + where);
|
|
|
|
QStringList idsList;
|
|
query->prepare(stmt);
|
|
if (query->exec())
|
|
{
|
|
Database::FlmFileContent data;
|
|
while (query->next())
|
|
{
|
|
int i = 0;
|
|
data.id = query->value(i++).toLongLong();
|
|
data.name = query->value(i++).toString();
|
|
data.lastModified = query->value(i++).toLongLong();
|
|
QString fileName = dir + QString(data.name).trimmed() + fExts;
|
|
QFileInfo fileInfo(fileName);
|
|
bool fileExists = fileInfo.exists();
|
|
if(!fileExists ||
|
|
(data.lastModified > fileInfo.lastModified().toMSecsSinceEpoch()))
|
|
{
|
|
idsList << QString::number(data.id);
|
|
}
|
|
}
|
|
}
|
|
|
|
if(idsList.isEmpty())
|
|
{
|
|
WARNING_LOG(m_logger)<< " pdf files outdated! ";
|
|
|
|
return;
|
|
}
|
|
|
|
/// start a new query with id matching the define condition of beeing newer than current existing file
|
|
/// or file doesn't exist
|
|
/// folderId is used in the first statement so no need to reuse it for second one. just use id offlm_file_content
|
|
where = QStringLiteral(" WHERE id IN (%1)").arg(idsList.join(QStringLiteral(","))) +
|
|
QStringLiteral(" AND file_type_id=%1 ").arg(FileManagement::FileType_def::Pdf);
|
|
tableName = (QStringLiteral("flm.flm_file_content"));
|
|
stmt = (QStringLiteral("SELECT id, name, file_status_id, content, last_modified FROM ") + tableName + where);
|
|
|
|
DEBUG_LOG(m_logger) << "### statement: " << stmt;
|
|
|
|
query->prepare(stmt);
|
|
|
|
QVector<Database::FlmFileContent> dataVec;
|
|
if (query->exec())
|
|
{
|
|
Database::FlmFileContent data;
|
|
while (query->next())
|
|
{
|
|
int i = 0;
|
|
data.id = query->value(i++).toLongLong();
|
|
data.name = query->value(i++).toString();
|
|
data.fileStatusId = static_cast<FileManagement::FileStatus_def::type>(query->value(i++).toInt());
|
|
data.content = query->value(i++).toByteArray();
|
|
data.lastModified = query->value(i++).toLongLong();
|
|
|
|
if(data.fileStatusId == FileManagement::FileStatus::Deleted)
|
|
{
|
|
DEBUG_LOG(m_logger)<< " skip ";
|
|
continue;
|
|
}
|
|
dataVec.append(data);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
const QString errorStr = tr("Not able to export PDF.");
|
|
ERROR_LOG(m_logger) << errorStr;
|
|
m_ocPdfDownloadReply.errorString(errorStr.toStdString());
|
|
return;
|
|
}
|
|
|
|
for(const auto &data : dataVec)
|
|
{
|
|
QByteArray content = data.content;
|
|
QString fileName = dir + QString(data.name).trimmed() + fExts;
|
|
QFile file(fileName);
|
|
QFileInfo fileInfo(file);
|
|
// remove if exist file by their name
|
|
if(fileInfo.exists() && file.remove() == false)
|
|
{
|
|
QString err = QStringLiteral("Couldn't replace existing file: ") + data.name;
|
|
WARNING_LOG(m_logger)<< err;
|
|
continue;
|
|
}
|
|
|
|
if(!file.open(QIODevice::WriteOnly))
|
|
{
|
|
QString err = tr("Failed to write file: ") + (data.name);
|
|
m_ocPdfDownloadReply.errorString(err.toStdString());
|
|
return;
|
|
}
|
|
|
|
file.write(content);
|
|
file.close();
|
|
}
|
|
}
|
|
|
|
bool HandlerPdfDownload::openRemoteDbConnection(const QString &remoteDatabaseName)
|
|
{
|
|
DEBUG_LOG(m_logger) <<" Open RemoteDb Connection..." ;
|
|
if (m_remoteDbConnection.isValid())
|
|
closeDb(m_remoteDbConnection);
|
|
|
|
bool bOk;
|
|
m_remoteDbConnection = openDb(remoteDatabaseName, true, &bOk);
|
|
if (!bOk)
|
|
return false;
|
|
return true;
|
|
}
|
|
|
|
QSqlDatabase HandlerPdfDownload::openDb(const QString &databaseName, bool remote, bool *bOk)
|
|
{
|
|
if (bOk)
|
|
*bOk = true;
|
|
// open postgres db, read table structure, read static data
|
|
auto s = Settings::settings();
|
|
const QString dbUser(QStringLiteral("ets_exm"));
|
|
const QString dbPasswd(QStringLiteral("ets11de"));
|
|
QSqlDatabase dbConnection = DBConnection::open(m_logger,
|
|
dbUser,
|
|
dbPasswd,
|
|
s->databaseDriver(),
|
|
remote ? m_remoteHostName : s->databaseHostname(),
|
|
remote ? Settings::remoteDbName() : databaseName);
|
|
DEBUG_LOG(m_logger) << "Trying to open database " << s->databaseHostname() << ":" << databaseName;
|
|
if (!dbConnection.isOpen())
|
|
{
|
|
ERROR_LOG(m_logger) << "Error opening database " << s->databaseHostname() << ":" << databaseName;
|
|
if (bOk)
|
|
*bOk = false;
|
|
}
|
|
else
|
|
NOTICE_LOG(m_logger) << "Opened database connection " << dbConnection.connectionName();
|
|
return dbConnection;
|
|
}
|
|
|
|
void HandlerPdfDownload::closeDb(QSqlDatabase &dbConn)
|
|
{
|
|
const QString connName = dbConn.connectionName();
|
|
NOTICE_LOG(m_logger) << "Closing database connection " << connName;
|
|
dbConn.close();
|
|
dbConn = QSqlDatabase();
|
|
QSqlDatabase::removeDatabase(connName);
|
|
}
|
|
|
|
void HandlerPdfDownload::onConnected()
|
|
{
|
|
INFO_LOG(m_logger) << "Connected to WebSocket server";
|
|
|
|
switch (m_currentMode)
|
|
{
|
|
case Mode::PORT_REQUEST:
|
|
m_webSocket->send(new WebSocketInterface::Messages::ServicePortsInformationRequest(QUuid::createUuid().toString()));
|
|
break;
|
|
case Mode::LIST_REQUEST:
|
|
m_webSocket->send(new WebSocketInterface::Messages::PdfListRequest(QUuid::createUuid().toString(), m_exerciseId));
|
|
break;
|
|
}
|
|
}
|
|
|
|
void HandlerPdfDownload::onDisconnected()
|
|
{
|
|
INFO_LOG(m_logger) << "Disconnected from server.";
|
|
}
|
|
|
|
void HandlerPdfDownload::onNewDownloadState(int progress, const QString &msg)
|
|
{
|
|
DEBUG_LOG(m_logger) << msg;
|
|
m_downloadReply.replyState(Core::FtReplyState::InProgress);
|
|
m_downloadReply.progress(progress);
|
|
m_downloadReply.currentStep(msg.toStdString());
|
|
m_fts->startPdfDownloadReply(m_downloadCookie, m_downloadReply);
|
|
}
|
|
|
|
void HandlerPdfDownload::onAllDownloadsFinished()
|
|
{
|
|
DEBUG_LOG(m_logger) << "Downloads finished";
|
|
m_downloadReply.replyState(Core::FtReplyState::Completed);
|
|
m_downloadReply.currentStep(tr("Downloads finished").toStdString());
|
|
m_downloadReply.progress(100);
|
|
m_fts->startPdfDownloadReply(m_downloadCookie, m_downloadReply);
|
|
}
|
|
|
|
void HandlerPdfDownload::openWebSocket()
|
|
{
|
|
DEBUG_LOG(m_logger) << "Opening websocket to: " << m_hostname << ":" << m_currentPort;
|
|
m_webSocket->open(m_hostname, m_currentPort);
|
|
}
|
|
|
|
} // namespace OcBaseDownload
|