All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.libtorrent4j.TorrentHandle Maven / Gradle / Ivy

The newest version!
/*
 * Copyright (c) 2018-2023, Alden Torres
 *
 * Licensed under the terms of the MIT license.
 * Copy of the license at https://opensource.org/licenses/MIT
 */

package org.libtorrent4j;

import org.libtorrent4j.alerts.CacheFlushedAlert;
import org.libtorrent4j.alerts.FileErrorAlert;
import org.libtorrent4j.alerts.FileRenameFailedAlert;
import org.libtorrent4j.alerts.FileRenamedAlert;
import org.libtorrent4j.alerts.HashFailedAlert;
import org.libtorrent4j.alerts.PieceFinishedAlert;
import org.libtorrent4j.alerts.ReadPieceAlert;
import org.libtorrent4j.alerts.StorageMovedAlert;
import org.libtorrent4j.alerts.StorageMovedFailedAlert;
import org.libtorrent4j.alerts.TorrentNeedCertAlert;
import org.libtorrent4j.swig.add_piece_flags_t;
import org.libtorrent4j.swig.announce_entry_vector;
import org.libtorrent4j.swig.byte_vector;
import org.libtorrent4j.swig.deadline_flags_t;
import org.libtorrent4j.swig.file_progress_flags_t;
import org.libtorrent4j.swig.int64_vector;
import org.libtorrent4j.swig.int_vector;
import org.libtorrent4j.swig.libtorrent;
import org.libtorrent4j.swig.partial_piece_info_vector;
import org.libtorrent4j.swig.peer_info_vector;
import org.libtorrent4j.swig.reannounce_flags_t;
import org.libtorrent4j.swig.resume_data_flags_t;
import org.libtorrent4j.swig.status_flags_t;
import org.libtorrent4j.swig.torrent_flags_t;
import org.libtorrent4j.swig.torrent_handle;
import org.libtorrent4j.swig.torrent_info;
import org.libtorrent4j.swig.torrent_status;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/**
 * You will usually have to store your torrent handles somewhere, since it's
 * the object through which you retrieve information about the torrent and
 * aborts the torrent.
 * 

* .. warning:: * Any member function that returns a value or fills in a value has to be * made synchronously. This means it has to wait for the main thread to * complete the query before it can return. This might potentially be * expensive if done from within a GUI thread that needs to stay * responsive. Try to avoid querying for information you don't need, and * try to do it in as few calls as possible. You can get most of the * interesting information about a torrent from the * torrent_handle::status() call. *

* The default constructor will initialize the handle to an invalid state. * Which means you cannot perform any operation on it, unless you first * assign it a valid handle. If you try to perform any operation on an * uninitialized handle, it will throw ``invalid_handle``. *

* .. warning:: * All operations on a torrent_handle may throw libtorrent_exception * exception, in case the handle is no longer referring to a torrent. * There is one exception is_valid() will never throw. Since the torrents * are processed by a background thread, there is no guarantee that a * handle will remain valid between two calls. * * @author gubatron * @author aldenml */ public final class TorrentHandle extends SwigObject { private static final long REQUEST_STATUS_RESOLUTION_MILLIS = 500; // cache this zero flag for performance reasons private static final status_flags_t STATUS_FLAGS_ZERO = new status_flags_t(); private long lastStatusRequestTime; private TorrentStatus lastStatus; /** * @param th the native object */ public TorrentHandle(torrent_handle th) { super(th); } /** * Instruct libtorrent to overwrite any data that may already have been * downloaded with the data of the new piece being added. */ public static final add_piece_flags_t OVERWRITE_EXISTING = torrent_handle.overwrite_existing; /** * This function will write {@code data} to the storage as piece {@code piece}, * as if it had been downloaded from a peer. {@code data} is expected to * point to a buffer of as many bytes as the size of the specified piece. * The data in the buffer is copied and passed on to the disk IO thread * to be written at a later point. *

* By default, data that's already been downloaded is not overwritten by * this buffer. If you trust this data to be correct (and pass the piece * hash check) you may pass the overwrite_existing flag. This will * instruct libtorrent to overwrite any data that may already have been * downloaded with this data. *

* Since the data is written asynchronously, you may know that is passed * or failed the hash check by waiting for * {@link PieceFinishedAlert} or * {@link HashFailedAlert}. * * @param piece the piece index * @param data the piece data * @param flags flags */ public void addPiece(int piece, byte[] data, add_piece_flags_t flags) { h.add_piece_bytes(piece, Vectors.bytes2byte_vector(data), flags); } /** * Same as calling {@link #addPiece(int, byte[], add_piece_flags_t)} with * {@code flags} with value 0. * * @param piece the piece index * @param data the piece data */ public void addPiece(int piece, byte[] data) { h.add_piece_bytes(piece, Vectors.bytes2byte_vector(data)); } /** * This function starts an asynchronous read operation of the specified * piece from this torrent. You must have completed the download of the * specified piece before calling this function. *

* When the read operation is completed, it is passed back through an * alert, {@link ReadPieceAlert}. * Since this alert is a response to an explicit * call, it will always be posted, regardless of the alert mask. *

* Note that if you read multiple pieces, the read operations are not * guaranteed to finish in the same order as you initiated them. * * @param piece the piece index */ public void readPiece(int piece) { h.read_piece(piece); } /** * Sets the first and last piece of the range for the piece picker to start * downloading in sequential mode. * * If the torrent metadata has not been downloaded yet * then the functions do nothing. * * @param firstPiece piece index for the rage */ public void setSequentialRange(int firstPiece, int lastPiece) { h.set_sequential_range(firstPiece, lastPiece); } /** * Sets the first piece of the range for the piece picker to start * downloading in sequential mode. *

* If the torrent metadata has not been downloaded yet * then the functions do nothing. * * @param firstPiece piece index for the rage */ public void setSequentialRange(int firstPiece) { h.set_sequential_range(firstPiece); } /** * Returns true if this piece has been completely downloaded, and false * otherwise. * * @param piece the piece index * @return if piece has been completely downloaded */ public boolean havePiece(int piece) { return h.have_piece(piece); } /** * Returns a list filled with one entry for each peer connected to this * torrent, given the handle is valid. If the handle is invalid, it will * return an empty list. *

* Each entry in the vector contains information about that particular peer. * * @return the list with the peers information * @see PeerInfo */ public List peerInfo() { if (!h.is_valid()) { return new ArrayList<>(); } peer_info_vector v = new peer_info_vector(); h.get_peer_info(v); int size = v.size(); ArrayList l = new ArrayList<>(size); for (int i = 0; i < size; i++) { l.add(new PeerInfo(v.get(i))); } return l; } /** * Returns a pointer to the torrent_info object associated with this * torrent. The {@link TorrentInfo} object may be a copy of the internal * object. If the torrent doesn't have metadata, the pointer will not be * initialized (i.e. a null). The torrent may be in a state without * metadata only if it was started without a .torrent file, e.g. by being * added by magnet link. *

* Note that the {@link TorrentInfo} object returned here may be a different * instance than the one added to the session, with different attributes * like piece layers, dht nodes and trackers. A {@link TorrentInfo} object does * not round-trip cleanly when added to a session. *

* This means if you want to create a .torrent file by passing the * {@link TorrentInfo} object into create_torrent, you need to use * {@link #torrentFileWithHashes()} instead. * * @return the internal torrent info */ public TorrentInfo torrentFile() { if (!h.is_valid()) { return null; } torrent_info ti = h.torrent_file_ptr(); return ti != null ? new TorrentInfo(ti) : null; } /** * Returns a *copy* of the internal {@link TorrentInfo} and piece layer * hashes (if it's a v2 torrent). The piece layers will only be included * if they are available. If this torrent was added from a .torrent file * with piece layers or if it's seeding, the piece layers are available. * This function is more expensive than {@link #torrentFile()} since it * needs to make copies of this information. *

* When constructing a create_torrent object from a {@link TorrentInfo} that's * in a session, you need to use this function. *

* Note that a torrent added from a magnet link may not have the full * merkle trees for all files, and hence not have the complete piece * layers. In that state, you cannot create a .torrent file even from * the {@link TorrentInfo} returned from `torrentFileWithHashes`. Once the * torrent completes downloading all files, becoming a seed, you can * make a .torrent file from it. * * @return a *copy* of the internal torrent info with the piece layer * hashes (if it's a v2 torrent). */ public TorrentInfo torrentFileWithHashes() { if (!h.is_valid()) { return null; } torrent_info ti = h.torrent_file_with_hashes_ptr(); return ti != null ? new TorrentInfo(ti) : null; } /** * `status()`` will return a structure with information about the status * of this torrent. If the torrent_handle is invalid, it will throw * libtorrent_exception exception. See torrent_status. The ``flags`` * argument filters what information is returned in the torrent_status. * Some information in there is relatively expensive to calculate, and if * you're not interested in it (and see performance issues), you can * filter them out. *

* By default everything is included. The flags you can use to decide * what to *include* are defined in the status_flags_t enum. *

* It is important not to call this method for each field in the status * for performance reasons. * * @return the status */ public TorrentStatus status(boolean force) { long now = System.currentTimeMillis(); if (force || (now - lastStatusRequestTime) >= REQUEST_STATUS_RESOLUTION_MILLIS) { lastStatusRequestTime = now; lastStatus = new TorrentStatus(h.status(STATUS_FLAGS_ZERO)); } return lastStatus; } /** * Returns a structure with information about the status * of this torrent. If the handle is invalid, it will throw * libtorrent_exception exception. See torrent_status. The ``flags`` * argument filters what information is returned in the torrent_status. * Some information in there is relatively expensive to calculate, and if * you're not interested in it (and see performance issues), you can * filter them out. * * @return the status */ public TorrentStatus status() { return status(false); } /** * calculates ``distributed_copies``, ``distributed_full_copies`` and * ``distributed_fraction``. */ public static final status_flags_t QUERY_DISTRIBUTED_COPIES = torrent_handle.query_distributed_copies; /** * includes partial downloaded blocks in ``total_done`` and * ``total_wanted_done``. */ public static final status_flags_t QUERY_ACCURATE_DOWNLOAD_COUNTERS = torrent_handle.query_accurate_download_counters; /** * includes ``last_seen_complete``. */ public static final status_flags_t QUERY_LAST_SEEN_COMPLETE = torrent_handle.query_last_seen_complete; /** * includes ``pieces``. */ public static final status_flags_t QUERY_PIECES = torrent_handle.query_pieces; /** * includes ``verified_pieces`` (only applies to torrents in *seed mode*). */ public static final status_flags_t QUERY_VERIFIED_PIECES = torrent_handle.query_verified_pieces; /** * includes ``torrent_file``, which is all the static information from the .torrent file. */ public static final status_flags_t QUERY_TORRENT_FILE = torrent_handle.query_torrent_file; /** * includes {@code name}, the name of the torrent. This is either derived * from the .torrent file, or from the {@code &dn=} magnet link argument * or possibly some other source. If the name of the torrent is not * known, this is an empty string. */ public static final status_flags_t QUERY_NAME = torrent_handle.query_name; /** * includes ``save_path``, the path to the directory the files of the * torrent are saved to. */ public static final status_flags_t QUERY_SAVE_PATH = torrent_handle.query_save_path; /** * This method returns an up to date torrent status, the {@code flags} parameters * is an or-combination of the {@link status_flags_t} native values, in case you want * advanced (and expensive) fields filled. We recommend the use of the simple call * to {@link #status()} that internally keep a cache with a small time resolution. * * @param flags the flags * @return the status */ public TorrentStatus status(status_flags_t flags) { return new TorrentStatus(h.status(flags)); } /** * Returns an array (list) with information about pieces that are partially * downloaded or not downloaded at all but partially requested. See * {@link PartialPieceInfo} for the fields in the returned vector. * * @return a list with partial piece info */ public ArrayList getDownloadQueue() { partial_piece_info_vector v = new partial_piece_info_vector(); h.get_download_queue(v); int size = (int) v.size(); ArrayList l = new ArrayList<>(size); for (int i = 0; i < size; i++) { l.add(new PartialPieceInfo(v.get(i))); } return l; } /** * Returns the info-hash for the torrent. *

* If this handle is to a torrent that hasn't loaded yet (for instance by being added) * by a URL, the returned value is undefined. * * @return the torrent info hash */ public Sha1Hash infoHash() { return new Sha1Hash(h.info_hash()); } /** * This method will disconnect all peers. *

* When a torrent is paused, it will however * remember all share ratios to all peers and remember all potential (not * connected) peers. Torrents may be paused automatically if there is a * file error (e.g. disk full) or something similar. See * {@link FileErrorAlert}. *

* To know if a torrent is paused or not, call * {@link #status()} and inspect TorrentStatus#isPaused() . *

* The ``flags`` argument to pause can be set to * ``torrent_handle::graceful_pause`` which will delay the disconnect of * peers that we're still downloading outstanding requests from. The * torrent will not accept any more requests and will disconnect all idle * peers. As soon as a peer is done transferring the blocks that were * requested from it, it is disconnected. This is a graceful shut down of * the torrent in the sense that no downloaded bytes are wasted. *

* torrents that are auto-managed may be automatically resumed again. It * does not make sense to pause an auto-managed torrent without making it * not automanaged first. */ public void pause() { h.pause(); } /** * Will reconnect all peers. *

* Torrents that are auto-managed may be automatically resumed again. */ public void resume() { h.resume(); } public torrent_flags_t getFlags() { return h.flags(); } public void setFlags(torrent_flags_t flags, torrent_flags_t mask) { h.set_flags(flags, mask); } public void setFlags(torrent_flags_t flags) { h.set_flags(flags); } public void unsetFlags(torrent_flags_t flags) { h.unset_flags(flags); } /** * Instructs libtorrent to flush all the disk caches for this torrent and * close all file handles. This is done asynchronously and you will be * notified that it's complete through {@link CacheFlushedAlert}. *

* Note that by the time you get the alert, libtorrent may have cached * more data for the torrent, but you are guaranteed that whatever cached * data libtorrent had by the time you called * {@code flushCache()} has been written to disk. */ public void flushCache() { h.flush_cache(); } /** * Returns true if any whole chunk has been downloaded * since the torrent was first loaded or since the last time the resume * data was saved. When saving resume data periodically, it makes sense * to skip any torrent which hasn't downloaded anything since the last * time. *

* A torrent's resume data is considered saved as soon as the alert is * posted. It is important to make sure this alert is received and * handled in order for this function to be meaningful. * * @return true if data has been downloaded since the last time the resume * data was saved. */ public boolean needSaveResumeData() { return h.need_save_resume_data(); } /** * Every torrent that is added is assigned a queue position exactly one * greater than the greatest queue position of all existing torrents. * Torrents that are being seeded have -1 as their queue position, since * they're no longer in line to be downloaded. *

* When a torrent is removed or turns into a seed, all torrents with * greater queue positions have their positions decreased to fill in the * space in the sequence. *

* This function returns the torrent's position in the download * queue. The torrents with the smallest numbers are the ones that are * being downloaded. The smaller number, the closer the torrent is to the * front of the line to be started. *

* The queue position is also available in the torrent_status. * * @return the queue position */ public int queuePosition() { return h.queue_position_ex(); } /** * The {@code queue_position_*()} functions adjust the torrents position in * the queue. Up means closer to the front and down means closer to the * back of the queue. Top and bottom refers to the front and the back of * the queue respectively. */ public void queuePositionUp() { h.queue_position_up(); } /** * The {@code queue_position_*()} functions adjust the torrents position in * the queue. Up means closer to the front and down means closer to the * back of the queue. Top and bottom refers to the front and the back of * the queue respectively. */ public void queuePositionDown() { h.queue_position_down(); } /** * The {@code queue_position_*()} functions adjust the torrents position in * the queue. Up means closer to the front and down means closer to the * back of the queue. Top and bottom refers to the front and the back of * the queue respectively. */ public void queuePositionTop() { h.queue_position_top(); } /** * The {@code queue_position_*()} functions adjust the torrents position in * the queue. Up means closer to the front and down means closer to the * back of the queue. Top and bottom refers to the front and the back of * the queue respectively. */ public void queuePositionBottom() { h.queue_position_bottom(); } /** * Updates the position in the queue for this torrent. The relative order * of all other torrents remain intact but their numerical queue position * shifts to make space for this torrent's new position * * @param position the new position */ public void queuePositionSet(int position) { h.queue_position_set_ex(position); } /** * For SSL torrents, use this to specify a path to a .pem file to use as * this client's certificate. The certificate must be signed by the * certificate in the .torrent file to be valid. *

* Note that when a torrent first starts up, and it needs a certificate, * it will suspend connecting to any peers until it has one. It's * typically desirable to resume the torrent after setting the SSL * certificate. *

* If you receive a {@link TorrentNeedCertAlert}, * you need to call this to provide a valid cert. If you don't have a cert * you won't be allowed to connect to any peers. * * @param certificate is a path to the (signed) certificate in .pem format * corresponding to this torrent. * @param privateKey is a path to the private key for the specified * certificate. This must be in .pem format. * @param dhParams is a path to the Diffie-Hellman parameter file, which * needs to be in .pem format. You can generate this file using the * openssl command like this: ``openssl dhparam -outform PEM -out * dhparams.pem 512``. */ public void setSslCertificate(String certificate, String privateKey, String dhParams) { h.set_ssl_certificate(certificate, privateKey, dhParams); } /** * For SSL torrents, use this to specify a path to a .pem file to use as * this client's certificate. The certificate must be signed by the * certificate in the .torrent file to be valid. *

* Note that when a torrent first starts up, and it needs a certificate, * it will suspend connecting to any peers until it has one. It's * typically desirable to resume the torrent after setting the SSL * certificate. *

* If you receive a {@link TorrentNeedCertAlert}, * you need to call this to provide a valid cert. If you don't have a cert * you won't be allowed to connect to any peers. * * @param certificate is a path to the (signed) certificate in .pem format * corresponding to this torrent. * @param privateKey is a path to the private key for the specified * certificate. This must be in .pem format. * @param dhParams is a path to the Diffie-Hellman parameter file, which * needs to be in .pem format. You can generate this file using the * openssl command like this: ``openssl dhparam -outform PEM -out * dhparams.pem 512``. * @param passphrase may be specified if the private key is encrypted and * requires a passphrase to be decrypted. */ public void setSslCertificate(String certificate, String privateKey, String dhParams, String passphrase) { h.set_ssl_certificate(certificate, privateKey, dhParams, passphrase); } /** * This method is like {@link #setSslCertificate} but takes the actual * certificate, private key and DH params as byte arrays, rather than paths * to files. * * @param certificate buffer of the (signed) certificate in .pem format * corresponding to this torrent. * @param privateKey buffer of the private key for the specified * certificate. This must be in .pem format. * @param dhParams buffer of the Diffie-Hellman parameter file, which * needs to be in .pem format. */ void setSslCertificateBuffer(byte[] certificate, byte[] privateKey, byte[] dhParams) { byte_vector cert = Vectors.bytes2byte_vector(certificate); byte_vector pk = Vectors.bytes2byte_vector(privateKey); byte_vector dh = Vectors.bytes2byte_vector(dhParams); h.set_ssl_certificate_buffer_ex(cert, pk, dh); } /** * The disk cache will be flushed before creating the resume data. * This avoids a problem with file timestamps in the resume data in * case the cache hasn't been flushed yet. */ public static final resume_data_flags_t FLUSH_DISK_CACHE = torrent_handle.flush_disk_cache; /** * The resume data will contain the metadata from the torrent file as * well. This is default for any torrent that's added without a * torrent file (such as a magnet link or a URL). */ public static final resume_data_flags_t SAVE_INFO_DICT = torrent_handle.save_info_dict; /** * If nothing significant has changed in the torrent since the last * time resume data was saved, fail this attempt. Significant changes * primarily include more data having been downloaded, file or piece * priorities having changed etc. If the resume data doesn't need * saving, a save_resume_data_failed_alert is posted with the error * resume_data_not_modified. */ public static final resume_data_flags_t ONLY_IF_MODIFIED = torrent_handle.only_if_modified; /** * ``save_resume_data()`` generates fast-resume data and returns it as an * entry. This entry is suitable for being bencoded. For more information * about how fast-resume works, see fast-resume_. *

* The ``flags`` argument is a bitmask of flags ORed together. see * save_resume_flags_t *

* This operation is asynchronous, ``save_resume_data`` will return * immediately. The resume data is delivered when it's done through an * save_resume_data_alert. *

* The fast resume data will be empty in the following cases: *

* 1. The torrent handle is invalid. * 2. The torrent is checking (or is queued for checking) its storage, it * will obviously not be ready to write resume data. * 3. The torrent hasn't received valid metadata and was started without * metadata (see libtorrent's metadata-from-peers_ extension) *

* Note that by the time you receive the fast resume data, it may already * be invalid if the torrent is still downloading! The recommended * practice is to first pause the session, then generate the fast resume * data, and then close it down. Make sure to not remove_torrent() before * you receive the save_resume_data_alert though. There's no need to * pause when saving intermittent resume data. *

* .. warning:: * If you pause every torrent individually instead of pausing the * session, every torrent will have its paused state saved in the * resume data! *

* .. warning:: * The resume data contains the modification timestamps for all files. * If one file has been modified when the torrent is added again, the * will be rechecked. When shutting down, make sure to flush the disk * cache before saving the resume data. This will make sure that the * file timestamps are up to date and won't be modified after saving * the resume data. The recommended way to do this is to pause the * torrent, which will flush the cache and disconnect all peers. *

* .. note:: * It is typically a good idea to save resume data whenever a torrent * is completed or paused. In those cases you don't need to pause the * torrent or the session, since the torrent will do no more writing to * its files. If you save resume data for torrents when they are * paused, you can accelerate the shutdown process by not saving resume * data again for paused torrents. Completed torrents should have their * resume data saved when they complete and on exit, since their * statistics might be updated. *

* In full allocation mode the reume data is never invalidated by * subsequent writes to the files, since pieces won't move around. This * means that you don't need to pause before writing resume data in full * or sparse mode. If you don't, however, any data written to disk after * you saved resume data and before the session closed is lost. *

* It also means that if the resume data is out dated, libtorrent will * not re-check the files, but assume that it is fairly recent. The * assumption is that it's better to loose a little bit than to re-check * the entire file. *

* It is still a good idea to save resume data periodically during * download as well as when closing down. *

* Example code to pause and save resume data for all torrents and wait * for the alerts: *

* .. code:: c++ *

     * {@code
     * extern int outstanding_resume_data; // global counter of outstanding resume data
     * std::vector handles = ses.get_torrents();
     * ses.pause();
     * for (std::vector::iterator i = handles.begin();
     * i != handles.end(); ++i)
     * {
     * torrent_handle& h = *i;
     * if (!h.is_valid()) continue;
     * torrent_status s = h.status();
     * if (!s.has_metadata) continue;
     * if (!s.need_save_resume_data()) continue;
     *
     * h.save_resume_data();
     * ++outstanding_resume_data;
     * }
     *
     * while (outstanding_resume_data > 0)
     * {
     * alert const* a = ses.wait_for_alert(seconds(10));
     *
     * // if we don't get an alert within 10 seconds, abort
     * if (a == 0) break;
     *
     * std::auto_ptr holder = ses.pop_alert();
     *
     * if (alert_cast(a))
     * {
     * process_alert(a);
     * --outstanding_resume_data;
     * continue;
     * }
     *
     * save_resume_data_alert const* rd = alert_cast(a);
     * if (rd == 0)
     * {
     * process_alert(a);
     * continue;
     * }
     *
     * torrent_handle h = rd->handle;
     * torrent_status st = h.status(torrent_handle::query_save_path | torrent_handle::query_name);
     * std::ofstream out((st.save_path
     * + "/" + st.name + ".fastresume").c_str()
     * , std::ios_base::binary);
     * out.unsetf(std::ios_base::skipws);
     * bencode(std::ostream_iterator(out), *rd->resume_data);
     * --outstanding_resume_data;
     * }
     * }
     * 
* .. note:: * Note how ``outstanding_resume_data`` is a global counter in this * example. This is deliberate, otherwise there is a race condition for * torrents that was just asked to save their resume data, they posted * the alert, but it has not been received yet. Those torrents would * report that they don't need to save resume data again, and skipped by * the initial loop, and thwart the counter otherwise. */ public void saveResumeData(resume_data_flags_t flags) { h.save_resume_data(flags); } /** * Similar to calling {@link #saveResumeData(resume_data_flags_t)} with * empty flags. */ public void saveResumeData() { h.save_resume_data(); } /** * Returns true if this handle refers to a valid torrent and false if it * hasn't been initialized or if the torrent it refers to has been * aborted. Note that a handle may become invalid after it has been added * to the session. Usually this is because the storage for the torrent is * somehow invalid or if the filenames are not allowed (and hence cannot * be opened/created) on your filesystem. If such an error occurs, a * file_error_alert is generated and all handles that refers to that * torrent will become invalid. */ public boolean isValid() { return h.is_valid(); } /** * Generates a magnet URI from the specified torrent. If the torrent * handle is invalid, null is returned. */ public String makeMagnetUri() { return h.is_valid() ? libtorrent.make_magnet_uri(h) : null; } /** * Will limit the upload bandwidth used by this * particular torrent to the limit you set. It is given as the number of * bytes per second the torrent is allowed to upload. */ public int getUploadLimit() { return h.upload_limit(); } /** * Will limit the upload bandwidth used by this * particular torrent to the limit you set. It is given as the number of * bytes per second the torrent is allowed to upload. */ public void setUploadLimit(int limit) { h.set_upload_limit(limit); } // ``set_upload_limit`` will limit the upload bandwidth used by this // particular torrent to the limit you set. It is given as the number of // bytes per second the torrent is allowed to upload. // ``set_download_limit`` works the same way but for download bandwidth // instead of upload bandwidth. Note that setting a higher limit on a // torrent then the global limit // (``session_settings::upload_rate_limit``) will not override the global // rate limit. The torrent can never upload more than the global rate // limit. // // ``upload_limit`` and ``download_limit`` will return the current limit // setting, for upload and download, respectively. public int getDownloadLimit() { return h.download_limit(); } // ``set_upload_limit`` will limit the upload bandwidth used by this // particular torrent to the limit you set. It is given as the number of // bytes per second the torrent is allowed to upload. // ``set_download_limit`` works the same way but for download bandwidth // instead of upload bandwidth. Note that setting a higher limit on a // torrent then the global limit // (``session_settings::upload_rate_limit``) will not override the global // rate limit. The torrent can never upload more than the global rate // limit. // // ``upload_limit`` and ``download_limit`` will return the current limit // setting, for upload and download, respectively. public void setDownloadLimit(int limit) { h.set_download_limit(limit); } /** * This method puts the torrent back in a state where it assumes to * have no resume data. All peers will be disconnected and the torrent * will stop announcing to the tracker. The torrent will be added to the * checking queue, and will be checked (all the files will be read and * compared to the piece hashes). Once the check is complete, the torrent * will start connecting to peers again, as normal. */ public void forceRecheck() { h.force_recheck(); } /** * By default, force-reannounce will still honor the min-interval * published by the tracker. If this flag is set, it will be ignored * and the tracker is announced immediately. */ public static final reannounce_flags_t IGNORE_MIN_INTERVAL = torrent_handle.ignore_min_interval; // ``force_reannounce()`` will force this torrent to do another tracker // request, to receive new peers. The ``seconds`` argument specifies how // many seconds from now to issue the tracker announces. // // If the tracker's ``min_interval`` has not passed since the last // announce, the forced announce will be scheduled to happen immediately // as the ``min_interval`` expires. This is to honor trackers minimum // re-announce interval settings. // // The ``tracker_index`` argument specifies which tracker to re-announce. // If set to -1 (which is the default), all trackers are re-announce. // public void forceReannounce(int seconds, int tracker_index, reannounce_flags_t flags) { h.force_reannounce(seconds, tracker_index, flags); } // ``force_reannounce()`` will force this torrent to do another tracker // request, to receive new peers. The ``seconds`` argument specifies how // many seconds from now to issue the tracker announces. // // If the tracker's ``min_interval`` has not passed since the last // announce, the forced announce will be scheduled to happen immediately // as the ``min_interval`` expires. This is to honor trackers minimum // re-announce interval settings. // // The ``tracker_index`` argument specifies which tracker to re-announce. // If set to -1 (which is the default), all trackers are re-announce. // public void forceReannounce(int seconds, int tracker_index) { h.force_reannounce(seconds, tracker_index); } // ``force_reannounce()`` will force this torrent to do another tracker // request, to receive new peers. The ``seconds`` argument specifies how // many seconds from now to issue the tracker announces. // // If the tracker's ``min_interval`` has not passed since the last // announce, the forced announce will be scheduled to happen immediately // as the ``min_interval`` expires. This is to honor trackers minimum // re-announce interval settings. // // The ``url`` argument specifies which tracker to re-announce. // public void forceReannounce(int seconds, String url, reannounce_flags_t flags) { h.force_reannounce(seconds, url, flags); } // ``force_reannounce()`` will force this torrent to do another tracker // request, to receive new peers. The ``seconds`` argument specifies how // many seconds from now to issue the tracker announces. // // If the tracker's ``min_interval`` has not passed since the last // announce, the forced announce will be scheduled to happen immediately // as the ``min_interval`` expires. This is to honor trackers minimum // re-announce interval settings. // // The ``url`` argument specifies which tracker to re-announce. // public void forceReannounce(int seconds, String url) { h.force_reannounce(seconds, url); } // ``force_reannounce()`` will force this torrent to do another tracker // request, to receive new peers. The ``seconds`` argument specifies how // many seconds from now to issue the tracker announces. // // If the tracker's ``min_interval`` has not passed since the last // announce, the forced announce will be scheduled to happen immediately // as the ``min_interval`` expires. This is to honor trackers minimum // re-announce interval settings. // // The ``tracker_index`` argument specifies which tracker to re-announce. // If set to -1 (which is the default), all trackers are re-announce. // public void forceReannounce(int seconds) { h.force_reannounce(seconds); } /** * Force this torrent to do another tracker * request, to receive new peers. The ``seconds`` argument specifies how * many seconds from now to issue the tracker announces. *

* If the tracker's ``min_interval`` has not passed since the last * announce, the forced announce will be scheduled to happen immediately * as the ``min_interval`` expires. This is to honor trackers minimum * re-announce interval settings. *

* The ``tracker_index`` argument specifies which tracker to re-announce. * If set to -1 (which is the default), all trackers are re-announce. */ public void forceReannounce() { h.force_reannounce(); } /** * Announce the torrent to the DHT immediately. */ public void forceDHTAnnounce() { h.force_dht_announce(); } /** * Announce the torrent on LSD immediately. */ public void forceLSDAnnounce() { h.force_lsd_announce(); } // ``scrape_tracker()`` will send a scrape request to a tracker. By // default (``idx`` = -1) it will scrape the last working tracker. If // ``idx`` is >= 0, the tracker with the specified index will scraped. // // A scrape request queries the tracker for statistics such as total // number of incomplete peers, complete peers, number of downloads etc. // // This request will specifically update the ``num_complete`` and // ``num_incomplete`` fields in the torrent_status struct once it // completes. When it completes, it will generate a scrape_reply_alert. // If it fails, it will generate a scrape_failed_alert. public void scrapeTracker(int idx) { h.scrape_tracker(idx); } // ``scrape_tracker()`` will send a scrape request to a tracker. By // default (``idx`` = -1) it will scrape the last working tracker. If // ``idx`` is >= 0, the tracker with the specified index will scraped. // // A scrape request queries the tracker for statistics such as total // number of incomplete peers, complete peers, number of downloads etc. // // This request will specifically update the ``num_complete`` and // ``num_incomplete`` fields in the torrent_status struct once it // completes. When it completes, it will generate a scrape_reply_alert. // If it fails, it will generate a scrape_failed_alert. public void scrapeTracker(String url) { h.scrape_tracker(url); } /** * Will return a sorted list with the trackers of this torrent. *

* The announce entry contains both a string {@code url} which specify the * announce url for the tracker as well as an int {@code tier}, which * specifies the order in which this tracker is tried. * * @return the list of trackers */ public List trackers() { if (!h.is_valid()) { return Collections.emptyList(); } return trackers(h.trackers()); } /** * Will send a scrape request to the tracker. A * scrape request queries the tracker for statistics such as total number * of incomplete peers, complete peers, number of downloads etc. *

* This request will specifically update the ``num_complete`` and * ``num_incomplete`` fields in the torrent_status struct once it * completes. When it completes, it will generate a scrape_reply_alert. * If it fails, it will generate a scrape_failed_alert. */ public void scrapeTracker() { h.scrape_tracker(); } /** * If you want libtorrent to use another list of trackers for this torrent, * you can use {@link #replaceTrackers(List)} which takes a list of the same * form as the one returned from {@link #trackers()} and will replace it. * If you want an immediate effect, you have to call {@link #forceReannounce()}. *

* The updated set of trackers will be saved in the resume data, and when * a torrent is started with resume data, the trackers from the resume * data will replace the original ones. * * @param trackers the list of trackers * @see AnnounceEntry */ public void replaceTrackers(List trackers) { announce_entry_vector v = new announce_entry_vector(); for (AnnounceEntry t : trackers) { v.add(t.swig()); } h.replace_trackers(v); } /** * This method will look if the specified tracker is already in the * set. If it is, it doesn't do anything. If it's not in the current set * of trackers, it will insert it in the tier specified in the * {@link AnnounceEntry}. *

* The updated set of trackers will be saved in the resume data, and when * a torrent is started with resume data, the trackers from the resume * data will replace the original ones. */ public void addTracker(AnnounceEntry tracker) { h.add_tracker(tracker.swig()); } /** * Adds another url to the torrent's list of url * seeds. If the given url already exists in that list, the call has no * effect. The torrent will connect to the server and try to download * pieces from it, unless it's paused, queued, checking or seeding. */ public void addUrlSeed(String url) { h.add_url_seed(url); } /** * Removes the given url if it exists already. */ public void removeUrlSeed(String url) { h.remove_url_seed(url); } /** * Return a set of the url seeds currently in this * torrent. This list is based on BEP 19. * * @return the url seed list */ public List urlSeeds() { return Vectors.string_vector2list(h.get_url_seeds()); } /** * Returns an array with the availability for each piece in this torrent. * libtorrent does not keep track of availability for seeds, so if the * torrent is seeding the availability for all pieces is reported as 0. *

* The piece availability is the number of peers that we are connected * that has advertised having a particular piece. This is the information * that libtorrent uses in order to prefer picking rare pieces. * * @return the array with piece availability */ public int[] pieceAvailability() { int_vector v = new int_vector(); h.piece_availability(v); return Vectors.int_vector2ints(v); } // These functions are used to set and get the priority of individual // pieces. By default all pieces have priority 1. That means that the // random rarest first algorithm is effectively active for all pieces. // You may however change the priority of individual pieces. There are 8 // different priority levels: // // 0. piece is not downloaded at all // 1. normal priority. Download order is dependent on availability // 2. higher than normal priority. Pieces are preferred over pieces with // the same availability, but not over pieces with lower availability // 3. pieces are as likely to be picked as partial pieces. // 4. pieces are preferred over partial pieces, but not over pieces with // lower availability // 5. *currently the same as 4* // 6. piece is as likely to be picked as any piece with availability 1 // 7. maximum priority, availability is disregarded, the piece is // preferred over any other piece with lower priority // // The exact definitions of these priorities are implementation details, // and subject to change. The interface guarantees that higher number // means higher priority, and that 0 means do not download. // // ``piece_priority`` sets or gets the priority for an individual piece, // specified by ``index``. // // ``prioritize_pieces`` takes a vector of integers, one integer per // piece in the torrent. All the piece priorities will be updated with // the priorities in the vector. // // ``piece_priorities`` returns a vector with one element for each piece // in the torrent. Each element is the current priority of that piece. public void piecePriority(int index, Priority priority) { h.piece_priority_ex(index, priority.swig()); } public Priority piecePriority(int index) { return Priority.fromSwig(h.piece_priority_ex(index)); } public void prioritizePieces(Priority[] priorities) { h.prioritize_pieces_ex(Priority.array2vector(priorities)); } public Priority[] piecePriorities() { byte_vector v = h.get_piece_priorities_ex(); return Priority.vector2array(v); } /** * index must be in the range [0, number_of_files). *

* The priority values are the same as for piece_priority(). *

* Whenever a file priority is changed, all other piece priorities are * reset to match the file priorities. In order to maintain sepcial * priorities for particular pieces, piece_priority() has to be called * again for those pieces. *

* You cannot set the file priorities on a torrent that does not yet have * metadata or a torrent that is a seed. ``file_priority(int, int)`` and * prioritize_files() are both no-ops for such torrents. * * @param index * @param priority */ public void filePriority(int index, Priority priority) { h.file_priority_ex(index, priority.swig()); } /** * index must be in the range [0, number_of_files). *

* queries or sets the priority of file index. * * @param index * */ public Priority filePriority(int index) { return Priority.fromSwig(h.file_priority_ex(index)); } /** * Takes a vector that has at as many elements as * there are files in the torrent. Each entry is the priority of that * file. The function sets the priorities of all the pieces in the * torrent based on the vector. * * @param priorities the array of priorities */ public void prioritizeFiles(Priority[] priorities) { h.prioritize_files_ex(Priority.array2vector(priorities)); } /** * Returns a vector with the priorities of all files. * * @return the array of priorities. */ public Priority[] filePriorities() { byte_vector v = h.get_file_priorities_ex(); return Priority.vector2array(v); } /** * This function sets or resets the deadline associated with a specific * piece index (``index``). libtorrent will attempt to download this * entire piece before the deadline expires. This is not necessarily * possible, but pieces with a more recent deadline will always be * prioritized over pieces with a deadline further ahead in time. The * deadline (and flags) of a piece can be changed by calling this * function again. *

* If the piece is already downloaded when this call is made, nothing * happens, unless the alert_when_available flag is set, in which case it * will do the same thing as calling read_piece() for ``index``. * * @param index * @param deadline */ public void setPieceDeadline(int index, int deadline) { h.set_piece_deadline(index, deadline); } /** * */ public static final deadline_flags_t ALERT_WHEN_AVAILABLE = torrent_handle.alert_when_available; /** * This function sets or resets the deadline associated with a specific * piece index (``index``). libtorrent will attempt to download this * entire piece before the deadline expires. This is not necessarily * possible, but pieces with a more recent deadline will always be * prioritized over pieces with a deadline further ahead in time. The * deadline (and flags) of a piece can be changed by calling this * function again. *

* The ``flags`` parameter can be used to ask libtorrent to send an alert * once the piece has been downloaded, by passing alert_when_available. * When set, the read_piece_alert alert will be delivered, with the piece * data, when it's downloaded. *

* If the piece is already downloaded when this call is made, nothing * happens, unless the alert_when_available flag is set, in which case it * will do the same thing as calling read_piece() for ``index``. * * @param index * @param deadline * @param flags */ public void setPieceDeadline(int index, int deadline, deadline_flags_t flags) { h.set_piece_deadline(index, deadline, flags); } /** * Removes the deadline from the piece. If it * hasn't already been downloaded, it will no longer be considered a * priority. * * @param index */ public void resetPieceDeadline(int index) { h.reset_piece_deadline(index); } /** * Removes deadlines on all pieces in the torrent. * As if {@link #resetPieceDeadline(int)} was called on all pieces. */ public void clearPieceDeadlines() { h.clear_piece_deadlines(); } /** * Only calculate file progress at piece granularity. This makes * the `fileProgress()` call cheaper and also only takes bytes that * have passed the hash check into account, so progress cannot * regress in this mode. */ public static final file_progress_flags_t PIECE_GRANULARITY = torrent_handle.piece_granularity; /** * This function fills in the supplied vector with the number of * bytes downloaded of each file in this torrent. The progress values are * ordered the same as the files in the torrent_info. This operation is * not very cheap. Its complexity is *O(n + mj)*. Where *n* is the number * of files, *m* is the number of downloading pieces and *j* is the * number of blocks in a piece. *

* The ``flags`` parameter can be used to specify the granularity of the * file progress. If left at the default value of 0, the progress will be * as accurate as possible, but also more expensive to calculate. If * ``torrent_handle::piece_granularity`` is specified, the progress will * be specified in piece granularity. i.e. only pieces that have been * fully downloaded and passed the hash check count. When specifying * piece granularity, the operation is a lot cheaper, since libtorrent * already keeps track of this internally and no calculation is required. * * @return the file progress */ public long[] fileProgress(file_progress_flags_t flags) { int64_vector v = new int64_vector(); h.file_progress(v, flags); return Vectors.int64_vector2longs(v); } /** * This function fills in the supplied vector with the number of * bytes downloaded of each file in this torrent. The progress values are * ordered the same as the files in the torrent_info. This operation is * not very cheap. Its complexity is *O(n + mj)*. Where *n* is the number * of files, *m* is the number of downloading pieces and *j* is the * number of blocks in a piece. * * @return the file progress */ public long[] fileProgress() { int64_vector v = new int64_vector(); h.file_progress(v); return Vectors.int64_vector2longs(v); } /** * The path to the directory where this torrent's files are stored. * It's typically the path as was given to async_add_torrent() or * add_torrent() when this torrent was started. */ public String savePath() { torrent_status ts = h.status(torrent_handle.query_save_path); return ts.getSave_path(); } /** * The name of the torrent. Typically this is derived from the * .torrent file. In case the torrent was started without metadata, * and hasn't completely received it yet, it returns the name given * to it when added to the session. * * @return the name */ public String getName() { torrent_status ts = h.status(torrent_handle.query_name); return ts.getName(); } /** * Moves the file(s) that this torrent are currently seeding from or * downloading to. If the given {@code savePath} is not located on the same * drive as the original save path, the files will be copied to the new * drive and removed from their original location. This will block all * other disk IO, and other torrents download and upload rates may drop * while copying the file. *

* Since disk IO is performed in a separate thread, this operation is * also asynchronous. Once the operation completes, the * {@link StorageMovedAlert} is generated, * with the new path as the message. If the move fails for some reason, * {@link StorageMovedFailedAlert} * generated instead, containing the error message. *

* The {@code flags} argument determines the behavior of the copying/moving * of the files in the torrent. *

* Files that have been renamed to have absolute paths are not moved by * this function. Keep in mind that files that don't belong to the * torrent but are stored in the torrent's directory may be moved as * well. This goes for files that have been renamed to absolute paths * that still end up inside the save path. * * @param savePath the new save path * @param flags the move behavior flags */ public void moveStorage(String savePath, MoveFlags flags) { h.move_storage(savePath, flags.swig()); } /** * Sames as calling {@link #moveStorage(String, MoveFlags)} with empty flags. * * @param savePath the new path * @see #moveStorage(String, MoveFlags) */ public void moveStorage(String savePath) { h.move_storage(savePath); } /** * Renames the file with the given index asynchronously. The rename * operation is complete when either a {@link FileRenamedAlert} or * {@link FileRenameFailedAlert} is posted. * * @param index * @param newName */ public void renameFile(int index, String newName) { h.rename_file(index, newName); } /** * Returns true if the torrent is in the session. It returns true before * session::remove_torrent() is called, and false afterward. *

* Note that this is a blocking function, unlike {@link #isValid()} * which returns immediately. * * @return true if the torrent is in the session */ public boolean inSession() { return h.in_session(); } @Override public boolean equals(Object obj) { if (!(obj instanceof TorrentHandle)) { return false; } return h.eq(((TorrentHandle) obj).h); } @Override public int hashCode() { return Long.hashCode(h.id()); } // helper function private static ArrayList trackers(announce_entry_vector v) { int size = v.size(); ArrayList l = new ArrayList<>(size); for (int i = 0; i < size; i++) { l.add(new AnnounceEntry(v.get(i))); } return l; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy