Files
RRJServer/ServerLMS/Systems/updatecontroller.cpp

596 lines
16 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#include "updatecontroller.h"
UpdateController::UpdateController(QObject *parent) :
QObject(parent),
commonClientHandler(nullptr)
{
buildPath = QDir::currentPath() + "/" + applicationFolderName;
sharedDataPath = QDir::currentPath() + "/" + sharedDataFolderName;
emit sigLogMessage(buildPath);
qDebug() << hashFileName;
}
void UpdateController::initialize(CommonClientHandler *commonClientHandler,DataParser *dataParser,AssetsManager *assetManager,Logger *logger)
{
this->commonClientHandler = commonClientHandler;
this->dataParser = dataParser;
this->assetManager = assetManager;
sizeToSend = 0;
assetManager->initialize(this,dataParser);
connect(this,&UpdateController::sigLogMessage,logger,&Logger::addTextToLogger,Qt::AutoConnection);
calculateFullHash();
currentStreamingPath = assetManager->setVersion("base");
setUpCurrentServerHash();
mutex = new QMutex;
qDebug() << "UpdateController init thread ID " << QThread::currentThreadId();
}
void UpdateController::changeAssetVersion(QString versionName)
{
commonClientHandler->slot_sendPacketToAllClients(PacketType::BUSY);
qDebug() << "UpdateController thread ID " << QThread::currentThreadId();
currentStreamingPath = assetManager->setVersion(versionName);
setUpCurrentServerHash();
commonClientHandler->slot_sendPacketToAllClients(PacketType::HASH_READY);
commonClientHandler->sendCurrentVersionToAllClient();
commonClientHandler->slot_sendPacketToAllClients(PacketType::FREE);
}
void UpdateController::createCopyVersion(QString versionName,QString newVersionName)
{
commonClientHandler->slot_sendPacketToAllClients(PacketType::BUSY);
assetManager->createCopyVersion(versionName,newVersionName);
commonClientHandler->slot_sendPacketToAllClients(PacketType::FREE);
}
void UpdateController::deleteAssetVersion(QString versionName)
{
assetManager->deleteVersion(versionName);
}
void UpdateController::compareFiles(ClientHandler* handler, QByteArray array)
{
mutex->lock();
loadHash();
clientDataList.clear();
xmlFileDataParse(array);
clientDataList.append(*datas);
checkNeedUpdate(handler);
mutex->unlock();
}
void UpdateController::showHash()
{
for(FileData& str : serverDataList){
emit sigLogMessage(str.hash);
}
}
void UpdateController::calculateFullHash()
{
commonClientHandler->slot_sendPacketToAllClients(PacketType::BUSY);
auto *list = calculateHash(buildPath);
saveHash(buildHashName,list);
calculateSharedHash();
emit sigLogMessage("Calculate hash complete");
commonClientHandler->slot_sendPacketToAllClients(PacketType::FREE);
}
void UpdateController::saveHash(QString fileName,QList<FileData> *fileList)
{
QFile hashFile(fileName);
hashFile.open(QIODevice::WriteOnly);
QXmlStreamWriter xmlWriter(&hashFile);
QListIterator<FileData> fileDataIterator(*fileList);
xmlWriter.setAutoFormatting(true);
xmlWriter.writeStartDocument();
xmlWriter.writeStartElement("FileDataList");
while (fileDataIterator.hasNext())
{
FileData data = fileDataIterator.next();
xmlWriter.writeStartElement("FileData");
xmlWriter.writeAttribute("Path",data.path);
xmlWriter.writeAttribute("Hash",data.hash);
xmlWriter.writeEndElement();
}
xmlWriter.writeEndElement();
xmlWriter.writeEndDocument();
hashFile.close();
}
void UpdateController::loadHash()
{
serverDataList.clear();
QFile hashFile(hashFileName);
QByteArray array;
if(hashFile.open(QIODevice::ReadOnly)){
array = hashFile.readAll();
hashFile.close();
}
QXmlStreamReader xmlReader(array);
while (!xmlReader.atEnd())
{
if(xmlReader.isStartElement())
{
if(xmlReader.name().toUtf8() == "FileData")
{
FileData data;
foreach(const QXmlStreamAttribute &attr,xmlReader.attributes())
{
QString name = attr.name().toString();
QString value = attr.value().toString();
if(name == "Path")
data.path = value;
else if(name == "Hash")
data.hash = value;
}
serverDataList.append(data);
}
}
xmlReader.readNextStartElement();
}
emit sigLogMessage("Hash load from file ");
}
void UpdateController::calculateSize()
{
QDirIterator iterator(buildPath);
quint64 total = 0;
while(iterator.hasNext()){
if(iterator.fileInfo().isFile()){
total += iterator.fileInfo().size();
}
iterator.next();
}
emit sigLogMessage("Full size: ");
emit sigLogMessage(QString::number(total));
}
QString UpdateController::getCommands()
{
QString commandsText;
commandsText += "check - check version ";
commandsText += "update - update files ";
return commandsText;
}
void UpdateController::setUpCurrentServerHash()
{
QList<FileData> *fileList = new QList<FileData>;
fileList->append(*calculateHash(buildPath));
fileList->append(*calculateHash(currentStreamingPath));
assetManager->prepareLocalPathList(fileList);
saveHash(hashFileName,fileList);
}
QString UpdateController::getCurrentStreamingPath() const
{
return currentStreamingPath;
}
void UpdateController::setLocalFileData(QList<FileData> dataList)
{
serverDataList.append(dataList);
}
bool UpdateController::checkNeedUpdate(ClientHandler *handler)
{
QList<FileData> *forSend = new QList<FileData>;
QList<FileData> *forDelete = new QList<FileData>;
fileSendList.clear();
fileDeleteList.clear();
sizeToSend = 0;
bool needUpdate = false;
for (auto &item:clientDataList) //проверка на недостающие файлы по адресам
{
if(item.path.contains("Temp")) continue;
if (!serverDataList.contains(item))
{
forDelete->append(item);
}
}
for (auto &item:serverDataList)
{
if(item.path.contains("Temp")) continue;
if (!clientDataList.contains(item))
{
forSend->append(item);
}
}
if(forSend->length() > 0) //формирование сообщения об обновлении
{
QString log;
log.append(Tools::getTime());
log.append(" Client: " + handler->getClient()->getLogin());
log.append(" Need updates: ");
log.append(QString::number(forSend->length()));
log.append(" objects");
fileSendList = *forSend;
emit sigLogMessage(log);
//printFileList(*forSend);
handler->sendMessageBlock(log);
needUpdate = true;
}
else
{
QString log;
log.append(Tools::getTime());
log.append(" Client: " + handler->getClient()->getLogin());
log.append(" no update required");
emit sigLogMessage(log);
handler->sendMessageBlock(log);
}
if(forDelete->length() > 0){
QString log;
log.append(Tools::getTime());
log.append(" Client: " + handler->getClient()->getLogin());
log.append(" Need delete: ");
log.append(QString::number(forDelete->length()));
log.append(" objects");
fileDeleteList = *forDelete;
emit sigLogMessage(log);
//printFileList(*forDelete);
handler->sendMessageBlock(log);
needUpdate = true;
}
else
{
QString log;
log.append(Tools::getTime());
log.append(" Client: " + handler->getClient()->getLogin());
log.append(" no delete required");
emit sigLogMessage(log);
handler->sendMessageBlock(log);
}
CalculateSizeToSend(*forSend);
handler->sendNeedUpdate(needUpdate,sizeToSend,forSend->length(),forDelete->length());
return needUpdate;
}
QList<FileData>* UpdateController::calculateHash(QString path)
{
serverDataList.clear();
QDirIterator iterator(path,QDirIterator::Subdirectories);
if(!QDir(path).exists()){
QDir().mkdir(path);
}
QDir dir(path);
dir.setFilter(QDir::NoDotAndDotDot);
QString hashString;
QList<FileData> *files = new QList<FileData>;
while (iterator.hasNext())
{
iterator.next();
QFileInfo fileInfo = iterator.fileInfo();
FileData currentFile;
QFile file(fileInfo.absoluteFilePath());
quint64 fileSize = file.size();
const quint64 bufferSize = 10240;
if (fileInfo.isHidden()) continue;
if(fileInfo.isFile() && file.open(QIODevice::ReadOnly) && !fileInfo.fileName().contains(".meta"))
{
char buffer[bufferSize];
int bytesRead;
int readSize = qMin(fileSize,bufferSize);
QCryptographicHash hash(QCryptographicHash::Md5);
while(readSize > 0 && (bytesRead = file.read(buffer,readSize)) > 0){
fileSize -= bytesRead;
hash.addData(buffer,bytesRead);
readSize = qMin(fileSize,bufferSize);
}
hashString = QString(hash.result().toHex());
currentFile.hash = hashString;
currentFile.path = Tools::createLocalPath(fileInfo.absoluteFilePath());
files->push_back(currentFile);
file.close();
}
else if(fileInfo.isDir() && fileInfo.fileName() != ".." && !fileInfo.isRoot())
{
currentFile.hash = "FOLDER";
currentFile.path = Tools::createLocalPath(fileInfo.path());
if(!files->contains(currentFile)){
files->push_back(currentFile);
}
}
}
std::sort(files->begin(),files->end());
serverDataList.append(*files);
return files;
}
QByteArray UpdateController::getAdditionalFile(QString name)
{
QString path = Tools::createSharedPath("/" + assetManager->getCurrentVersionData()->getViewName() + "/AdditionalFiles" + name);
QFile addFile(path);
QByteArray array;
if(addFile.open(QIODevice::ReadOnly)){
array = addFile.readAll();
addFile.close();
}
return array;
}
QByteArray UpdateController::getLocalHash()
{
QFile hashFile(hashFileName);
QByteArray array;
if(hashFile.open(QIODevice::ReadOnly)){
array = hashFile.readAll();
hashFile.close();
}
return array;
}
QString UpdateController::getCurrentVersionName()
{
return assetManager->getCurrentVersionData()->getViewName();
}
void UpdateController::CalculateSizeToSend(QList<FileData> diffList)
{
QListIterator<FileData> serverDiffIterator(diffList);
while (serverDiffIterator.hasNext())
{
QString path;
FileData pathForUpdate = serverDiffIterator.next();
if(pathForUpdate.path.contains(streamingAssetsFolderName))
{
path = Tools::createStreamingToRealPath(pathForUpdate.path,assetManager->getCurrentVersionData());
}
else
{
path = Tools::createRootPath(pathForUpdate.path);
}
QFile file(path);
sizeToSend += file.size();
}
}
void UpdateController::calculateSharedHash()
{
QDir sharedDir(sharedDataPath);
QDirIterator dirIterator(sharedDir);
QList<FileData> *fileList = new QList<FileData>;
QList<StreamingVersionData*> *versionList = new QList<StreamingVersionData*>;
while (dirIterator.hasNext())
{
dirIterator.next();
QFileInfo fileInfo = dirIterator.fileInfo();
if (fileInfo.fileName() == "." || fileInfo.fileName() == "..")
continue;
QString fileName = staticDataFolderName + "/" + fileInfo.fileName() + "Hash.xml";
fileList = calculateHash(fileInfo.absoluteFilePath());
saveHash(fileName,fileList);
StreamingVersionData *version = new StreamingVersionData(
fileInfo.absoluteFilePath(),fileInfo.fileName(),
fileInfo.birthTime(),fileInfo.size());
versionList->append(version);
}
createVersionListXmlAnswer(*versionList);
assetManager->setVersionList(versionList);
}
void UpdateController::createVersionListXmlAnswer(QList<StreamingVersionData *> version) //TODO: переименовать и перебросить в AssetManager
{
QList<SXmlAnswerTag> listTag;
foreach(StreamingVersionData* ver,version)
{
SAttribute attribute1 = {"Version", ver->getViewName()};
SAttribute attribute2 = {"Created", ver->getCreateData().toString()};
QList<SAttribute> listAttr = {attribute1, attribute2};
SXmlAnswerTag tag = {"VersionData", listAttr};
listTag.append(tag);
}
QFile file(versionListFile);
file.open(QIODevice::WriteOnly);
QXmlStreamWriter xmlWriter(&file);
xmlWriter.setAutoFormatting(true);
xmlWriter.writeStartDocument();
xmlWriter.writeStartElement("VersionList");
foreach(SXmlAnswerTag tag,listTag)
{
xmlWriter.writeStartElement(tag.elementName);
foreach(SAttribute attribute,tag.attr)
{
xmlWriter.writeAttribute(attribute.name,attribute.value);
}
xmlWriter.writeEndElement();
}
xmlWriter.writeEndElement();
xmlWriter.writeEndDocument();
file.close();
}
void UpdateController::saveVersionToFile(StreamingVersionData *streamingVersion) //TODO: переименовать и перебросить в AssetManager
{
QFile file(version);
file.open(QFile::WriteOnly);
QXmlStreamWriter xmlWriter(&file);
xmlWriter.setAutoFormatting(true);
xmlWriter.writeStartDocument();
xmlWriter.writeStartElement("VersionData");
xmlWriter.writeAttribute("Version",streamingVersion->getViewName());
xmlWriter.writeAttribute("Created",streamingVersion->getCreateData().toString());
xmlWriter.writeEndElement();
xmlWriter.writeEndDocument();
file.close();
}
void UpdateController::sendNewVersionList()
{
commonClientHandler->sendNewVersionListToAllClient();
}
bool UpdateController::checkDuplicate(QString versionName)
{
return assetManager->findDuplicate(versionName);
}
void UpdateController::xmlFileDataParse(QByteArray array)
{
QXmlStreamReader xmlReader(array);
datas = new QList<FileData>;
xmlReader.readNext();
//Крутимся в цикле до тех пор, пока не достигнем конца документа
while(!xmlReader.atEnd())
{
//Проверяем, является ли элемент началом тега
if(xmlReader.isStartElement())
{
if(xmlReader.name() == "FileData")
{
FileData data;
foreach(const QXmlStreamAttribute &attr,xmlReader.attributes())
{
QString name = attr.name().toString();
QString value = attr.value().toString();
if(name == "Path")
data.path = value;
else if(name == "Hash")
data.hash = value;
}
datas->append(data);
}
}
xmlReader.readNext();
}
}
void UpdateController::printFileList(QList<FileData> fileData)
{
QListIterator<FileData> iterator(fileData);
while (iterator.hasNext())
{
auto next = iterator.next();
emit sigLogMessage(next.path);
}
}
QList<FileData> UpdateController::getFileDeleteList() const
{
return fileDeleteList;
}
QList<FileData> UpdateController::getFileSendList()
{
QList<FileData> sendList = *assetManager->prepareRealPathList(&fileSendList);
return sendList;
}
QList<FileData> UpdateController::getClientDataList() const
{
return clientDataList;
}
DataInfo *UpdateController::getCurrentDataInfo()
{
return dataInfo;
}
QList<FileData> *UpdateController::getDatas() const
{
return datas;
}
void UpdateController::clearCurrentDataInfo()
{
delete dataInfo;
}
UpdateController::~UpdateController()
{
}