qBittorrent
BitTorrent::DBResumeDataStorage::Worker Class Referencefinal
Inheritance diagram for BitTorrent::DBResumeDataStorage::Worker:
Collaboration diagram for BitTorrent::DBResumeDataStorage::Worker:

Public Member Functions

 Worker (const QString &dbPath, const QString &dbConnectionName)
 
void openDatabase () const
 
void closeDatabase () const
 
void store (const TorrentID &id, const LoadTorrentParams &resumeData) const
 
void remove (const TorrentID &id) const
 
void storeQueue (const QVector< TorrentID > &queue) const
 

Private Attributes

const QString m_path
 
const QString m_connectionName
 

Detailed Description

Definition at line 171 of file dbresumedatastorage.cpp.

Constructor & Destructor Documentation

◆ Worker()

BitTorrent::DBResumeDataStorage::Worker::Worker ( const QString &  dbPath,
const QString &  dbConnectionName 
)

Definition at line 488 of file dbresumedatastorage.cpp.

489  : m_path {dbPath}
490  , m_connectionName {dbConnectionName}
491 {
492 }

Member Function Documentation

◆ closeDatabase()

void BitTorrent::DBResumeDataStorage::Worker::closeDatabase ( ) const

Definition at line 502 of file dbresumedatastorage.cpp.

503 {
504  QSqlDatabase::removeDatabase(m_connectionName);
505 }

◆ openDatabase()

void BitTorrent::DBResumeDataStorage::Worker::openDatabase ( ) const

Definition at line 494 of file dbresumedatastorage.cpp.

495 {
496  auto db = QSqlDatabase::addDatabase(QLatin1String("QSQLITE"), m_connectionName);
497  db.setDatabaseName(m_path);
498  if (!db.open())
499  throw RuntimeError(db.lastError().text());
500 }

Referenced by BitTorrent::DBResumeDataStorage::DBResumeDataStorage().

Here is the caller graph for this function:

◆ remove()

void BitTorrent::DBResumeDataStorage::Worker::remove ( const TorrentID id) const

Definition at line 624 of file dbresumedatastorage.cpp.

625 {
626  const auto deleteTorrentStatement = QString::fromLatin1("DELETE FROM %1 WHERE %2 = %3;")
628 
629  auto db = QSqlDatabase::database(m_connectionName);
630  QSqlQuery query {db};
631 
632  try
633  {
634  if (!query.prepare(deleteTorrentStatement))
635  throw RuntimeError(query.lastError().text());
636 
637  query.bindValue(DB_COLUMN_TORRENT_ID.placeholder, id.toString());
638  if (!query.exec())
639  throw RuntimeError(query.lastError().text());
640  }
641  catch (const RuntimeError &err)
642  {
643  LogMsg(tr("Couldn't delete resume data of torrent '%1'. Error: %2")
644  .arg(id.toString(), err.message()), Log::CRITICAL);
645  }
646 }
QString message() const noexcept
Definition: exceptions.cpp:36
void LogMsg(const QString &message, const Log::MsgType &type)
Definition: logger.cpp:125
@ CRITICAL
Definition: logger.h:48
QString toString(const lt::socket_type_t socketType)
Definition: session.cpp:183

References Log::CRITICAL, anonymous_namespace{dbresumedatastorage.cpp}::DB_COLUMN_TORRENT_ID, anonymous_namespace{dbresumedatastorage.cpp}::DB_TABLE_TORRENTS, LogMsg(), Exception::message(), anonymous_namespace{dbresumedatastorage.cpp}::Column::name, anonymous_namespace{dbresumedatastorage.cpp}::Column::placeholder, anonymous_namespace{dbresumedatastorage.cpp}::quoted(), and anonymous_namespace{session.cpp}::toString().

Here is the call graph for this function:

◆ store()

void BitTorrent::DBResumeDataStorage::Worker::store ( const TorrentID id,
const LoadTorrentParams resumeData 
) const

Definition at line 507 of file dbresumedatastorage.cpp.

