qBittorrent
BitTorrent::BencodeResumeDataStorage Class Referencefinal

#include <bencoderesumedatastorage.h>

Inheritance diagram for BitTorrent::BencodeResumeDataStorage:
Collaboration diagram for BitTorrent::BencodeResumeDataStorage:

Classes

class  Worker
 

Public Member Functions

 BencodeResumeDataStorage (const QString &path, QObject *parent=nullptr)
 
 ~BencodeResumeDataStorage () override
 
QVector< TorrentIDregisteredTorrents () const override
 
std::optional< LoadTorrentParamsload (const TorrentID &id) const override
 
void store (const TorrentID &id, const LoadTorrentParams &resumeData) const override
 
void remove (const TorrentID &id) const override
 
void storeQueue (const QVector< TorrentID > &queue) const override
 

Private Member Functions

void loadQueue (const QString &queueFilename)
 
std::optional< LoadTorrentParamsloadTorrentResumeData (const QByteArray &data, const QByteArray &metadata) const
 

Private Attributes

const QDir m_resumeDataDir
 
QVector< TorrentIDm_registeredTorrents
 
QThread * m_ioThread = nullptr
 
Workerm_asyncWorker = nullptr
 

Detailed Description

Definition at line 41 of file bencoderesumedatastorage.h.

Constructor & Destructor Documentation

◆ BencodeResumeDataStorage()

BitTorrent::BencodeResumeDataStorage::BencodeResumeDataStorage ( const QString &  path,
QObject *  parent = nullptr 
)
explicit

Definition at line 92 of file bencoderesumedatastorage.cpp.

93  : ResumeDataStorage {parent}
94  , m_resumeDataDir {path}
95  , m_ioThread {new QThread {this}}
96  , m_asyncWorker {new Worker {m_resumeDataDir}}
97 {
98  if (!m_resumeDataDir.exists() && !m_resumeDataDir.mkpath(m_resumeDataDir.absolutePath()))
99  {
100  throw RuntimeError {tr("Cannot create torrent resume folder: \"%1\"")
101  .arg(Utils::Fs::toNativePath(m_resumeDataDir.absolutePath()))};
102  }
103 
104  const QRegularExpression filenamePattern {QLatin1String("^([A-Fa-f0-9]{40})\\.fastresume$")};
105  const QStringList filenames = m_resumeDataDir.entryList(QStringList(QLatin1String("*.fastresume")), QDir::Files, QDir::Unsorted);
106 
107  m_registeredTorrents.reserve(filenames.size());
108  for (const QString &filename : filenames)
109  {
110  const QRegularExpressionMatch rxMatch = filenamePattern.match(filename);
111  if (rxMatch.hasMatch())
112  m_registeredTorrents.append(TorrentID::fromString(rxMatch.captured(1)));
113  }
114 
115  loadQueue(m_resumeDataDir.absoluteFilePath(QLatin1String("queue")));
116 
117  qDebug() << "Registered torrents count: " << m_registeredTorrents.size();
118 
119  m_asyncWorker->moveToThread(m_ioThread);
120  connect(m_ioThread, &QThread::finished, m_asyncWorker, &QObject::deleteLater);
121  m_ioThread->start();
122 }
void loadQueue(const QString &queueFilename)
static TorrentID fromString(const QString &hashString)
Definition: infohash.cpp:76
QString toNativePath(const QString &path)
Definition: fs.cpp:64

References BitTorrent::TorrentID::fromString(), loadQueue(), m_asyncWorker, m_ioThread, m_registeredTorrents, m_resumeDataDir, and Utils::Fs::toNativePath().

Here is the call graph for this function:

◆ ~BencodeResumeDataStorage()

BitTorrent::BencodeResumeDataStorage::~BencodeResumeDataStorage ( )
override

Definition at line 124 of file bencoderesumedatastorage.cpp.

125 {
126  m_ioThread->quit();
127  m_ioThread->wait();
128 }

Member Function Documentation

◆ load()

std::optional< BitTorrent::LoadTorrentParams > BitTorrent::BencodeResumeDataStorage::load ( const TorrentID id) const
overridevirtual

Implements BitTorrent::ResumeDataStorage.

Definition at line 135 of file bencoderesumedatastorage.cpp.

