Browse Source

Handle exception when torrent file cannot be exported

Both `lt::create_torrent` constructor and `lt::create_torrent::generate()`
can throw an exception so we need to handle it to prevent the app from crashing.
adaptive-webui-19844
Vladimir Golovnev (Glassez) 3 years ago committed by Vladimir Golovnev
parent
commit
3faa7226e7
  1. 14
      src/base/bittorrent/bencoderesumedatastorage.cpp
  2. 15
      src/base/bittorrent/dbresumedatastorage.cpp
  3. 2
      src/base/bittorrent/session.cpp
  4. 38
      src/base/bittorrent/torrentcreatorthread.cpp
  5. 10
      src/base/bittorrent/torrentcreatorthread.h
  6. 25
      src/base/bittorrent/torrentinfo.cpp
  7. 3
      src/gui/addnewtorrentdialog.cpp

14
src/base/bittorrent/bencoderesumedatastorage.cpp

@ -338,18 +338,24 @@ void BitTorrent::BencodeResumeDataStorage::Worker::store(const TorrentID &id, co @@ -338,18 +338,24 @@ void BitTorrent::BencodeResumeDataStorage::Worker::store(const TorrentID &id, co
if (torrentInfo)
{
const QString torrentFilepath = m_resumeDataDir.absoluteFilePath(QString::fromLatin1("%1.torrent").arg(id.toString()));
const lt::create_torrent torrentCreator = lt::create_torrent(*torrentInfo);
const lt::entry metadata = torrentCreator.generate();
try
{
const auto torrentCreator = lt::create_torrent(*torrentInfo);
const lt::entry metadata = torrentCreator.generate();
writeEntryToFile(torrentFilepath, metadata);
}
catch (const RuntimeError &err)
{
LogMsg(tr("Couldn't save torrent metadata to '%1'. Error: %2")
LogMsg(tr("Couldn't save torrent metadata to '%1'. Error: %2.")
.arg(torrentFilepath, err.message()), Log::CRITICAL);
return;
}
catch (const std::exception &err)
{
LogMsg(tr("Couldn't save torrent metadata to '%1'. Error: %2.")
.arg(torrentFilepath, QString::fromLocal8Bit(err.what())), Log::CRITICAL);
return;
}
}
lt::entry data = lt::write_resume_data(p);
@ -371,7 +377,7 @@ void BitTorrent::BencodeResumeDataStorage::Worker::store(const TorrentID &id, co @@ -371,7 +377,7 @@ void BitTorrent::BencodeResumeDataStorage::Worker::store(const TorrentID &id, co
}
catch (const RuntimeError &err)
{
LogMsg(tr("Couldn't save torrent resume data to '%1'. Error: %2")
LogMsg(tr("Couldn't save torrent resume data to '%1'. Error: %2.")
.arg(resumeFilepath, err.message()), Log::CRITICAL);
}
}

15
src/base/bittorrent/dbresumedatastorage.cpp

@ -459,9 +459,18 @@ void BitTorrent::DBResumeDataStorage::Worker::store(const TorrentID &id, const L @@ -459,9 +459,18 @@ void BitTorrent::DBResumeDataStorage::Worker::store(const TorrentID &id, const L
const std::shared_ptr<lt::torrent_info> torrentInfo = std::move(p.ti);
if (torrentInfo)
{
const lt::create_torrent torrentCreator = lt::create_torrent(*torrentInfo);
const lt::entry metadata = torrentCreator.generate();
lt::bencode(std::back_inserter(bencodedMetadata), metadata);
try
{
const auto torrentCreator = lt::create_torrent(*torrentInfo);
const lt::entry metadata = torrentCreator.generate();
lt::bencode(std::back_inserter(bencodedMetadata), metadata);
}
catch (const std::exception &err)
{
LogMsg(tr("Couldn't save torrent metadata. Error: %1.")
.arg(QString::fromLocal8Bit(err.what())), Log::CRITICAL);
return;
}
columns.append(DB_COLUMN_METADATA);
}

2
src/base/bittorrent/session.cpp

@ -2321,7 +2321,7 @@ void Session::exportTorrentFile(const Torrent *torrent, TorrentExportFolder fold @@ -2321,7 +2321,7 @@ void Session::exportTorrentFile(const Torrent *torrent, TorrentExportFolder fold
}
catch (const RuntimeError &err)
{
LogMsg(tr("Couldn't export torrent metadata file '%1'. Reason: %2")
LogMsg(tr("Couldn't export torrent metadata file '%1'. Reason: %2.")
.arg(newTorrentPath, err.message()), Log::WARNING);
}
}

38
src/base/bittorrent/torrentcreatorthread.cpp

@ -98,6 +98,12 @@ void TorrentCreatorThread::sendProgressSignal(int currentPieceIdx, int totalPiec @@ -98,6 +98,12 @@ void TorrentCreatorThread::sendProgressSignal(int currentPieceIdx, int totalPiec
emit updateProgress(static_cast<int>((currentPieceIdx * 100.) / totalPieces));
}
void TorrentCreatorThread::checkInterruptionRequested() const
{
if (isInterruptionRequested())
throw RuntimeError(tr("Operation aborted"));
}
void TorrentCreatorThread::run()
{
emit updateProgress(0);
@ -118,7 +124,7 @@ void TorrentCreatorThread::run() @@ -118,7 +124,7 @@ void TorrentCreatorThread::run()
// need to sort the file names by natural sort order
QStringList dirs = {m_params.inputPath};
QDirIterator dirIter(m_params.inputPath, (QDir::AllDirs | QDir::NoDotAndDotDot), QDirIterator::Subdirectories);
QDirIterator dirIter {m_params.inputPath, (QDir::AllDirs | QDir::NoDotAndDotDot), QDirIterator::Subdirectories};
while (dirIter.hasNext())
{
dirIter.next();
@ -151,7 +157,7 @@ void TorrentCreatorThread::run() @@ -151,7 +157,7 @@ void TorrentCreatorThread::run()
fs.add_file(fileName.toStdString(), fileSizeMap[fileName]);
}
if (isInterruptionRequested()) return;
checkInterruptionRequested();
#if (LIBTORRENT_VERSION_NUM >= 20000)
lt::create_torrent newTorrent {fs, m_params.pieceSize, toNativeTorrentFormatFlag(m_params.torrentFormat)};
@ -181,9 +187,7 @@ void TorrentCreatorThread::run() @@ -181,9 +187,7 @@ void TorrentCreatorThread::run()
lt::set_piece_hashes(newTorrent, Utils::Fs::toNativePath(parentPath).toStdString()
, [this, &newTorrent](const lt::piece_index_t n)
{
if (isInterruptionRequested())
throw RuntimeError {tr("Create new torrent aborted.")};
checkInterruptionRequested();
sendProgressSignal(static_cast<LTUnderlyingType<lt::piece_index_t>>(n), newTorrent.num_pieces());
});
@ -194,7 +198,7 @@ void TorrentCreatorThread::run() @@ -194,7 +198,7 @@ void TorrentCreatorThread::run()
// Is private ?
newTorrent.set_priv(m_params.isPrivate);
if (isInterruptionRequested()) return;
checkInterruptionRequested();
lt::entry entry = newTorrent.generate();
@ -202,32 +206,30 @@ void TorrentCreatorThread::run() @@ -202,32 +206,30 @@ void TorrentCreatorThread::run()
if (!m_params.source.isEmpty())
entry["info"]["source"] = m_params.source.toStdString();
if (isInterruptionRequested()) return;
checkInterruptionRequested();
// create the torrent
QFile outfile {m_params.savePath};
if (!outfile.open(QIODevice::WriteOnly))
{
throw RuntimeError {tr("Create new torrent file failed. Reason: %1")
.arg(outfile.errorString())};
}
throw RuntimeError(outfile.errorString());
if (isInterruptionRequested()) return;
checkInterruptionRequested();
lt::bencode(Utils::IO::FileDeviceOutputIterator {outfile}, entry);
if (outfile.error() != QFileDevice::NoError)
{
throw RuntimeError {tr("Create new torrent file failed. Reason: %1")
.arg(outfile.errorString())};
}
throw RuntimeError(outfile.errorString());
outfile.close();
emit updateProgress(100);
emit creationSuccess(m_params.savePath, parentPath);
}
catch (const std::exception &e)
catch (const RuntimeError &err)
{
emit creationFailure(tr("Create new torrent file failed. Reason: %1.").arg(err.message()));
}
catch (const std::exception &err)
{
emit creationFailure(e.what());
emit creationFailure(tr("Create new torrent file failed. Reason: %1.").arg(QString::fromLocal8Bit(err.what())));
}
}

10
src/base/bittorrent/torrentcreatorthread.h

@ -65,10 +65,11 @@ namespace BitTorrent @@ -65,10 +65,11 @@ namespace BitTorrent
class TorrentCreatorThread final : public QThread
{
Q_OBJECT
Q_DISABLE_COPY_MOVE(TorrentCreatorThread)
public:
TorrentCreatorThread(QObject *parent = nullptr);
~TorrentCreatorThread();
explicit TorrentCreatorThread(QObject *parent = nullptr);
~TorrentCreatorThread() override;
void create(const TorrentCreatorParams &params);
@ -79,16 +80,15 @@ namespace BitTorrent @@ -79,16 +80,15 @@ namespace BitTorrent
, const int pieceSize, const bool isAlignmentOptimized, int paddedFileSizeLimit);
#endif
protected:
void run() override;
signals:
void creationFailure(const QString &msg);
void creationSuccess(const QString &path, const QString &branchPath);
void updateProgress(int progress);
private:
void run() override;
void sendProgressSignal(int currentPieceIdx, int totalPieces);
void checkInterruptionRequested() const;
TorrentCreatorParams m_params;
};

25
src/base/bittorrent/torrentinfo.cpp

@ -167,18 +167,25 @@ TorrentInfo TorrentInfo::loadFromFile(const QString &path, QString *error) noexc @@ -167,18 +167,25 @@ TorrentInfo TorrentInfo::loadFromFile(const QString &path, QString *error) noexc
void TorrentInfo::saveToFile(const QString &path) const
{
if (!isValid())
throw RuntimeError {tr("Invalid metadata.")};
throw RuntimeError {tr("Invalid metadata")};
const lt::create_torrent torrentCreator = lt::create_torrent(*(nativeInfo()));
const lt::entry torrentEntry = torrentCreator.generate();
try
{
const auto torrentCreator = lt::create_torrent(*nativeInfo());
const lt::entry torrentEntry = torrentCreator.generate();
QFile torrentFile {path};
if (!torrentFile.open(QIODevice::WriteOnly))
throw RuntimeError {torrentFile.errorString()};
QFile torrentFile {path};
if (!torrentFile.open(QIODevice::WriteOnly))
throw RuntimeError(torrentFile.errorString());
lt::bencode(Utils::IO::FileDeviceOutputIterator {torrentFile}, torrentEntry);
if (torrentFile.error() != QFileDevice::NoError)
throw RuntimeError {torrentFile.errorString()};
lt::bencode(Utils::IO::FileDeviceOutputIterator {torrentFile}, torrentEntry);
if (torrentFile.error() != QFileDevice::NoError)
throw RuntimeError(torrentFile.errorString());
}
catch (const lt::system_error &err)
{
throw RuntimeError(QString::fromLocal8Bit(err.what()));
}
}
bool TorrentInfo::isValid() const

3
src/gui/addnewtorrentdialog.cpp

@ -475,7 +475,8 @@ void AddNewTorrentDialog::saveTorrentFile() @@ -475,7 +475,8 @@ void AddNewTorrentDialog::saveTorrentFile()
}
catch (const RuntimeError &err)
{
QMessageBox::critical(this, tr("I/O Error"), err.message());
QMessageBox::critical(this, tr("I/O Error")
, tr("Couldn't export torrent metadata file '%1'. Reason: %2.").arg(path, err.message()));
}
}

Loading…
Cancel
Save