508 {
509  // We need to adjust native libtorrent resume data
510  lt::add_torrent_params p = resumeData.ltAddTorrentParams;
511  p.save_path = Profile::instance()->toPortablePath(QString::fromStdString(p.save_path)).toStdString();
512  if (resumeData.stopped)
513  {
514  p.flags |= lt::torrent_flags::paused;
515  p.flags &= ~lt::torrent_flags::auto_managed;
516  }
517  else
518  {
519  // Torrent can be actually "running" but temporarily "paused" to perform some
520  // service jobs behind the scenes so we need to restore it as "running"
521  if (resumeData.operatingMode == BitTorrent::TorrentOperatingMode::AutoManaged)
522  {
523  p.flags |= lt::torrent_flags::auto_managed;
524  }
525  else
526  {
527  p.flags &= ~lt::torrent_flags::paused;
528  p.flags &= ~lt::torrent_flags::auto_managed;
529  }
530  }
531 
532  QVector<Column> columns {
546  };
547 
548  lt::entry data = lt::write_resume_data(p);
549 
550  // metadata is stored in separate column
551  QByteArray bencodedMetadata;
552  if (p.ti)
553  {
554  lt::entry::dictionary_type &dataDict = data.dict();
555  lt::entry metadata {lt::entry::dictionary_t};
556  lt::entry::dictionary_type &metadataDict = metadata.dict();
557  metadataDict.insert(dataDict.extract("info"));
558  metadataDict.insert(dataDict.extract("creation date"));
559  metadataDict.insert(dataDict.extract("created by"));
560  metadataDict.insert(dataDict.extract("comment"));
561 
562  try
563  {
564  bencodedMetadata.reserve(512 * 1024);
565  lt::bencode(std::back_inserter(bencodedMetadata), metadata);
566  }
567  catch (const std::exception &err)
568  {
569  LogMsg(tr("Couldn't save torrent metadata. Error: %1.")
570  .arg(QString::fromLocal8Bit(err.what())), Log::CRITICAL);
571  return;
572  }
573 
574  columns.append(DB_COLUMN_METADATA);
575  }
576 
577  QByteArray bencodedResumeData;
578  bencodedResumeData.reserve(256 * 1024);
579  lt::bencode(std::back_inserter(bencodedResumeData), data);
580 
581  const QString insertTorrentStatement = makeInsertStatement(DB_TABLE_TORRENTS, columns)
583  auto db = QSqlDatabase::database(m_connectionName);
584  QSqlQuery query {db};
585 
586  try
587  {
588  if (!query.prepare(insertTorrentStatement))
589  throw RuntimeError(query.lastError().text());
590 
591  query.bindValue(DB_COLUMN_TORRENT_ID.placeholder, id.toString());
592  query.bindValue(DB_COLUMN_NAME.placeholder, resumeData.name);
593  query.bindValue(DB_COLUMN_CATEGORY.placeholder, resumeData.category);
594  query.bindValue(DB_COLUMN_TAGS.placeholder, (resumeData.tags.isEmpty()
595  ? QVariant(QVariant::String) : resumeData.tags.join(QLatin1String(","))));
596  query.bindValue(DB_COLUMN_CONTENT_LAYOUT.placeholder, Utils::String::fromEnum(resumeData.contentLayout));
597  query.bindValue(DB_COLUMN_RATIO_LIMIT.placeholder, static_cast<int>(resumeData.ratioLimit * 1000));
598  query.bindValue(DB_COLUMN_SEEDING_TIME_LIMIT.placeholder, resumeData.seedingTimeLimit);
599  query.bindValue(DB_COLUMN_HAS_OUTER_PIECES_PRIORITY.placeholder, resumeData.firstLastPiecePriority);
600  query.bindValue(DB_COLUMN_HAS_SEED_STATUS.placeholder, resumeData.hasSeedStatus);
601  query.bindValue(DB_COLUMN_OPERATING_MODE.placeholder, Utils::String::fromEnum(resumeData.operatingMode));
602  query.bindValue(DB_COLUMN_STOPPED.placeholder, resumeData.stopped);
603 
604  if (!resumeData.useAutoTMM)
605  {
606  query.bindValue(DB_COLUMN_TARGET_SAVE_PATH.placeholder, Profile::instance()->toPortablePath(resumeData.savePath));
607  query.bindValue(DB_COLUMN_DOWNLOAD_PATH.placeholder, Profile::instance()->toPortablePath(resumeData.downloadPath));
608  }
609 
610  query.bindValue(DB_COLUMN_RESUMEDATA.placeholder, bencodedResumeData);
611  if (!bencodedMetadata.isEmpty())
612  query.bindValue(DB_COLUMN_METADATA.placeholder, bencodedMetadata);
613 
614  if (!query.exec())
615  throw RuntimeError(query.lastError().text());
616  }
617  catch (const RuntimeError &err)
618  {
619  LogMsg(tr("Couldn't store resume data for torrent '%1'. Error: %2")
620  .arg(id.toString(), err.message()), Log::CRITICAL);
621  }
622 }
QString toPortablePath(const QString &absolutePath) const
Definition: profile.cpp:121
static const Profile * instance()
Definition: profile.cpp:67
QString fromEnum(const T &value)
Definition: string.h:67
QString makeOnConflictUpdateStatement(const Column &constraint, const QVector< Column > &columns)
QString makeInsertStatement(const QString &tableName, const QVector< Column > &columns)