136 {
137  const QString idString = id.toString();
138  const QString fastresumePath = m_resumeDataDir.absoluteFilePath(QString::fromLatin1("%1.fastresume").arg(idString));
139  const QString torrentFilePath = m_resumeDataDir.absoluteFilePath(QString::fromLatin1("%1.torrent").arg(idString));
140 
141  QFile resumeDataFile {fastresumePath};
142  if (!resumeDataFile.open(QIODevice::ReadOnly))
143  {
144  LogMsg(tr("Cannot read file %1: %2").arg(fastresumePath, resumeDataFile.errorString()), Log::WARNING);
145  return std::nullopt;
146  }
147 
148  QFile metadataFile {torrentFilePath};
149  if (metadataFile.exists() && !metadataFile.open(QIODevice::ReadOnly))
150  {
151  LogMsg(tr("Cannot read file %1: %2").arg(torrentFilePath, metadataFile.errorString()), Log::WARNING);
152  return std::nullopt;
153  }
154 
155  const QByteArray data = resumeDataFile.readAll();
156  const QByteArray metadata = (metadataFile.isOpen() ? metadataFile.readAll() : "");
157 
158  return loadTorrentResumeData(data, metadata);
159 }
std::optional< LoadTorrentParams > loadTorrentResumeData(const QByteArray &data, const QByteArray &metadata) const
void LogMsg(const QString &message, const Log::MsgType &type)
Definition: logger.cpp:125
@ WARNING
Definition: logger.h:47

References LogMsg(), and Log::WARNING.

Here is the call graph for this function:

◆ loadQueue()

void BitTorrent::BencodeResumeDataStorage::loadQueue ( const QString &  queueFilename)
private

Definition at line 276 of file bencoderesumedatastorage.cpp.

277 {
278  QFile queueFile {queueFilename};
279  if (!queueFile.exists())
280  return;
281 
282  if (queueFile.open(QFile::ReadOnly))
283  {
284  const QRegularExpression hashPattern {QLatin1String("^([A-Fa-f0-9]{40})$")};
285  QByteArray line;
286  int start = 0;
287  while (!(line = queueFile.readLine().trimmed()).isEmpty())
288  {
289  const QRegularExpressionMatch rxMatch = hashPattern.match(line);
290  if (rxMatch.hasMatch())
291  {
292  const auto torrentID = TorrentID::fromString(rxMatch.captured(1));
293  const int pos = m_registeredTorrents.indexOf(torrentID, start);
294  if (pos != -1)
295  {
296  std::swap(m_registeredTorrents[start], m_registeredTorrents[pos]);
297  ++start;
298  }
299  }
300  }
301  }
302  else
303  {
304  LogMsg(tr("Couldn't load torrents queue from '%1'. Error: %2")
305  .arg(queueFile.fileName(), queueFile.errorString()), Log::WARNING);
306  }
307 }

References BitTorrent::TorrentID::fromString(), LogMsg(), and Log::WARNING.

Referenced by BencodeResumeDataStorage().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ loadTorrentResumeData()

std::optional< BitTorrent::LoadTorrentParams > BitTorrent::BencodeResumeDataStorage::loadTorrentResumeData ( const QByteArray &  data,
const QByteArray &  metadata 
) const
private

Definition at line 161 of file bencoderesumedatastorage.cpp.

