transmission/qt/Torrent.h

686 lines
13 KiB
C++

/*
* This file Copyright (C) 2009-2015 Mnemosyne LLC
*
* It may be used under the GNU GPL versions 2 or 3
* or any future license endorsed by Mnemosyne LLC.
*
*/
#pragma once
#include <array>
#include <bitset>
#include <ctime> // time_t
#include <QIcon>
#include <QMetaType>
#include <QObject>
#include <QString>
#include <libtransmission/transmission.h>
#include <libtransmission/crypto-utils.h>
#include <libtransmission/quark.h>
#include "FaviconCache.h"
#include "Macros.h"
#include "Speed.h"
#ifdef ERROR
#undef ERROR
#endif
class QPixmap;
class Prefs;
extern "C"
{
struct tr_variant;
}
struct Peer
{
bool client_is_choked;
bool client_is_interested;
bool is_downloading_from;
bool is_encrypted;
bool is_incoming;
bool is_uploading_to;
bool peer_is_choked;
bool peer_is_interested;
QString address;
QString client_name;
QString flags;
int port;
Speed rate_to_client;
Speed rate_to_peer;
double progress;
};
using PeerList = QVector<Peer>;
struct TrackerStat
{
QPixmap getFavicon() const;
bool has_announced;
bool has_scraped;
bool is_backup;
bool last_announce_succeeded;
bool last_announce_timed_out;
bool last_scrape_succeeded;
bool last_scrape_timed_out;
int announce_state;
int download_count;
int id;
int last_announce_peer_count;
int last_announce_start_time;
int last_announce_time;
int last_scrape_start_time;
int last_scrape_time;
int leecher_count;
int next_announce_time;
int next_scrape_time;
int scrape_state;
int seeder_count;
int tier;
FaviconCache::Key favicon_key;
QString announce;
QString last_announce_result;
QString last_scrape_result;
};
using TrackerStatsList = QVector<TrackerStat>;
struct TorrentFile
{
bool wanted = true;
int index = -1;
int priority = 0;
QString filename;
uint64_t size = 0;
uint64_t have = 0;
};
using FileList = QVector<TorrentFile>;
class TorrentHash
{
private:
std::array<uint8_t, SHA_DIGEST_LENGTH> data_ = {};
public:
TorrentHash() {}
TorrentHash(char const* str)
{
tr_hex_to_sha1(data_.data(), str);
}
TorrentHash(QString const& str)
{
tr_hex_to_sha1(data_.data(), str.toUtf8().constData());
}
bool operator ==(TorrentHash const& that) const
{
return data_ == that.data_;
}
bool operator !=(TorrentHash const& that) const
{
return data_ != that.data_;
}
bool operator <(TorrentHash const& that) const
{
return data_ < that.data_;
}
QString toString() const
{
char str[SHA_DIGEST_LENGTH * 2 + 1];
tr_sha1_to_hex(str, data_.data());
return QString::fromUtf8(str, SHA_DIGEST_LENGTH * 2);
}
};
class Torrent : public QObject
{
Q_OBJECT
TR_DISABLE_COPY_MOVE(Torrent)
public:
Torrent(Prefs const&, int id);
int getBandwidthPriority() const
{
return bandwidth_priority_;
}
int id() const
{
return id_;
}
QString const& name() const
{
return name_;
}
bool hasName() const
{
return !name_.isEmpty();
}
QString const& creator() const
{
return creator_;
}
QString const& comment() const
{
return comment_;
}
QString const& getPath() const
{
return download_dir_;
}
QString getError() const;
TorrentHash const& hash() const
{
return hash_;
}
bool hasError() const
{
return error_ != TR_STAT_OK;
}
bool isDone() const
{
return leftUntilDone() == 0;
}
bool isSeed() const
{
return haveVerified() >= totalSize();
}
bool isPrivate() const
{
return is_private_;
}
bool getSeedRatio(double& setmeRatio) const;
uint64_t haveVerified() const
{
return have_verified_;
}
uint64_t haveUnverified() const
{
return have_unchecked_;
}
uint64_t desiredAvailable() const
{
return desired_available_;
}
uint64_t haveTotal() const
{
return haveVerified() + haveUnverified();
}
uint64_t totalSize() const
{
return total_size_;
}
uint64_t sizeWhenDone() const
{
return size_when_done_;
}
uint64_t leftUntilDone() const
{
return left_until_done_;
}
uint64_t pieceSize() const
{
return piece_size_;
}
bool hasMetadata() const
{
return metadataPercentDone() >= 1.0;
}
int pieceCount() const
{
return piece_count_;
}
double ratio() const
{
auto const u = uploadedEver();
auto const d = downloadedEver();
auto const t = totalSize();
return double(u) / (d ? d : t);
}
double percentComplete() const
{
return totalSize() != 0 ? haveTotal() / static_cast<double>(totalSize()) : 0;
}
double percentDone() const
{
auto const l = leftUntilDone();
auto const s = sizeWhenDone();
return s ? double(s - l) / s : 0.0;
}
double metadataPercentDone() const
{
return metadata_percent_complete_;
}
uint64_t downloadedEver() const
{
return downloaded_ever_;
}
uint64_t uploadedEver() const
{
return uploaded_ever_;
}
uint64_t failedEver() const
{
return failed_ever_;
}
int compareSeedRatio(Torrent const&) const;
int compareRatio(Torrent const&) const;
int compareETA(Torrent const&) const;
bool hasETA() const
{
return getETA() >= 0;
}
int getETA() const
{
return eta_;
}
time_t lastActivity() const
{
return activity_date_;
}
time_t lastStarted() const
{
return start_date_;
}
time_t dateAdded() const
{
return added_date_;
}
time_t dateCreated() const
{
return date_created_;
}
time_t dateEdited() const
{
return edit_date_;
}
time_t manualAnnounceTime() const
{
return manual_announce_time_;
}
bool canManualAnnounceAt(time_t t) const
{
return isReadyToTransfer() && (manualAnnounceTime() <= t);
}
int peersWeAreDownloadingFrom() const
{
return peers_sending_to_us_;
}
int webseedsWeAreDownloadingFrom() const
{
return webseeds_sending_to_us_;
}
int peersWeAreUploadingTo() const
{
return peers_getting_from_us_;
}
bool isUploading() const
{
return peersWeAreUploadingTo() > 0;
}
int connectedPeers() const
{
return peers_connected_;
}
int connectedPeersAndWebseeds() const
{
return connectedPeers() + webseedsWeAreDownloadingFrom();
}
Speed const& downloadSpeed() const
{
return download_speed_;
}
Speed const& uploadSpeed() const
{
return upload_speed_;
}
double getVerifyProgress() const
{
return recheck_progress_;
}
bool includesTracker(FaviconCache::Key const& key) const;
FaviconCache::Keys const& trackerKeys() const
{
return tracker_keys_;
}
Speed uploadLimit() const
{
return Speed::fromKBps(upload_limit_);
}
Speed downloadLimit() const
{
return Speed::fromKBps(download_limit_);
}
bool uploadIsLimited() const
{
return upload_limited_;
}
bool downloadIsLimited() const
{
return download_limited_;
}
bool honorsSessionLimits() const
{
return honors_session_limits_;
}
int peerLimit() const
{
return peer_limit_;
}
double seedRatioLimit() const
{
return seed_ratio_limit_;
}
tr_ratiolimit seedRatioMode() const
{
return static_cast<tr_ratiolimit>(seed_ratio_mode_);
}
int seedIdleLimit() const
{
return seed_idle_limit_;
}
tr_idlelimit seedIdleMode() const
{
return static_cast<tr_idlelimit>(seed_idle_mode_);
}
TrackerStatsList const& trackerStats() const
{
return tracker_stats_;
}
PeerList const& peers() const
{
return peers_;
}
FileList const& files() const
{
return files_;
}
int queuePosition() const
{
return queue_position_;
}
bool isStalled() const
{
return is_stalled_;
}
QString activityString() const;
tr_torrent_activity getActivity() const
{
return static_cast<tr_torrent_activity>(status_);
}
bool isFinished() const
{
return is_finished_;
}
bool isPaused() const
{
return getActivity() == TR_STATUS_STOPPED;
}
bool isWaitingToVerify() const
{
return getActivity() == TR_STATUS_CHECK_WAIT;
}
bool isVerifying() const
{
return getActivity() == TR_STATUS_CHECK;
}
bool isDownloading() const
{
return getActivity() == TR_STATUS_DOWNLOAD;
}
bool isWaitingToDownload() const
{
return getActivity() == TR_STATUS_DOWNLOAD_WAIT;
}
bool isSeeding() const
{
return getActivity() == TR_STATUS_SEED;
}
bool isWaitingToSeed() const
{
return getActivity() == TR_STATUS_SEED_WAIT;
}
bool isReadyToTransfer() const
{
return getActivity() == TR_STATUS_DOWNLOAD || getActivity() == TR_STATUS_SEED;
}
bool isQueued() const
{
return isWaitingToDownload() || isWaitingToSeed();
}
QIcon getMimeTypeIcon() const;
enum Field
{
ACTIVITY_DATE,
ADDED_DATE,
BANDWIDTH_PRIORITY,
COMMENT,
CREATOR,
DATE_CREATED,
DESIRED_AVAILABLE,
DOWNLOADED_EVER,
DOWNLOAD_DIR,
DOWNLOAD_LIMIT,
DOWNLOAD_LIMITED,
DOWNLOAD_SPEED,
EDIT_DATE,
ERROR,
ERROR_STRING,
ETA,
FAILED_EVER,
FILE_COUNT,
FILES,
HASH,
HAVE_UNCHECKED,
HAVE_VERIFIED,
HONORS_SESSION_LIMITS,
ICON,
IS_FINISHED,
IS_PRIVATE,
IS_STALLED,
LEFT_UNTIL_DONE,
MANUAL_ANNOUNCE_TIME,
METADATA_PERCENT_COMPLETE,
NAME,
PEERS,
PEERS_CONNECTED,
PEERS_GETTING_FROM_US,
PEERS_SENDING_TO_US,
PEER_LIMIT,
PERCENT_DONE,
PIECE_COUNT,
PIECE_SIZE,
PRIMARY_MIME_TYPE,
QUEUE_POSITION,
RECHECK_PROGRESS,
SEED_IDLE_LIMIT,
SEED_IDLE_MODE,
SEED_RATIO_LIMIT,
SEED_RATIO_MODE,
SIZE_WHEN_DONE,
START_DATE,
STATUS,
TOTAL_SIZE,
TRACKER_STATS,
UPLOADED_EVER,
UPLOAD_LIMIT,
UPLOAD_LIMITED,
UPLOAD_SPEED,
WEBSEEDS_SENDING_TO_US,
N_FIELDS
};
using fields_t = std::bitset<N_FIELDS>;
fields_t update(tr_quark const* keys, tr_variant const* const* values, size_t n);
private:
int const id_;
bool download_limited_ = {};
bool honors_session_limits_ = {};
bool is_finished_ = {};
bool is_private_ = {};
bool is_stalled_ = {};
bool upload_limited_ = {};
time_t activity_date_ = {};
time_t added_date_ = {};
time_t date_created_ = {};
time_t edit_date_ = {};
time_t manual_announce_time_ = {};
time_t start_date_ = {};
int bandwidth_priority_ = {};
int download_limit_ = {};
int error_ = {};
int eta_ = {};
int peer_limit_ = {};
int peers_connected_ = {};
int peers_getting_from_us_ = {};
int peers_sending_to_us_ = {};
int piece_count_ = {};
int queue_position_ = {};
int seed_idle_limit_ = {};
int seed_idle_mode_ = {};
int seed_ratio_mode_ = {};
int status_ = {};
int upload_limit_ = {};
int webseeds_sending_to_us_ = {};
uint64_t desired_available_ = {};
uint64_t downloaded_ever_ = {};
uint64_t failed_ever_ = {};
uint64_t file_count_ = {};
uint64_t have_unchecked_ = {};
uint64_t have_verified_ = {};
uint64_t left_until_done_ = {};
uint64_t piece_size_ = {};
uint64_t size_when_done_ = {};
uint64_t total_size_ = {};
uint64_t uploaded_ever_ = {};
double metadata_percent_complete_ = {};
double percent_done_ = {};
double recheck_progress_ = {};
double seed_ratio_limit_ = {};
QString primary_mime_type_;
QString comment_;
QString creator_;
QString download_dir_;
QString error_string_;
QString name_;
// mutable because it's a lazy lookup
mutable QIcon icon_;
PeerList peers_;
FileList files_;
FaviconCache::Keys tracker_keys_;
TrackerStatsList tracker_stats_;
Speed upload_speed_;
Speed download_speed_;
Prefs const& prefs_;
TorrentHash hash_;
};
Q_DECLARE_METATYPE(Torrent const*)