/* * Squawk messenger. * Copyright (C) 2019 Yury Gubich * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "manager.h" #include #include "cardinternal.h" #include "infoforuser.h" #include "owncardinternal.h" #include "owninfoforuser.h" Core::DelayManager::Manager::Manager(const QString& poj, Job::Id mpj, QObject* parent) : QObject(parent), maxParallelJobs(mpj), nextJobId(1), scheduledJobs(), scheduledJobsById(scheduledJobs.get()), jobSequence(scheduledJobs.get()), runningJobs(), ownVCardJobId(0), ownInfoJobId(0), scheduledVCards(), requestedVCards(), #ifdef WITH_OMEMO requestedBundles(), #endif ownJid(poj) {} Core::DelayManager::Manager::~Manager() { for (const std::pair& pair : runningJobs) delete pair.second; for (Job* job : jobSequence) delete job; } Core::DelayManager::Job::Id Core::DelayManager::Manager::getNextJobId() { Job::Id id = nextJobId++; if (id == 0) id = nextJobId++; return id; } void Core::DelayManager::Manager::getInfo(const QString& jid) { if (jid == ownJid) return getOwnInfo(); Job* job = nullptr; #ifdef WITH_OMEMO std::map::const_iterator bitr = requestedBundles.find(jid); if (bitr != requestedBundles.end()) { std::map::const_iterator itr = runningJobs.find(bitr->second); if (itr == runningJobs.end()) throw JobNotFound(bitr->second); job = itr->second; } else #endif job = getVCardJob(jid); if (job != nullptr) { if (job->type == Job::Type::cardInternal) replaceJob(new InfoForUser(job->id, jid)); } else scheduleJob(new InfoForUser(getNextJobId(), jid)); } void Core::DelayManager::Manager::getOwnInfo() { if (ownInfoJobId == 0) { if (ownVCardJobId != 0) replaceJob(new OwnInfoForUser(ownVCardJobId)); else scheduleJob(new OwnInfoForUser(getNextJobId())); } } void Core::DelayManager::Manager::getVCard(const QString& jid) { Job* job = getVCardJob(jid); if (job == nullptr) scheduleJob(new CardInternal(getNextJobId(), jid)); } void Core::DelayManager::Manager::getOwnVCard() { if (ownVCardJobId == 0) scheduleJob(new OwnCardInternal(getNextJobId())); } bool Core::DelayManager::Manager::isOwnVCardPending() const { return ownVCardJobId != 0; } Core::DelayManager::Job* Core::DelayManager::Manager::getVCardJob(const QString& jid) { Job* job = nullptr; std::map::const_iterator sitr = scheduledVCards.find(jid); if (sitr == scheduledVCards.end()) { std::map::const_iterator ritr = requestedVCards.find(jid); if (ritr != requestedVCards.end()) { std::map::const_iterator itr = runningJobs.find(ritr->second); if (itr == runningJobs.end()) throw JobNotFound(ritr->second, "getVCardJob:1"); job = itr->second; } } else { StorageById::const_iterator itr = scheduledJobsById.find(sitr->second); if (itr == scheduledJobsById.end()) throw JobNotFound(sitr->second, "getVCardJob:2"); job = *itr; } return job; } void Core::DelayManager::Manager::preScheduleJob(Job* job) { switch (job->type) { case Job::Type::cardInternal: scheduledVCards.emplace(dynamic_cast(job)->jid, job->id); break; case Job::Type::ownCardInternal: ownVCardJobId = job->id; break; case Job::Type::infoForUser: scheduledVCards.emplace(dynamic_cast(job)->jid, job->id); break; case Job::Type::ownInfoForUser: ownVCardJobId = job->id; ownInfoJobId = job->id; break; } } void Core::DelayManager::Manager::scheduleJob(Job* job) { preScheduleJob(job); if (runningJobs.size() < maxParallelJobs) executeJob(job); else scheduledJobs.push_back(job); } void Core::DelayManager::Manager::preExecuteJob(Job* job) { switch (job->type) { case Job::Type::cardInternal: case Job::Type::infoForUser: { Contact* cij = dynamic_cast(job); requestedVCards.emplace(cij->jid, job->id); scheduledVCards.erase(cij->jid); } break; case Job::Type::ownInfoForUser: case Job::Type::ownCardInternal: break; } } void Core::DelayManager::Manager::executeJob(Job* job) { preExecuteJob(job); runningJobs.emplace(job->id, job); switch (job->type) { case Job::Type::cardInternal: case Job::Type::infoForUser: emit requestVCard(dynamic_cast(job)->jid); break; case Job::Type::ownInfoForUser: case Job::Type::ownCardInternal: emit requestOwnVCard(); break; } } void Core::DelayManager::Manager::jobIsDone(Job::Id jobId) { std::map::const_iterator itr = runningJobs.find(jobId); if (itr == runningJobs.end()) throw JobNotFound(jobId, "jobIsDone"); Job* job = itr->second; delete job; runningJobs.erase(itr); if (scheduledJobs.size() > 0) { Job* job = scheduledJobs.front(); scheduledJobs.pop_front(); executeJob(job); } } void Core::DelayManager::Manager::replaceJob(Job* job) { preScheduleJob(job); std::map::iterator itr = runningJobs.find(job->id); if (itr != runningJobs.end()) { preExecuteJob(job); delete itr->second; itr->second = job; } else { StorageById::iterator sitr = scheduledJobsById.find(job->id); if (sitr != scheduledJobsById.end()) { delete *(sitr); scheduledJobsById.replace(sitr, job); } else throw JobNotFound(job->id, "replaceJob"); } } void Core::DelayManager::Manager::jobIsCanceled(Job* job, bool wasRunning) { switch (job->type) { case Job::Type::cardInternal: { CardInternal* jb = dynamic_cast(job); if (wasRunning) requestedVCards.erase(jb->jid); else scheduledVCards.erase(jb->jid); emit gotVCard(jb->jid, Shared::VCard()); } break; case Job::Type::infoForUser: { InfoForUser* jb = dynamic_cast(job); switch (jb->getStage()) { case InfoForUser::Stage::waitingForVCard: if (wasRunning) requestedVCards.erase(jb->jid); else scheduledVCards.erase(jb->jid); emit gotVCard(jb->jid, Shared::VCard()); break; case InfoForUser::Stage::waitingForBundles: #ifdef WITH_OMEMO requestedBundles.erase(jb->jid); #endif break; default: break; } emit gotInfo(Shared::Info(jb->jid)); } break; case Job::Type::ownInfoForUser: { OwnInfoForUser* jb = dynamic_cast(job); if (jb->getStage() == OwnInfoForUser::Stage::waitingForVCard) { ownVCardJobId = 0; emit gotOwnVCard(Shared::VCard()); } ownInfoJobId = 0; emit gotOwnInfo(Shared::Info (ownJid)); } break; case Job::Type::ownCardInternal: ownVCardJobId = 0; emit gotOwnVCard(Shared::VCard()); break; } delete job; } void Core::DelayManager::Manager::disconnected() { for (const std::pair pair : runningJobs) jobIsCanceled(pair.second, true); for (Job* job : scheduledJobs) jobIsCanceled(job, false); runningJobs.clear(); scheduledJobs.clear(); } void Core::DelayManager::Manager::receivedVCard(const QString& jid, const Shared::VCard& card) { std::map::const_iterator cardItr = requestedVCards.find(jid); if (cardItr == requestedVCards.end()) { qDebug() << "received VCard for" << jid << "but it was never requested through manager, ignoring"; return; } Job::Id jobId = cardItr->second; requestedVCards.erase(cardItr); std::map::const_iterator itr = runningJobs.find(jobId); if (itr == runningJobs.end()) throw JobNotFound(jobId, "receivedVCard"); Job* job = itr->second; switch (job->type) { case Job::Type::cardInternal: jobIsDone(jobId); emit gotVCard(jid, card); break; case Job::Type::infoForUser: { #ifdef WITH_OMEMO requestedBundles.emplace(jid, jobId); InfoForUser* jb = dynamic_cast(job); jb->receivedVCard(card); emit requestBundles(jid); #else Shared::Info info(jid); info.turnIntoContact(card); emit gotInfo(info); jobIsDone(jobId); #endif emit gotVCard(jid, card); } break; default: throw UnexpectedJobType(job->type, "receivedVCard"); } } void Core::DelayManager::Manager::receivedOwnVCard(const Shared::VCard& card) { if (ownVCardJobId == 0) { qDebug() << "received own VCard for" << ownJid << "but it was never requested through manager, ignoring"; return; } Job::Id jobId = ownVCardJobId; ownVCardJobId = 0; std::map::const_iterator itr = runningJobs.find(jobId); if (itr == runningJobs.end()) throw JobNotFound(jobId, "receivedOwnVCard"); Job* job = itr->second; switch (job->type) { case Job::Type::ownCardInternal: jobIsDone(jobId); emit gotOwnVCard(card); break; case Job::Type::ownInfoForUser: { #ifdef WITH_OMEMO OwnInfoForUser* jb = dynamic_cast(job); jb->receivedVCard(card); emit requestOwnBundles(); #else Shared::Info info(ownJid); info.turnIntoOwnAccount(card); emit gotOwnInfo(info); jobIsDone(jobId); #endif emit gotOwnVCard(card); } break; default: throw UnexpectedJobType(job->type, "receivedVCard"); } } #ifdef WITH_OMEMO void Core::DelayManager::Manager::receivedBundles(const QString& jid, const std::list& keys) { std::map::const_iterator itr = requestedBundles.find(jid); if (itr == requestedBundles.end()) { qDebug() << "received bundles for" << jid << "but they were never requested through manager, ignoring"; return; } Job::Id jobId = itr->second; requestedBundles.erase(itr); std::map::const_iterator jitr = runningJobs.find(jobId); if (jitr == runningJobs.end()) throw JobNotFound(jobId, "receivedBundles"); Job* jb = jitr->second; InfoForUser* job = dynamic_cast(jb); Shared::Info info(jid); info.turnIntoContact(job->claim(), new std::list(keys)); emit gotInfo(info); jobIsDone(jobId); } void Core::DelayManager::Manager::receivedOwnBundles(const std::list& keys) { if (ownInfoJobId == 0) { qDebug() << "received own bundles for" << ownJid << "but they were never requested through manager, ignoring"; return; } Job::Id jobId = ownInfoJobId; ownInfoJobId = 0; std::map::const_iterator jitr = runningJobs.find(jobId); if (jitr == runningJobs.end()) throw JobNotFound(jobId, "receivedOwnBundles"); Job* jb = jitr->second; OwnInfoForUser* job = dynamic_cast(jb); Shared::Info info(ownJid); info.turnIntoOwnAccount(job->claim(), new std::list(keys)); emit gotOwnInfo(info); jobIsDone(jobId); } #endif void Core::DelayManager::Manager::setOwnJid(const QString& jid) { ownJid = jid; } Core::DelayManager::Manager::UnexpectedJobType::UnexpectedJobType(Job::Type p_type, const std::string& p_method): Exception(), type(p_type), method(p_method) {} std::string Core::DelayManager::Manager::UnexpectedJobType::getMessage() const{ std::string msg("Unexpected job type: "); msg += Job::TypeString[static_cast(type)]; if (method.size() > 0) msg += " in method " + method; return msg; } Core::DelayManager::Manager::JobNotFound::JobNotFound(Job::Id p_id, const std::string& p_method) : Exception(), id(p_id), method(p_method) {} std::string Core::DelayManager::Manager::JobNotFound::getMessage() const { std::string msg("Job with id "); msg += std::to_string(id); msg += " was not found"; if (method.size() > 0) msg += " in method " + method; return msg; }