References BitTorrent::LoadTorrentParams::category, BitTorrent::LoadTorrentParams::contentLayout, Log::CRITICAL, anonymous_namespace{dbresumedatastorage.cpp}::DB_COLUMN_CATEGORY, anonymous_namespace{dbresumedatastorage.cpp}::DB_COLUMN_CONTENT_LAYOUT, anonymous_namespace{dbresumedatastorage.cpp}::DB_COLUMN_DOWNLOAD_PATH, anonymous_namespace{dbresumedatastorage.cpp}::DB_COLUMN_HAS_OUTER_PIECES_PRIORITY, anonymous_namespace{dbresumedatastorage.cpp}::DB_COLUMN_HAS_SEED_STATUS, anonymous_namespace{dbresumedatastorage.cpp}::DB_COLUMN_METADATA, anonymous_namespace{dbresumedatastorage.cpp}::DB_COLUMN_NAME, anonymous_namespace{dbresumedatastorage.cpp}::DB_COLUMN_OPERATING_MODE, anonymous_namespace{dbresumedatastorage.cpp}::DB_COLUMN_RATIO_LIMIT, anonymous_namespace{dbresumedatastorage.cpp}::DB_COLUMN_RESUMEDATA, anonymous_namespace{dbresumedatastorage.cpp}::DB_COLUMN_SEEDING_TIME_LIMIT, anonymous_namespace{dbresumedatastorage.cpp}::DB_COLUMN_STOPPED, anonymous_namespace{dbresumedatastorage.cpp}::DB_COLUMN_TAGS, anonymous_namespace{dbresumedatastorage.cpp}::DB_COLUMN_TARGET_SAVE_PATH, anonymous_namespace{dbresumedatastorage.cpp}::DB_COLUMN_TORRENT_ID, anonymous_namespace{dbresumedatastorage.cpp}::DB_TABLE_TORRENTS, BitTorrent::LoadTorrentParams::downloadPath, BitTorrent::LoadTorrentParams::firstLastPiecePriority, Utils::String::fromEnum(), BitTorrent::LoadTorrentParams::hasSeedStatus, Profile::instance(), OrderedSet< T, Compare >::isEmpty(), OrderedSet< T, Compare >::join(), LogMsg(), BitTorrent::LoadTorrentParams::ltAddTorrentParams, anonymous_namespace{dbresumedatastorage.cpp}::makeInsertStatement(), anonymous_namespace{dbresumedatastorage.cpp}::makeOnConflictUpdateStatement(), Exception::message(), BitTorrent::LoadTorrentParams::name, BitTorrent::LoadTorrentParams::operatingMode, anonymous_namespace{dbresumedatastorage.cpp}::Column::placeholder, BitTorrent::LoadTorrentParams::ratioLimit, BitTorrent::LoadTorrentParams::savePath, BitTorrent::LoadTorrentParams::seedingTimeLimit, BitTorrent::LoadTorrentParams::stopped, BitTorrent::LoadTorrentParams::tags, Profile::toPortablePath(), anonymous_namespace{session.cpp}::toString(), and BitTorrent::LoadTorrentParams::useAutoTMM.

Here is the call graph for this function:

◆ storeQueue()

void BitTorrent::DBResumeDataStorage::Worker::storeQueue ( const QVector< TorrentID > &  queue) const

Definition at line 648 of file dbresumedatastorage.cpp.

649 {
650  const auto updateQueuePosStatement = QString::fromLatin1("UPDATE %1 SET %2 = %3 WHERE %4 = %5;")
653 
654  auto db = QSqlDatabase::database(m_connectionName);
655 
656  try
657  {
658  if (!db.transaction())
659  throw RuntimeError(db.lastError().text());
660 
661  QSqlQuery query {db};
662 
663  try
664  {
665  if (!query.prepare(updateQueuePosStatement))
666  throw RuntimeError(query.lastError().text());
667 
668  int pos = 0;
669  for (const TorrentID &torrentID : queue)
670  {
671  query.bindValue(DB_COLUMN_TORRENT_ID.placeholder, torrentID.toString());
672  query.bindValue(DB_COLUMN_QUEUE_POSITION.placeholder, pos++);
673  if (!query.exec())
674  throw RuntimeError(query.lastError().text());
675  }
676 
677  if (!db.commit())
678  throw RuntimeError(db.lastError().text());
679  }
680  catch (const RuntimeError &)
681  {
682  db.rollback();
683  throw;
684  }
685  }
686  catch (const RuntimeError &err)
687  {
688  LogMsg(tr("Couldn't store torrents queue positions. Error: %1")
689  .arg(err.message()), Log::CRITICAL);
690  }
691 }

References Log::CRITICAL, anonymous_namespace{dbresumedatastorage.cpp}::DB_COLUMN_QUEUE_POSITION, anonymous_namespace{dbresumedatastorage.cpp}::DB_COLUMN_TORRENT_ID, anonymous_namespace{dbresumedatastorage.cpp}::DB_TABLE_TORRENTS, LogMsg(), Exception::message(), anonymous_namespace{dbresumedatastorage.cpp}::Column::name, anonymous_namespace{dbresumedatastorage.cpp}::Column::placeholder, and anonymous_namespace{dbresumedatastorage.cpp}::quoted().

Here is the call graph for this function:

Member Data Documentation

◆ m_connectionName

const QString BitTorrent::DBResumeDataStorage::Worker::m_connectionName
private

Definition at line 187 of file dbresumedatastorage.cpp.

◆ m_path

const QString BitTorrent::DBResumeDataStorage::Worker::m_path
private

Definition at line 186 of file dbresumedatastorage.cpp.


The documentation for this class was generated from the following file: