Bt is a modern Java 8 BitTorrent library. It offers good performance, reliability and is highly customizable.
© 2016-2021
Andrei Tomashpolskiy
Declare the following dependencies in your project’s pom.xml:
<dependency>
<groupId>com.github.atomashpolskiy</groupId>
<artifactId>bt-core</artifactId>
<version>${bt-version}</version>
</dependency>
<!-- for the sake of keeping the core with minimum number of 3-rd party
dependencies HTTP tracker support is shipped as a separate module;
you may omit this dependency if only UDP trackers are going to be used -->
<dependency>
<groupId>com.github.atomashpolskiy</groupId>
<artifactId>bt-http-tracker-client</artifactId>
<version>${bt-version}</version>
</dependency>
Bt CLI client is a very simple program for downloading/seeding a single torrent. It illustrates the most basic use case of Bt library.
See usage notes and explore the CliClient class for an example of assembling a basic Bt client.
Each Bt client is split into two parts:
Main idea is that there is a number of shared services and resources, that can be re-used by multiple torrent sessions. These include:
Hence, there are two ways to create a Bt client:
1) Client with a private runtime
Storage storage = new FileSystemStorage(/* target directory */);
BtClient client = Bt.client().storage(storage).torrent(/* torrent source */).build();
client.startAsync().join();
2) Client, attached to a shared runtime
Storage storage = new FileSystemStorage(/* target directory */);
BtRuntime sharedRuntime = BtRuntime.defaultRuntime();
URL url1 = /* torrent file URL #1 */,
url2 = /* torrent file URL #2 */;
BtClient client1 = Bt.client(sharedRuntime).storage(storage).torrent(/* torrent source #1 */).build();
BtClient client2 = Bt.client(sharedRuntime).storage(storage).torrent(/* torrent source #2 */).build();
// wait until both clients have finished
CompletableFuture.allOf(client1.startAsync(), client2.startAsync()).join();
Bt is built around Google Guice DI container and follows the canonical modular approach:
Core Bt modules are:
By default only UDP trackers are supported by the core library. HTTP tracker integration is shipped as a standalone module in a separate Maven library:
The reason for not including HTTP tracker support in the core is that it depends on Apache HTTP Components library. Thus, if you plan on using HTTP tracker, include the following dependency in pom.xml:
<dependency>
<groupId>com.github.atomashpolskiy</groupId>
<artifactId>bt-http-tracker-client</artifactId>
<version>${bt-version}</version>
</dependency>
There are two ways of contributing an extra module into runtime:
bt.runtime.BtRuntimeBuilder#autoLoadModules()
method when building a runtime; in this case each loaded module will use its’ default configurationBtRuntimeBuilder builder = BtRuntimeBuilder.builder();
// ... setup as needed
BtRuntime runtime = builder.autoLoadModules().build();
bt.runtime.BtRuntimeBuilder#module()
method:PeerExchangeConfig config = new PeerExchangeConfig() {
@Override
public int getMinEventsPerMessage() {
// don't send PEX message if there are less than 50 added/dropped peer events
return 50;
}
};
PeerExchangeModule customModule = new PeerExchangeModule(config);
BtRuntime runtime = BtRuntime.builder().module(customModule).build();
Peer exchange service is also turned off by default. Enable auto-loading of modules or manually contribute bt.peerexchange.PeerExchangeModule into runtime to enable peer sharing.
When it comes to configuration, Bt runtime provides reasonable defaults for most cases. However, you might still need to tweak some parameters, e.g. which network link to use, on which port to listen for incoming peer connections, etc. For such cases the runtime builder provides a handy method:
Config config = new Config();
config.setAcceptorAddress(/* network address */);
config.setAcceptorPort(/* network port */);
// tweak other parameters
BtRuntime runtime = BtRuntime.builder(config).build();
See full list of configuration parameters on Config page in the JavaDoc.
There are two methods for starting the torrent session in BtClient:
The no-argument method will just begin the torrent processing. The overloaded version will also launch a scheduled future, that will be calling the provided listener with current session state at a given interval. Session state contains some useful information, e.g. a list of connected peers, download progress and such, so it might be a good idea to inspect it from time to time. E.g. the CLI client uses session state to determine whether it should stop:
client.startAsync(state -> {
if (!options.shouldSeedAfterDownloaded() && state.getPiecesRemaining() == 0) {
client.stop();
}
}, 1000).join();
Both methods return a CompletableFuture<?>, which provides the most natural way for co-ordinating multiple torrent sessions. Run in parallel? Sequentially? Custom processing chain? All is possible via standard Java API.
Stopping the client is as easy as calling BtClient#stop().
By default the runtime is configured to startup and shutdown synchronously with the client.
This is not always the desired behaviour. E.g. when implementing a “pause” button, the client should be stopped and then started again after a user event. In such case creating and starting a new runtime each time the user clicks “resume” would be inefficient. That’s why there is a dedicated method for turning this feature off:
Manual runtime shutdown is performed by calling BtRuntime#shutdown(). Behaviour is completely identical to the automatic mode: stopping all clients (if any of them are still executing), performing registered shutdown hooks, releasing resources, done.
Everything stated above also applies when the runtime is shared among several clients (multiple simultaneous torrent sessions). With the only difference that this time runtime fires up when any of the clients is started and shutdowns when all of the clients are finished (unless automatic shutdown is disabled like in the single client case).