163 {
164  const QByteArray allData = ((metadata.isEmpty() || data.isEmpty())
165  ? data : (data.chopped(1) + metadata.mid(1)));
166 
167  lt::error_code ec;
168  const lt::bdecode_node root = lt::bdecode(allData, ec);
169  if (ec || (root.type() != lt::bdecode_node::dict_t))
170  return std::nullopt;
171 
172  LoadTorrentParams torrentParams;
173  torrentParams.restored = true;
174  torrentParams.category = fromLTString(root.dict_find_string_value("qBt-category"));
175  torrentParams.name = fromLTString(root.dict_find_string_value("qBt-name"));
176  torrentParams.hasSeedStatus = root.dict_find_int_value("qBt-seedStatus");
177  torrentParams.firstLastPiecePriority = root.dict_find_int_value("qBt-firstLastPiecePriority");
178  torrentParams.seedingTimeLimit = root.dict_find_int_value("qBt-seedingTimeLimit", Torrent::USE_GLOBAL_SEEDING_TIME);
179 
180  torrentParams.savePath = Profile::instance()->fromPortablePath(
181  Utils::Fs::toUniformPath(fromLTString(root.dict_find_string_value("qBt-savePath"))));
182  torrentParams.useAutoTMM = torrentParams.savePath.isEmpty();
183  if (!torrentParams.useAutoTMM)
184  {
185  torrentParams.downloadPath = Profile::instance()->fromPortablePath(
186  Utils::Fs::toUniformPath(fromLTString(root.dict_find_string_value("qBt-downloadPath"))));
187  }
188 
189  // TODO: The following code is deprecated. Replace with the commented one after several releases in 4.4.x.
190  // === BEGIN DEPRECATED CODE === //
191  const lt::bdecode_node contentLayoutNode = root.dict_find("qBt-contentLayout");
192  if (contentLayoutNode.type() == lt::bdecode_node::string_t)
193  {
194  const QString contentLayoutStr = fromLTString(contentLayoutNode.string_value());
195  torrentParams.contentLayout = Utils::String::toEnum(contentLayoutStr, TorrentContentLayout::Original);
196  }
197  else
198  {
199  const bool hasRootFolder = root.dict_find_int_value("qBt-hasRootFolder");
200  torrentParams.contentLayout = (hasRootFolder ? TorrentContentLayout::Original : TorrentContentLayout::NoSubfolder);
201  }
202  // === END DEPRECATED CODE === //
203  // === BEGIN REPLACEMENT CODE === //
204  // torrentParams.contentLayout = Utils::String::parse(
205  // fromLTString(root.dict_find_string_value("qBt-contentLayout")), TorrentContentLayout::Default);
206  // === END REPLACEMENT CODE === //
207 
208  const lt::string_view ratioLimitString = root.dict_find_string_value("qBt-ratioLimit");
209  if (ratioLimitString.empty())
210  torrentParams.ratioLimit = root.dict_find_int_value("qBt-ratioLimit", Torrent::USE_GLOBAL_RATIO * 1000) / 1000.0;
211  else
212  torrentParams.ratioLimit = fromLTString(ratioLimitString).toDouble();
213 
214  const lt::bdecode_node tagsNode = root.dict_find("qBt-tags");
215  if (tagsNode.type() == lt::bdecode_node::list_t)
216  {
217  for (int i = 0; i < tagsNode.list_size(); ++i)
218  {
219  const QString tag = fromLTString(tagsNode.list_string_value_at(i));
220  torrentParams.tags.insert(tag);
221  }
222  }
223 
224  lt::add_torrent_params &p = torrentParams.ltAddTorrentParams;
225 
226  p = lt::read_resume_data(root, ec);
227  p.save_path = Profile::instance()->fromPortablePath(fromLTString(p.save_path)).toStdString();
228 
229  if (p.flags & lt::torrent_flags::stop_when_ready)
230  {
231  // If torrent has "stop_when_ready" flag set then it is actually "stopped"
232  torrentParams.stopped = true;
233  torrentParams.operatingMode = TorrentOperatingMode::AutoManaged;
234  // ...but temporarily "resumed" to perform some service jobs (e.g. checking)
235  p.flags &= ~lt::torrent_flags::paused;
236  p.flags |= lt::torrent_flags::auto_managed;
237  }
238  else
239  {
240  torrentParams.stopped = (p.flags & lt::torrent_flags::paused) && !(p.flags & lt::torrent_flags::auto_managed);
241  torrentParams.operatingMode = (p.flags & lt::torrent_flags::paused) || (p.flags & lt::torrent_flags::auto_managed)
242  ? TorrentOperatingMode::AutoManaged : TorrentOperatingMode::Forced;
243  }
244 
245  const bool hasMetadata = (p.ti && p.ti->is_valid());
246  if (!hasMetadata && !root.dict_find("info-hash"))
247  return std::nullopt;
248 
249  return torrentParams;
250 }
static const int USE_GLOBAL_SEEDING_TIME
Definition: torrent.h:107
static const qreal USE_GLOBAL_RATIO
Definition: torrent.h:104
QString fromPortablePath(const QString &portablePath) const
Definition: profile.cpp:126
static const Profile * instance()
Definition: profile.cpp:67
QString toUniformPath(const QString &path)
Definition: fs.cpp:69
T toEnum(const QString &serializedValue, const T &defaultValue)
Definition: string.h:77

