mirror of
https://gitea.msk.dinamika-avia.ru/Constanta-Design/RRJServer.git
synced 2026-03-28 19:55:48 +03:00
Переделано под один мега-проект LMS с общим CMakeLists.txt
This commit is contained in:
582
ServerLMS/Systems/updatecontroller.cpp
Normal file
582
ServerLMS/Systems/updatecontroller.cpp
Normal file
@@ -0,0 +1,582 @@
|
||||
#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::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()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user