#include "yacreader_local_server.h" #include #include #include #include "yacreader_global.h" #include "db_helper.h" #include "comic_db.h" #include "QsLog.h" using namespace YACReader; QMutex YACReaderClientConnectionWorker::dbMutex; // int YACReaderClientConnectionWorker::count = 0; YACReaderLocalServer::YACReaderLocalServer(QObject *parent) : QObject(parent) { localServer = new QLocalServer(this); QLocalServer::removeServer(YACREADERLIBRARY_GUID); if (!localServer->listen(YACREADERLIBRARY_GUID)) { QLOG_ERROR() << "Unable to create local server"; } connect(localServer, &QLocalServer::newConnection, this, &YACReaderLocalServer::sendResponse); } bool YACReaderLocalServer::isListening() { return localServer->isListening(); } /*void YACReaderLocalServer::run() { while(1) exec(); }*/ void YACReaderLocalServer::sendResponse() { QLocalSocket *clientConnection = localServer->nextPendingConnection(); // connect(clientConnection, SIGNAL(disconnected()),clientConnection, SLOT(deleteLater())); clientConnection->setParent(0); auto worker = new YACReaderClientConnectionWorker(clientConnection); if (worker != 0) { clientConnection->moveToThread(worker); connect(worker, &YACReaderClientConnectionWorker::comicUpdated, this, &YACReaderLocalServer::comicUpdated); connect(worker, &QThread::finished, worker, &QObject::deleteLater); worker->start(); } QLOG_TRACE() << "connection incoming"; // clientConnection->waitForBytesWritten();*/ // clientConnection->disconnectFromServer(); } bool YACReaderLocalServer::isRunning() { QLocalSocket socket; socket.connectToServer(YACREADERLIBRARY_GUID); if (socket.waitForConnected(500)) return true; // Server is running (another instance of YACReaderLibrary has been launched) return false; } void YACReaderLocalServer::close() { localServer->close(); } YACReaderClientConnectionWorker::YACReaderClientConnectionWorker(QLocalSocket *cc) : QThread(), clientConnection(cc) { } YACReaderClientConnectionWorker::~YACReaderClientConnectionWorker() { } /*#include #include #include */ void YACReaderClientConnectionWorker::run() { /*{ QFile f(QString("c:/temp/thread%1.txt").arg(count)); f.open(QIODevice::Append); QTextStream out(&f); out << QString("Thread%1 starts").arg(count) << endl; f.close(); } uint t1 = QDateTime::currentMSecsSinceEpoch();*/ quint64 libraryId; ComicDB comic; OpenComicSource source = { OpenComicSource::ReadingList, 0 }; qulonglong nextComicId; int tries = 0; int dataAvailable = 0; QByteArray packageSize; clientConnection->waitForReadyRead(1000); while (((long unsigned int)packageSize.size() < sizeof(quint32)) && (tries < 20)) { packageSize.append(clientConnection->read(sizeof(quint32) - packageSize.size())); clientConnection->waitForReadyRead(100); if (dataAvailable == packageSize.size()) { tries++; } dataAvailable = packageSize.size(); } if (tries == 20) { QLOG_ERROR() << "Local connection: unable to read the message size" << clientConnection->errorString(); return; } QDataStream sizeStream(packageSize); sizeStream.setVersion(QDataStream::Qt_4_8); quint32 totalSize = 0; sizeStream >> totalSize; tries = 0; QByteArray data; int dataRead = 0; while ((quint32)data.size() < totalSize && tries < 200) { data.append(clientConnection->readAll()); if ((quint32)data.length() < totalSize) clientConnection->waitForReadyRead(100); if (dataRead == data.length()) // no bytes were read tries++; dataRead = data.length(); } if (tries == 200) { QLOG_ERROR() << QString("Local connection: unable to read message (%1,%2)").arg(data.size()).arg(totalSize); return; } QDataStream dataStream(data); quint8 msgType; dataStream >> msgType; switch (msgType) { case YACReader::RequestComicInfo: { dataStream >> libraryId; dataStream >> source; dataStream >> comic; QList siblings; if (source.source == OpenComicSource::ReadingList) { getComicInfoFromReadingList(libraryId, source.sourceId, comic, siblings); } else { getComicInfo(libraryId, comic, siblings); } QByteArray block; QDataStream out(&block, QIODevice::WriteOnly); out.setVersion(QDataStream::Qt_4_8); out << (quint32)0; out << comic; out << siblings; out.device()->seek(0); out << (quint32)(block.size() - sizeof(quint32)); int written = 0; tries = 0; while (written != block.size() && tries < 200) { int ret = clientConnection->write(block); clientConnection->waitForBytesWritten(10); if (ret != -1) { written += ret; clientConnection->flush(); } else tries++; } if (tries == 200 && written != block.size()) { QLOG_ERROR() << QString("Local connection (comic info requested): unable to send response (%1,%2)").arg(written).arg(block.size()); } break; } case YACReader::SendComicInfo: { bool nextComicInfoAvailable; dataStream >> libraryId; dataStream >> comic; if (dataStream.atEnd()) { nextComicInfoAvailable = false; } else { nextComicInfoAvailable = true; dataStream >> nextComicId; } if (nextComicInfoAvailable) { updateComic(libraryId, comic, nextComicId); } else { updateComic(libraryId, comic); } break; } } clientConnection->waitForDisconnected(); clientConnection->deleteLater(); /*count++; uint t2 = QDateTime::currentMSecsSinceEpoch(); { QFile f(QString("c:/temp/thread%1.txt").arg(count)); f.open(QIODevice::Append); QTextStream out(&f); out << QString("Thread%1 ends : time - %2").arg(count).arg(t2-t1) << endl; f.close(); }*/ } void YACReaderClientConnectionWorker::getComicInfo(quint64 libraryId, ComicDB &comic, QList &siblings) { QMutexLocker locker(&dbMutex); comic = DBHelper::getComicInfo(libraryId, comic.id); siblings = DBHelper::getSiblings(libraryId, comic.parentId); } void YACReaderClientConnectionWorker::getComicInfoFromReadingList(quint64 libraryId, unsigned long long readingListId, ComicDB &comic, QList &siblings) { QMutexLocker locker(&dbMutex); comic = DBHelper::getComicInfo(libraryId, comic.id); siblings = DBHelper::getReadingListFullContent(libraryId, readingListId, true); } void YACReaderClientConnectionWorker::updateComic(quint64 libraryId, ComicDB &comic) { QMutexLocker locker(&dbMutex); DBHelper::update(libraryId, comic.info); emit comicUpdated(libraryId, comic); } void YACReaderClientConnectionWorker::updateComic(quint64 libraryId, ComicDB &comic, qulonglong nextComicId) { QMutexLocker locker(&dbMutex); DBHelper::update(libraryId, comic.info); ComicInfo nextcomicinfo; nextcomicinfo.id = nextComicId; DBHelper::setComicAsReading(libraryId, nextcomicinfo); emit comicUpdated(libraryId, comic); }