References BitTorrent::LoadTorrentParams::category, BitTorrent::LoadTorrentParams::contentLayout, BitTorrent::LoadTorrentParams::downloadPath, BitTorrent::LoadTorrentParams::firstLastPiecePriority, anonymous_namespace{bencoderesumedatastorage.cpp}::fromLTString(), Profile::fromPortablePath(), BitTorrent::LoadTorrentParams::hasSeedStatus, Profile::instance(), BitTorrent::LoadTorrentParams::ltAddTorrentParams, BitTorrent::LoadTorrentParams::name, BitTorrent::LoadTorrentParams::operatingMode, BitTorrent::LoadTorrentParams::ratioLimit, BitTorrent::LoadTorrentParams::restored, BitTorrent::LoadTorrentParams::savePath, BitTorrent::LoadTorrentParams::seedingTimeLimit, BitTorrent::LoadTorrentParams::stopped, BitTorrent::LoadTorrentParams::tags, Utils::String::toEnum(), Utils::Fs::toUniformPath(), BitTorrent::Torrent::USE_GLOBAL_RATIO, BitTorrent::Torrent::USE_GLOBAL_SEEDING_TIME, and BitTorrent::LoadTorrentParams::useAutoTMM.

Here is the call graph for this function:

◆ registeredTorrents()

QVector< BitTorrent::TorrentID > BitTorrent::BencodeResumeDataStorage::registeredTorrents ( ) const
overridevirtual

Implements BitTorrent::ResumeDataStorage.

Definition at line 130 of file bencoderesumedatastorage.cpp.

131 {
132  return m_registeredTorrents;
133 }

◆ remove()

void BitTorrent::BencodeResumeDataStorage::remove ( const TorrentID id) const
overridevirtual

Implements BitTorrent::ResumeDataStorage.

Definition at line 260 of file bencoderesumedatastorage.cpp.

261 {
262  QMetaObject::invokeMethod(m_asyncWorker, [this, id]()
263  {
264  m_asyncWorker->remove(id);
265  });
266 }

◆ store()

void BitTorrent::BencodeResumeDataStorage::store ( const TorrentID id,
const LoadTorrentParams resumeData 
) const
overridevirtual

Implements BitTorrent::ResumeDataStorage.

Definition at line 252 of file bencoderesumedatastorage.cpp.

253 {
254  QMetaObject::invokeMethod(m_asyncWorker, [this, id, resumeData]()
255  {
256  m_asyncWorker->store(id, resumeData);
257  });
258 }
void store(const TorrentID &id, const LoadTorrentParams &resumeData) const

◆ storeQueue()

void BitTorrent::BencodeResumeDataStorage::storeQueue ( const QVector< TorrentID > &  queue) const
overridevirtual

Implements BitTorrent::ResumeDataStorage.

Definition at line 268 of file bencoderesumedatastorage.cpp.

269 {
270  QMetaObject::invokeMethod(m_asyncWorker, [this, queue]()
271  {
272  m_asyncWorker->storeQueue(queue);
273  });
274 }
void storeQueue(const QVector< TorrentID > &queue) const

Member Data Documentation

◆ m_asyncWorker

Worker* BitTorrent::BencodeResumeDataStorage::m_asyncWorker = nullptr
private

Definition at line 65 of file bencoderesumedatastorage.h.

Referenced by BencodeResumeDataStorage().

◆ m_ioThread

QThread* BitTorrent::BencodeResumeDataStorage::m_ioThread = nullptr
private

Definition at line 62 of file bencoderesumedatastorage.h.

Referenced by BencodeResumeDataStorage().

◆ m_registeredTorrents

QVector<TorrentID> BitTorrent::BencodeResumeDataStorage::m_registeredTorrents
private

Definition at line 61 of file bencoderesumedatastorage.h.

Referenced by BencodeResumeDataStorage().

◆ m_resumeDataDir


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