#include "sendsystem.h" SendSystem::SendSystem(QObject *parent) : QObject(parent), client(nullptr), socket(nullptr), dataParser(nullptr), globalMutex(nullptr), buffer(nullptr), type(TypeClientAutorization::TYPE_GUI), flSendingStopped(false), flWaitWritenToSocket(false), bytesWritedToSocket(0), fileSize(0), countSend(0) { qDebug() << "SendSystem init thread ID " << QThread::currentThreadId(); buffer = new char[sendFileBlockSize]; } SendSystem::~SendSystem() { delete buffer; } void SendSystem::initialize(DataParser *dataParser, QMutex *globalMutex) { qDebug() << "SendSystem::initialize thread ID " << QThread::currentThreadId(); this->dataParser = dataParser; this->globalMutex = globalMutex; connect(this, &SendSystem::sigSendNotify, dataParser->ClientAnswer(), &ClientAnswerParser::notify, Qt::DirectConnection); //потому что возвращает значение } void SendSystem::setClient(Client *client, QTcpSocket *socket) { qDebug() << "SendSystem::setClient thread ID " << QThread::currentThreadId(); this->socket = socket; this->client = client; this->type = client->getClientType(); flSendingStopped = false; } void SendSystem::updateFiles(QList fileSendList, QList deleteList) { QListIterator clientIterator(deleteList); while(clientIterator.hasNext()) { FileData data = clientIterator.next(); slot_sendDeleteBlock(data.path); if(slot_getIsSendingStopped()) { Logger::instance().log("Client: " + client->getLogin() + " isSendStopped", LogLevel::ERROR); return; } } QListIterator serverIterator(fileSendList); while(serverIterator.hasNext()) { FileData data = serverIterator.next(); if (data.hash == "FOLDER") { slot_sendFolderBlock(data.path); } else { slot_sendFileBlock_V3(data.path); } if(slot_getIsSendingStopped()) { return; } } slot_sendPacketType(PacketType::UPDATE_FILES_COMPLETE); } bool SendSystem::waitWrittenData(QString marker, int msec) { bool success = socket->waitForBytesWritten(msec); if(success) { //qInfo() << "Data sended OK. <" + marker + ">"; } else { qDebug() << "WaitForBytesWritten timeout. <" + marker + ">"; } return success; } void SendSystem::slot_BytesWrittenToSocket(qint64 bytes) { flWaitWritenToSocket = false; bytesWritedToSocket = bytes; } bool SendSystem::slot_getIsSendingStopped() const { return flSendingStopped; } void SendSystem::slot_stopSending() { flSendingStopped = true; } void SendSystem::slot_socketClose() { socket->close(); } void SendSystem::slot_sendVersion() { QByteArray data = dataParser->ClientAnswer()->currentVersion(); slot_sendXmlAnswer(data); } void SendSystem::slot_sendNotify(QString notify) { auto answer = emit sigSendNotify(notify); slot_sendXmlAnswer(answer); } void SendSystem::slot_sendPacketType(PacketType packetType) { Logger::instance().log(" SEND TO: " + client->getLogin() + " " + enumToString(packetType), LogLevel::DEBUG); if (client->getClientType() == TypeClientAutorization::TYPE_QT_CLIENT || client->getClientType() == TypeClientAutorization::TYPE_GUI) { QDataStream stream(socket); stream.setVersion(QDataStream::Qt_DefaultCompiledVersion); stream << packetType; waitWrittenData("sendPacketType"); } else { QByteArray message; int type = (int)packetType; message.append(reinterpret_cast(&type), sizeof(int)); socket->write(message); } } void SendSystem::slot_sendXmlAnswer(QByteArray array, PacketType packetType) { Logger::instance().log("SEND TO: "+ client->getLogin() + " " + enumToString(packetType) + "\n Text: " + QString(array), LogLevel::DEBUG); if (client->getClientType() == TypeClientAutorization::TYPE_QT_CLIENT || client->getClientType() == TypeClientAutorization::TYPE_GUI) { QDataStream stream(socket); stream.setVersion(QDataStream::Qt_DefaultCompiledVersion); stream << packetType; stream << array; waitWrittenData("sendXmlAnswer"); } else { slot_sendPacketType(packetType); QByteArray message; int size = array.length(); message.append(reinterpret_cast(&size), sizeof(int)); socket->write(message); socket->write(array); } } void SendSystem::slot_sendDocs(QString docsPath) { slot_sendFileBlock(docsPath); } void SendSystem::slot_sendNeedUpdate(bool flag, quint64 size, quint64 fileCount, quint64 deleteCount) { QDataStream stream(socket); stream.setVersion(QDataStream::Qt_DefaultCompiledVersion); stream << PacketType::TYPE_NEEDUPDATE; stream << flag; stream << size; stream << fileCount; stream << deleteCount; waitWrittenData("sendNeedUpdate"); } void SendSystem::slot_sendFolderBlock(QString path) { QDataStream stream(socket); stream.setVersion(QDataStream::Qt_DefaultCompiledVersion); stream << PacketType::TYPE_FOLDER; stream << path; waitWrittenData("sendFolderBlock"); } void SendSystem::slot_sendDeleteBlock(QString path) { QDataStream stream(socket); stream.setVersion(QDataStream::Qt_DefaultCompiledVersion); stream << PacketType::TYPE_DELETE; stream << path; waitWrittenData("sendDeleteBlock"); } void SendSystem::slot_sendFileBlock(QString path) { //qDebug() << "SendSystem::sendFileBlock path: " << path; if(slot_getIsSendingStopped()) { //Поведение на случай отключения клиента Logger::instance().log("Client: " + client->getLogin() + " isSendingStopped", LogLevel::ERROR); return; } QFile file(path); QFileInfo fileInfo(file); fileSize = file.size(); if (fileSize == 0) { Logger::instance().log("Client: " + client->getLogin() + " ERROR! File zero size " + fileInfo.fileName(), LogLevel::ERROR); Logger::instance().log(path, LogLevel::ERROR); return; } if(!file.open(QFile::ReadOnly)) { Logger::instance().log("Client: " + client->getLogin() + " ERROR! File not open: " + fileInfo.fileName(), LogLevel::ERROR); Logger::instance().log(path, LogLevel::ERROR); return; } countSend = 0; QDataStream stream(socket); stream.setVersion(QDataStream::Qt_DefaultCompiledVersion); stream << PacketType::TYPE_FILE; stream << path << fileSize; waitWrittenData("sendFileBlock:header " + fileInfo.fileName()); while(!file.atEnd()) { if(socket->state() == QAbstractSocket::UnconnectedState) { Logger::instance().log("Client: " + client->getLogin() + " UnconnectedState", LogLevel::ERROR); break; } QByteArray data = file.read(sendFileBlockSize); stream << data; waitWrittenData(QString("sendFileBlock:data (size %1) ").arg(data.size()) + fileInfo.fileName()); countSend++; } file.close(); countSend = 0; } void SendSystem::slot_sendFileBlock_V3(QString path) { //qDebug() << "SendSystem::sendFileBlock path: " << path; if(slot_getIsSendingStopped()) { //Поведение на случай отключения клиента Logger::instance().log("Client: " + client->getLogin() + " isSendingStopped", LogLevel::ERROR); return; } QFile file(path); QFileInfo fileInfo(file); fileSize = file.size(); if (fileSize == 0) { Logger::instance().log("Client: " + client->getLogin() + " ERROR! File zero size " + fileInfo.fileName(), LogLevel::ERROR); Logger::instance().log(path, LogLevel::ERROR); return; } if(!file.open(QFile::ReadOnly)) { Logger::instance().log("Client: " + client->getLogin() + " ERROR! File not open: " + fileInfo.fileName(), LogLevel::ERROR); Logger::instance().log(path, LogLevel::ERROR); return; } countSend = 0; QDataStream stream(socket); stream.setVersion(QDataStream::Qt_DefaultCompiledVersion); stream << PacketType::TYPE_FILE; stream << path << fileSize; waitWrittenData("sendFileBlock:header " + fileInfo.fileName()); connect(this->socket, &QTcpSocket::bytesWritten, this, &SendSystem::slot_BytesWrittenToSocket); while(!file.atEnd()) { if(socket->state() == QAbstractSocket::UnconnectedState) { Logger::instance().log("Client: " + client->getLogin() + " UnconnectedState", LogLevel::ERROR); break; } qint64 readBytes = file.read(buffer, sendFileBlockSize); if(readBytes <= 0) break; flWaitWritenToSocket = true; while(!socket->write(buffer, readBytes)) { qCritical() << "socket->write ERROR. size " + QString::number(readBytes); int i = 0; i++; } while(flWaitWritenToSocket) { QCoreApplication::processEvents(); // Обеспечиваем обработку сообщений int i = 0; i++; } waitWrittenData(QString("sendFileBlock:data (readBytes %1, num %2) ").arg(QString::number(readBytes), QString::number(countSend)) + fileInfo.fileName()); countSend++; } disconnect(this->socket, &QTcpSocket::bytesWritten, this, &SendSystem::slot_BytesWrittenToSocket); file.close(); countSend = 0; } void SendSystem::slot_sendFileBlockByteArray(QByteArray array, PacketType packetType) { if(client->getClientType() == TypeClientAutorization::TYPE_QT_CLIENT || client->getClientType() == TypeClientAutorization::TYPE_GUI) { QDataStream stream(socket); stream.setVersion(QDataStream::Qt_DefaultCompiledVersion); qint64 size = array.size(); qint64 bytesSended = 0; if (size == 0) { Logger::instance().log(" WARNING! Zero size ",LogLevel::ERROR); return; } stream << packetType; //Отправляем тип блока stream << size; waitWrittenData("sendFileBlockByteArray"); while (bytesSended < size) { QByteArray chunk = array.mid(bytesSended, sendFileBlockSize); stream << chunk; waitWrittenData("sendFileBlockByteArray"); bytesSended += chunk.length(); } } else { slot_sendPacketType(packetType); qint64 size = array.size(); qint64 bytesSended = 0; if (size == 0) { Logger::instance().log(" WARNING! Zero size ",LogLevel::ERROR); return; } QByteArray message; message.append(reinterpret_cast(&size), sizeof(int)); socket->write(message); while (size > 0) { QByteArray chunk = array.mid(bytesSended, sendFileBlockSize); bytesSended = socket->write(chunk); size -= bytesSended; } } } void SendSystem::slot_sendFileBlockWithRename(QString path, QString newName) { //qDebug() << "SendSystem::sendFileBlockWithRename thread ID " << QThread::currentThreadId(); QDataStream stream(socket); stream.setVersion(QDataStream::Qt_DefaultCompiledVersion); QFile file(Tools::createRootPath(path)); QFileInfo fileInfo(file); fileSize = fileInfo.size(); if(fileSize == 0){ Logger::instance().log("Client: " + client->getLogin() + " WARNING! Zero size " + fileInfo.fileName(),LogLevel::ERROR); return; } QString pathForSend = Tools::createFolderPath(path) + "/" + staticDataFolderName + newName; stream << PacketType::TYPE_FILE; stream << pathForSend << fileSize; waitWrittenData("sendFileBlockWithRename"); if(slot_getIsSendingStopped()) { //Поведение на случай отключения клиента file.close(); return; } //socket->waitForBytesWritten(); if(file.open(QFile::ReadOnly)){ while(!file.atEnd()){ QByteArray data = file.read(sendFileBlockSize); stream << data; waitWrittenData("sendFileBlockWithRename"); countSend++; } Logger::instance().log("Send file " + fileInfo.fileName()); } file.close(); countSend = 0; waitWrittenData("sendFileBlockWithRename"); //socket->waitForReadyRead(100); slot_sendNotify(commandHashCompleteClient); }