/** \file LogThread.cpp
\brief The thread to do the log but not block the main thread
\author alpha_one_x86
\licence GPL3, see the file COPYING */
#include "LogThread.h"
#include "ResourcesManager.h"
#include "OptionEngine.h"
#include "cpp11addition.h"
#ifdef Q_OS_WIN32
#ifndef NOMINMAX
#define NOMINMAX
#endif
#include <windows.h>
#endif
#include <QMessageBox>
std::string LogThread::text_header_copy="[Copy] ";
std::string LogThread::text_header_move="[Move] ";
std::string LogThread::text_header_skip="[Skip] ";
std::string LogThread::text_header_stop="[Stop] ";
std::string LogThread::text_header_error="[Error] ";
std::string LogThread::text_header_MkPath="[MkPath] ";
std::string LogThread::text_header_RmPath="[RmPath] ";
std::string LogThread::text_var_source="%source%";
std::string LogThread::text_var_size="%size%";
std::string LogThread::text_var_destination="%destination%";
std::string LogThread::text_var_path="%path%";
std::string LogThread::text_var_error="%error%";
std::string LogThread::text_var_mtime="%mtime%";
std::string LogThread::text_var_time="%time%";
std::string LogThread::text_var_timestring="%dd.MM.yyyy h:m:s%";
#ifdef Q_OS_WIN32
std::string LogThread::text_var_computer="%computer%";
std::string LogThread::text_var_user="%user%";
#endif
std::string LogThread::text_var_operation="%operation%";
std::string LogThread::text_var_rmPath="%rmPath%";
std::string LogThread::text_var_mkPath="%mkPath%";
LogThread::LogThread()
{
sync=false;
connect(OptionEngine::optionEngine,&OptionEngine::newOptionValue, this, &LogThread::newOptionValue);
enabled=false;
moveToThread(this);
start(QThread::IdlePriority);
connect(this, &LogThread::newData, this,&LogThread::realDataWrite,Qt::QueuedConnection);
newOptionValue("Write_log", "transfer", OptionEngine::optionEngine->getOptionValue("Write_log","transfer"));
newOptionValue("Write_log", "error", OptionEngine::optionEngine->getOptionValue("Write_log","error"));
newOptionValue("Write_log", "folder", OptionEngine::optionEngine->getOptionValue("Write_log","folder"));
newOptionValue("Write_log", "sync", OptionEngine::optionEngine->getOptionValue("Write_log","sync"));
newOptionValue("Write_log", "transfer_format", OptionEngine::optionEngine->getOptionValue("Write_log","transfer_format"));
newOptionValue("Write_log", "error_format", OptionEngine::optionEngine->getOptionValue("Write_log","error_format"));
newOptionValue("Write_log", "folder_format", OptionEngine::optionEngine->getOptionValue("Write_log","folder_format"));
newOptionValue("Write_log", "sync", OptionEngine::optionEngine->getOptionValue("Write_log","sync"));
newOptionValue("Write_log", "enabled", OptionEngine::optionEngine->getOptionValue("Write_log","enabled"));
#ifdef Q_OS_WIN32
DWORD size=0;
WCHAR * computerNameW=new WCHAR[size];
if(GetComputerNameW(computerNameW,&size))
computer=QString::fromWCharArray(computerNameW,size-1).toStdString();
else
computer="Unknown computer";
delete computerNameW;
WCHAR * userNameW=new WCHAR[size];
if(GetUserNameW(userNameW,&size))
user=QString::fromWCharArray(userNameW,size-1).toStdString();
else
user="Unknown user";
delete userNameW;
#endif
#ifdef Q_OS_WIN32
lineReturn="\r\n";
#else
lineReturn="\n";
#endif
}
LogThread::~LogThread()
{
closeLogs();
quit();
wait();
}
bool LogThread::logTransfer() const
{
return enabled && log_enable_transfer;
}
void LogThread::openLogs()
{
if(stringtobool(OptionEngine::optionEngine->getOptionValue("Write_log","enabled"))==false)
return;
if(log.isOpen())
{
QMessageBox::critical(NULL,tr("Error"),tr("Log file already open, error: %1").arg(log.errorString()));
ULTRACOPIER_DEBUGCONSOLE(Ultracopier::DebugLevel_Warning,"log file already open, error: "+log.errorString().toStdString());
return;
}
log.setFileName(QString::fromStdString(OptionEngine::optionEngine->getOptionValue("Write_log","file")));
if(sync)
{
if(!log.open(QIODevice::WriteOnly|QIODevice::Unbuffered))
{
QMessageBox::critical(NULL,tr("Error"),tr("Unable to open the log file, error: %1").arg(log.errorString()));
ULTRACOPIER_DEBUGCONSOLE(Ultracopier::DebugLevel_Warning,"Unable to open the log file, error: "+log.errorString().toStdString());
}
else
ULTRACOPIER_DEBUGCONSOLE(Ultracopier::DebugLevel_Notice,"opened log: "+OptionEngine::optionEngine->getOptionValue("Write_log","file"));
}
else
{
if(!log.open(QIODevice::WriteOnly))
{
QMessageBox::critical(NULL,tr("Error"),tr("Unable to open the log file, error: %1").arg(log.errorString()));
ULTRACOPIER_DEBUGCONSOLE(Ultracopier::DebugLevel_Warning,"Unable to open the log file, error: "+log.errorString().toStdString());
}
else
ULTRACOPIER_DEBUGCONSOLE(Ultracopier::DebugLevel_Notice,"opened log: "+OptionEngine::optionEngine->getOptionValue("Write_log","file"));
}
}
void LogThread::closeLogs()
{
if(log.isOpen() && data.size()>0)
log.write(data.data(),data.size());
log.close();
}
void LogThread::newTransferStart(const Ultracopier::ItemOfCopyList &item)
{
if(!logTransfer())
return;
std::string text;
if(item.mode==Ultracopier::Copy)
text=LogThread::text_header_copy+transfer_format+lineReturn;
else
text=LogThread::text_header_move+transfer_format+lineReturn;
text=replaceBaseVar(text);
//Variable is %source%, %size%, %destination%
stringreplaceAll(text,LogThread::text_var_source,item.sourceFullPath);
stringreplaceAll(text,LogThread::text_var_size,std::to_string(item.size));
stringreplaceAll(text,LogThread::text_var_destination,item.destinationFullPath);
stringreplaceAll(text,LogThread::text_var_time,QDateTime::currentDateTime().toString(QString::fromStdString(LogThread::text_var_timestring)).toStdString());
emit newData(text);
}
/** method called when new transfer is started */
void LogThread::transferSkip(const Ultracopier::ItemOfCopyList &item)
{
if(!logTransfer())
return;
std::string text=LogThread::text_header_skip+transfer_format+lineReturn;
text=replaceBaseVar(text);
//Variable is %source%, %size%, %destination%
stringreplaceAll(text,LogThread::text_var_source,item.sourceFullPath);
stringreplaceAll(text,LogThread::text_var_size,std::to_string(item.size));
stringreplaceAll(text,LogThread::text_var_destination,item.destinationFullPath);
stringreplaceAll(text,LogThread::text_var_time,QDateTime::currentDateTime().toString(QString::fromStdString(LogThread::text_var_timestring)).toStdString());
emit newData(text);
}
void LogThread::newTransferStop(const Ultracopier::ItemOfCopyList &item)
{
if(!logTransfer())
return;
std::string text=LogThread::text_header_stop+transfer_format+lineReturn;
text=replaceBaseVar(text);
//Variable is %source%, %size%, %destination%
stringreplaceAll(text,LogThread::text_var_source,item.sourceFullPath);
stringreplaceAll(text,LogThread::text_var_size,std::to_string(item.size));
stringreplaceAll(text,LogThread::text_var_destination,item.destinationFullPath);
stringreplaceAll(text,LogThread::text_var_time,QDateTime::currentDateTime().toString(QString::fromStdString(LogThread::text_var_timestring)).toStdString());
emit newData(text);
}
void LogThread::error(const std::string &path,const uint64_t &size,const uint64_t &mtime,const std::string &error)
{
if(!log_enable_error)
return;
std::string text=LogThread::text_header_error+error_format+lineReturn;
text=replaceBaseVar(text);
//Variable is %path%, %size%, %mtime%, %error%
stringreplaceAll(text,LogThread::text_var_path,path);
stringreplaceAll(text,LogThread::text_var_size,std::to_string(size));
stringreplaceAll(text,LogThread::text_var_mtime,QDateTime::fromTime_t(static_cast<unsigned int>(mtime)).toString(Qt::ISODate).toStdString());
stringreplaceAll(text,LogThread::text_var_error,error);
stringreplaceAll(text,LogThread::text_var_time,QDateTime::fromTime_t(static_cast<unsigned int>(mtime)).toString(QString::fromStdString(LogThread::text_var_timestring)).toStdString());
emit newData(text);
}
void LogThread::run()
{
exec();
}
void LogThread::realDataWrite(const std::string &text)
{
#ifdef ULTRACOPIER_DEBUG
if(!log.isOpen())
{
ULTRACOPIER_DEBUGCONSOLE(Ultracopier::DebugLevel_Critical,"transfer log not open");
return;
}
#endif // ULTRACOPIER_DEBUG
ULTRACOPIER_DEBUGCONSOLE(Ultracopier::DebugLevel_Notice,"start");
if(log.write(text.data(),text.size())==-1)
{
ULTRACOPIER_DEBUGCONSOLE(Ultracopier::DebugLevel_Warning,"unable to write into transfer log: "+log.errorString().toStdString());
return;
}
if(sync)
log.flush();
}
void LogThread::newOptionValue(const std::string &group,const std::string &name,const std::string &value)
{
if(group!="Write_log")
return;
if(name=="transfer_format")
transfer_format=value;
else if(name=="error_format")
error_format=value;
else if(name=="folder_format")
folder_format=value;
else if(name=="sync")
{
sync=stringtobool(value);
ULTRACOPIER_DEBUGCONSOLE(Ultracopier::DebugLevel_Notice,"sync flag is set on: "+value);
if(sync)
{
if(log.isOpen())
log.flush();
}
}
else if(name=="transfer")
log_enable_transfer=stringtobool(OptionEngine::optionEngine->getOptionValue("Write_log","enabled")) && stringtobool(value);
else if(name=="error")
log_enable_error=stringtobool(OptionEngine::optionEngine->getOptionValue("Write_log","enabled")) && stringtobool(value);
else if(name=="folder")
log_enable_folder=stringtobool(OptionEngine::optionEngine->getOptionValue("Write_log","enabled")) && stringtobool(value);
if(name=="enabled")
{
enabled=stringtobool(value);
if(enabled)
openLogs();
else
closeLogs();
}
}
std::string LogThread::replaceBaseVar(std::string text)
{
stringreplaceAll(text,LogThread::text_var_time,QDateTime::currentDateTime().toString(QString::fromStdString(LogThread::text_var_timestring)).toStdString());
#ifdef Q_OS_WIN32
stringreplaceAll(text,LogThread::text_var_computer,computer);
stringreplaceAll(text,LogThread::text_var_user,user);
#endif
return text;
}
void LogThread::rmPath(const std::string &path)
{
if(!logTransfer())
return;
std::string text=LogThread::text_header_RmPath+folder_format+lineReturn;
text=replaceBaseVar(text);
//Variable is %operation% %path%
stringreplaceAll(text,LogThread::text_var_path,path);
stringreplaceAll(text,LogThread::text_var_operation,LogThread::text_var_rmPath);
emit newData(text);
}
void LogThread::mkPath(const std::string &path)
{
if(!logTransfer())
return;
std::string text=LogThread::text_header_MkPath+folder_format+lineReturn;
text=replaceBaseVar(text);
//Variable is %operation% %path%
stringreplaceAll(text,LogThread::text_var_path,path);
stringreplaceAll(text,LogThread::text_var_operation,LogThread::text_var_mkPath);
emit newData(text);
}