mirror of
https://framagit.org/tom79/fedilab-tube
synced 2025-04-13 01:52:01 +02:00
lib
This commit is contained in:
parent
2cdabbcb70
commit
70e8133350
23
frostwire-jlibtorrent/.gitignore
vendored
Normal file
23
frostwire-jlibtorrent/.gitignore
vendored
Normal file
@ -0,0 +1,23 @@
|
||||
*~
|
||||
.DS_Store
|
||||
*.ipr
|
||||
*.iws
|
||||
.idea
|
||||
.gradle
|
||||
/build
|
||||
/out
|
||||
/android/build
|
||||
/android/src/main/jniLibs
|
||||
/java/out/
|
||||
*.o
|
||||
/jlibtorrent.xcodeproj/xcuserdata/
|
||||
/obj
|
||||
frostwire-jlibtorrent.i*
|
||||
/test-libtorrent
|
||||
/swig/bin
|
||||
/swig/build
|
||||
/libjlibtorrent*.dylib
|
||||
/libjlibtorrent*.so
|
||||
/jlibtorrent*.dll
|
||||
/node/jlibtorrent.node
|
||||
/dht_shell.dat
|
259
frostwire-jlibtorrent/.travis.yml
Normal file
259
frostwire-jlibtorrent/.travis.yml
Normal file
@ -0,0 +1,259 @@
|
||||
language: cpp
|
||||
dist: eoan
|
||||
|
||||
matrix:
|
||||
include:
|
||||
- env: os_build=android os_arch=arm android_api=19
|
||||
- env: os_build=android os_arch=arm64 android_api=21
|
||||
- env: os_build=android os_arch=x86 android_api=19
|
||||
- env: os_build=android os_arch=x86_64 android_api=21
|
||||
- env: os_build=linux os_arch=x86
|
||||
- env: os_build=linux os_arch=x86_64
|
||||
- env: os_build=windows os_arch=x86
|
||||
- env: os_build=windows os_arch=x86_64
|
||||
- os: osx
|
||||
env: os_build=macosx os_arch=x86_64
|
||||
osx_image: xcode11.2
|
||||
|
||||
branches:
|
||||
only:
|
||||
- master
|
||||
|
||||
before_install:
|
||||
- wget -nv -O boost.zip https://dl.bintray.com/boostorg/release/1.73.0/source/boost_1_73_0.zip
|
||||
- unzip -qq boost.zip
|
||||
- cd boost_1_73_0
|
||||
- ls -lth
|
||||
- ./bootstrap.sh
|
||||
- ./b2
|
||||
- cd ..
|
||||
- export BOOST_ROOT=$PWD/boost_1_73_0
|
||||
- export BOOST_BUILD_PATH=$BOOST_ROOT
|
||||
|
||||
# openssl: download
|
||||
- wget -nv -O openssl.tar.gz https://www.openssl.org/source/openssl-1.1.1i.tar.gz
|
||||
- tar xzf openssl.tar.gz
|
||||
- export OPENSSL_SOURCE=$PWD/openssl-1.1.1i
|
||||
# fix source code
|
||||
# avoid GDI dependency in windows, fix double return statement on threads_none.c
|
||||
- if [ $os_build == "windows" ]; then
|
||||
sed -i 's/if defined(_WIN32_WINNT) && _WIN32_WINNT>=0x0333/if 0/g' $OPENSSL_SOURCE/crypto/cryptlib.c;
|
||||
sed -i 's/MessageBox.*//g' $OPENSSL_SOURCE/crypto/cryptlib.c;
|
||||
sed -i 's/return return 0;/return 0;/g' $OPENSSL_SOURCE/crypto/threads_none.c;
|
||||
fi
|
||||
|
||||
# libtorrent: download and checkout revision
|
||||
- git clone https://github.com/arvidn/libtorrent
|
||||
- cd libtorrent
|
||||
- git checkout 77172672c8db2f6bcef17d867d9a81faae77ec1e
|
||||
- git submodule init
|
||||
- git submodule update
|
||||
- cd ..
|
||||
- export LIBTORRENT_ROOT=$PWD/libtorrent
|
||||
|
||||
# android ndk: download and create toolchain
|
||||
- if [ $os_build == "android" ]; then
|
||||
wget -nv -O android-ndk.zip https://dl.google.com/android/repository/android-ndk-r21d-linux-x86_64.zip;
|
||||
echo "Extracting NDK...wait";
|
||||
unzip -qq android-ndk.zip;
|
||||
export NDK=$PWD/android-ndk-r21d;
|
||||
$NDK/build/tools/make_standalone_toolchain.py --arch $os_arch --api $android_api --stl libc++ --install-dir android-toolchain;
|
||||
export ANDROID_TOOLCHAIN=$PWD/android-toolchain;
|
||||
fi
|
||||
|
||||
- if [[ $os_build == "linux" || $os_build == "windows" ]]; then
|
||||
sudo apt-get install -qq g++-7 g++-7-multilib;
|
||||
fi
|
||||
|
||||
- if [[ $os_build == "linux" && $os_arch == "x86" ]]; then
|
||||
sudo apt-get install -qq libc6-dev-i386;
|
||||
sudo apt-get install -qq lib32gcc-5-dev;
|
||||
sudo apt-get install -qq lib32stdc++-5-dev;
|
||||
sudo ln -s /usr/include/asm-generic /usr/include/asm;
|
||||
fi
|
||||
|
||||
# linux cross compilation tools for windows development
|
||||
# remove files related to libwinpthread dll
|
||||
- if [[ $os_build == "windows" && $os_arch == "x86" ]]; then
|
||||
sudo apt-get install -qq g++-mingw-w64-i686;
|
||||
fi
|
||||
|
||||
- if [[ $os_build == "windows" && $os_arch == "x86_64" ]]; then
|
||||
sudo apt-get install -qq g++-mingw-w64-x86-64;
|
||||
fi
|
||||
|
||||
# install gradle in macOS to run the unit tests
|
||||
- if [ $os_build == "macosx" ]; then
|
||||
brew update > /dev/null && brew install gradle;
|
||||
fi
|
||||
|
||||
# openssl
|
||||
- 'export OPENSSL_NO_OPTS="no-afalgeng no-async no-autoalginit no-autoerrinit
|
||||
no-capieng no-cms no-comp no-deprecated no-dgram no-dso no-dtls
|
||||
no-dynamic-engine no-egd no-engine no-err no-filenames no-gost no-hw
|
||||
no-makedepend no-multiblock no-nextprotoneg no-posix-io no-psk
|
||||
no-rdrand no-sctp no-shared no-sock no-srp no-srtp no-static-engine
|
||||
no-stdio no-threads no-ui-console no-zlib no-zlib-dynamic
|
||||
-fno-strict-aliasing -fvisibility=hidden -Os"'
|
||||
# android-arm
|
||||
- if [[ $os_build == "android" && $os_arch == "arm" ]]; then
|
||||
export CC=$ANDROID_TOOLCHAIN/bin/arm-linux-androideabi-clang;
|
||||
export run_openssl_configure="./Configure linux-armv4 ${OPENSSL_NO_OPTS} -march=armv7-a -mfpu=neon -fPIC --prefix=$OPENSSL_SOURCE/../openssl";
|
||||
fi
|
||||
# android-arm64
|
||||
- if [[ $os_build == "android" && $os_arch == "arm64" ]]; then
|
||||
export CC=$ANDROID_TOOLCHAIN/bin/aarch64-linux-android-clang;
|
||||
export run_openssl_configure="./Configure linux-aarch64 ${OPENSSL_NO_OPTS} -march=armv8-a+crypto -fPIC --prefix=$OPENSSL_SOURCE/../openssl";
|
||||
fi
|
||||
# android-x86
|
||||
- if [[ $os_build == "android" && $os_arch == "x86" ]]; then
|
||||
export CC=$ANDROID_TOOLCHAIN/bin/i686-linux-android-clang;
|
||||
export run_openssl_configure="./Configure linux-elf ${OPENSSL_NO_OPTS} -fPIC -mstackrealign --prefix=$OPENSSL_SOURCE/../openssl";
|
||||
fi
|
||||
# android-x86_64
|
||||
- if [[ $os_build == "android" && $os_arch == "x86_64" ]]; then
|
||||
export CC=$ANDROID_TOOLCHAIN/bin/x86_64-linux-android-clang;
|
||||
export run_openssl_configure="./Configure linux-x86_64 ${OPENSSL_NO_OPTS} -fPIC --prefix=$OPENSSL_SOURCE/../openssl";
|
||||
fi
|
||||
# linux-x86
|
||||
- if [[ $os_build == "linux" && $os_arch == "x86" ]]; then
|
||||
export CC=gcc-7;
|
||||
export run_openssl_configure="./Configure linux-elf ${OPENSSL_NO_OPTS} -fPIC -m32 --prefix=$OPENSSL_SOURCE/../openssl";
|
||||
fi
|
||||
# linux-x86_64
|
||||
- if [[ $os_build == "linux" && $os_arch == "x86_64" ]]; then
|
||||
export CC=gcc-7;
|
||||
export run_openssl_configure="./Configure linux-x86_64 ${OPENSSL_NO_OPTS} -fPIC --prefix=$OPENSSL_SOURCE/../openssl";
|
||||
fi
|
||||
# windows-x86
|
||||
- if [[ $os_build == "windows" && $os_arch == "x86" ]]; then
|
||||
export CC=i686-w64-mingw32-gcc-posix;
|
||||
export run_openssl_configure="./Configure mingw ${OPENSSL_NO_OPTS} --prefix=$OPENSSL_SOURCE/../openssl";
|
||||
fi
|
||||
# windows-x86_64
|
||||
- if [[ $os_build == "windows" && $os_arch == "x86_64" ]]; then
|
||||
export CC=x86_64-w64-mingw32-gcc-posix;
|
||||
export run_openssl_configure="./Configure mingw64 ${OPENSSL_NO_OPTS} --prefix=$OPENSSL_SOURCE/../openssl";
|
||||
fi
|
||||
# macosx
|
||||
- if [ $os_build == "macosx" ]; then
|
||||
export run_openssl_configure="./Configure darwin64-x86_64-cc ${OPENSSL_NO_OPTS} --prefix=$OPENSSL_SOURCE/../openssl";
|
||||
fi
|
||||
|
||||
# jlibtorrent
|
||||
# android-arm
|
||||
- if [[ $os_build == "android" && $os_arch == "arm" ]]; then
|
||||
export run_bjam="${BOOST_ROOT}/b2 --user-config=config/android-arm-config.jam variant=release toolset=clang-linux-arm target-os=android location=bin/release/android/armeabi-v7a";
|
||||
export run_objcopy="${ANDROID_TOOLCHAIN}/bin/arm-linux-androideabi-objcopy --only-keep-debug bin/release/android/armeabi-v7a/libjlibtorrent.so bin/release/android/armeabi-v7a/libjlibtorrent.so.debug";
|
||||
export run_strip="${ANDROID_TOOLCHAIN}/bin/arm-linux-androideabi-strip --strip-unneeded -x -g bin/release/android/armeabi-v7a/libjlibtorrent.so";
|
||||
export run_readelf="${ANDROID_TOOLCHAIN}/bin/arm-linux-androideabi-readelf -d bin/release/android/armeabi-v7a/libjlibtorrent.so";
|
||||
export PATH=$ANDROID_TOOLCHAIN/arm-linux-androideabi/bin:$PATH;
|
||||
sed -i 's/RANLIB = ranlib/RANLIB = "${ANDROID_TOOLCHAIN}\/bin\/arm-linux-androideabi-ranlib"/g' ${BOOST_ROOT}/tools/build/src/tools/gcc.jam;
|
||||
fi
|
||||
# android-arm64
|
||||
- if [[ $os_build == "android" && $os_arch == "arm64" ]]; then
|
||||
export run_bjam="${BOOST_ROOT}/b2 --user-config=config/android-arm64-config.jam variant=release toolset=clang-arm64 target-os=android location=bin/release/android/arm64-v8a";
|
||||
export run_objcopy="${ANDROID_TOOLCHAIN}/bin/aarch64-linux-android-objcopy --only-keep-debug bin/release/android/arm64-v8a/libjlibtorrent.so bin/release/android/arm64-v8a/libjlibtorrent.so.debug";
|
||||
export run_strip="${ANDROID_TOOLCHAIN}/bin/aarch64-linux-android-strip --strip-unneeded -x bin/release/android/arm64-v8a/libjlibtorrent.so";
|
||||
export run_readelf="${ANDROID_TOOLCHAIN}/bin/aarch64-linux-android-readelf -d bin/release/android/arm64-v8a/libjlibtorrent.so";
|
||||
export PATH=$ANDROID_TOOLCHAIN/aarch64-linux-android/bin:$PATH;
|
||||
sed -i 's/RANLIB = ranlib/RANLIB = "${ANDROID_TOOLCHAIN}\/bin\/aarch64-linux-android-ranlib"/g' ${BOOST_ROOT}/tools/build/src/tools/gcc.jam;
|
||||
fi
|
||||
# android-x86
|
||||
- if [[ $os_build == "android" && $os_arch == "x86" ]]; then
|
||||
export run_bjam="${BOOST_ROOT}/b2 --user-config=config/android-x86-config.jam variant=release toolset=clang-x86 target-os=android location=bin/release/android/x86";
|
||||
export run_objcopy="${ANDROID_TOOLCHAIN}/bin/i686-linux-android-objcopy --only-keep-debug bin/release/android/x86/libjlibtorrent.so bin/release/android/x86/libjlibtorrent.so.debug";
|
||||
export run_strip="${ANDROID_TOOLCHAIN}/bin/i686-linux-android-strip --strip-unneeded -x -g bin/release/android/x86/libjlibtorrent.so";
|
||||
export run_readelf="${ANDROID_TOOLCHAIN}/bin/i686-linux-android-readelf -d bin/release/android/x86/libjlibtorrent.so";
|
||||
export PATH=$ANDROID_TOOLCHAIN/i686-linux-android/bin:$PATH;
|
||||
sed -i 's/RANLIB = ranlib/RANLIB = "${ANDROID_TOOLCHAIN}\/bin\/i686-linux-android-ranlib"/g' ${BOOST_ROOT}/tools/build/src/tools/gcc.jam;
|
||||
fi
|
||||
# android-x86_64
|
||||
- if [[ $os_build == "android" && $os_arch == "x86_64" ]]; then
|
||||
export run_bjam="${BOOST_ROOT}/b2 --user-config=config/android-x86_64-config.jam variant=release toolset=clang-x86_64 target-os=android location=bin/release/android/x86_64";
|
||||
export run_objcopy="${ANDROID_TOOLCHAIN}/bin/x86_64-linux-android-objcopy --only-keep-debug bin/release/android/x86_64/libjlibtorrent.so bin/release/android/x86_64/libjlibtorrent.so.debug";
|
||||
export run_strip="${ANDROID_TOOLCHAIN}/bin/x86_64-linux-android-strip --strip-unneeded -x bin/release/android/x86_64/libjlibtorrent.so";
|
||||
export run_readelf="${ANDROID_TOOLCHAIN}/bin/x86_64-linux-android-readelf -d bin/release/android/x86_64/libjlibtorrent.so";
|
||||
export PATH=$ANDROID_TOOLCHAIN/x86_64-linux-android/bin:$PATH;
|
||||
sed -i 's/RANLIB = ranlib/RANLIB = "${ANDROID_TOOLCHAIN}\/bin\/x86_64-linux-android-ranlib"/g' ${BOOST_ROOT}/tools/build/src/tools/gcc.jam;
|
||||
fi
|
||||
# linux-x86
|
||||
- if [[ $os_build == "linux" && $os_arch == "x86" ]]; then
|
||||
export run_bjam="${BOOST_ROOT}/b2 --user-config=config/linux-x86-config.jam variant=release toolset=gcc-x86 target-os=linux location=bin/release/linux/x86";
|
||||
export run_objcopy="objcopy --only-keep-debug bin/release/linux/x86/libjlibtorrent.so bin/release/linux/x86/libjlibtorrent.so.debug";
|
||||
export run_strip="strip --strip-unneeded -x bin/release/linux/x86/libjlibtorrent.so";
|
||||
export run_readelf="readelf -d bin/release/linux/x86/libjlibtorrent.so";
|
||||
fi
|
||||
# linux-x86_64
|
||||
- if [[ $os_build == "linux" && $os_arch == "x86_64" ]]; then
|
||||
export run_bjam="${BOOST_ROOT}/b2 --user-config=config/linux-x86_64-config.jam variant=release toolset=gcc-x86_64 target-os=linux location=bin/release/linux/x86_64";
|
||||
export run_objcopy="objcopy --only-keep-debug bin/release/linux/x86_64/libjlibtorrent.so bin/release/linux/x86_64/libjlibtorrent.so.debug";
|
||||
export run_strip="strip --strip-unneeded -x bin/release/linux/x86_64/libjlibtorrent.so";
|
||||
export run_readelf="readelf -d bin/release/linux/x86_64/libjlibtorrent.so";
|
||||
fi
|
||||
# windows-x86
|
||||
- if [[ $os_build == "windows" && $os_arch == "x86" ]]; then
|
||||
sed -i 's/ JNICALL Java_com_frostwire/ JNICALL _Java_com_frostwire/g' swig/libtorrent_jni.cpp;
|
||||
export run_bjam="${BOOST_ROOT}/b2 --user-config=config/windows-x86-config.jam variant=release toolset=gcc-x86 target-os=windows location=bin/release/windows/x86";
|
||||
export run_strip="i686-w64-mingw32-strip --strip-unneeded -x bin/release/windows/x86/libjlibtorrent.dll";
|
||||
export run_readelf="eval objdump -p bin/release/windows/x86/jlibtorrent.dll | grep DLL";
|
||||
fi
|
||||
# windows-x86_64
|
||||
- if [[ $os_build == "windows" && $os_arch == "x86_64" ]]; then
|
||||
export run_bjam="${BOOST_ROOT}/b2 --user-config=config/windows-x86_64-config.jam variant=release toolset=gcc-x86_64 target-os=windows location=bin/release/windows/x86_64";
|
||||
export run_strip="x86_64-w64-mingw32-strip --strip-unneeded -x bin/release/windows/x86_64/libjlibtorrent.dll";
|
||||
export run_readelf="eval objdump -p bin/release/windows/x86_64/jlibtorrent.dll | grep DLL";
|
||||
fi
|
||||
# macosx
|
||||
- if [ $os_build == "macosx" ]; then
|
||||
export run_bjam="${BOOST_ROOT}/b2 --user-config=config/macosx-x86_64-config.jam variant=release toolset=darwin-x86_64 target-os=darwin location=bin/release/macosx/x86_64";
|
||||
export run_strip="strip -S -x bin/release/macosx/x86_64/libjlibtorrent.dylib";
|
||||
export run_readelf="otool -L bin/release/macosx/x86_64/libjlibtorrent.dylib";
|
||||
fi
|
||||
|
||||
script:
|
||||
|
||||
- cd $OPENSSL_SOURCE
|
||||
- $run_openssl_configure
|
||||
- echo "Compiling openssl...(remove &> /dev/null to see output)"
|
||||
- make #&> /dev/null
|
||||
- make install_sw &> /dev/null
|
||||
- cd ..
|
||||
- export OPENSSL_ROOT=$PWD/openssl
|
||||
|
||||
- cd swig
|
||||
- $run_bjam
|
||||
- $run_objcopy
|
||||
- $run_strip
|
||||
- if [[ $os_build == "windows" && $os_arch == "x86" ]]; then
|
||||
mv bin/release/windows/x86/libjlibtorrent.dll bin/release/windows/x86/jlibtorrent.dll;
|
||||
fi
|
||||
- if [[ $os_build == "windows" && $os_arch == "x86_64" ]]; then
|
||||
mv bin/release/windows/x86_64/libjlibtorrent.dll bin/release/windows/x86_64/jlibtorrent.dll;
|
||||
fi
|
||||
- if [ $os_build == "macosx" ]; then
|
||||
cd ..;
|
||||
cp swig/bin/release/macosx/x86_64/libjlibtorrent.dylib .;
|
||||
gradle test;
|
||||
cd swig;
|
||||
fi
|
||||
- $run_readelf
|
||||
- cd ..
|
||||
|
||||
before_deploy:
|
||||
- if [ -d swig/bin ]; then
|
||||
cd swig/bin;
|
||||
find . -type f | egrep -v '.*\.so$|.*\.dll$|.*\.dylib$|.*\.debug$' | xargs rm;
|
||||
find . -empty -type d | xargs rm -r;
|
||||
fi
|
||||
- cd ../..
|
||||
|
||||
deploy:
|
||||
provider: s3
|
||||
access_key_id: $S3_ACCESS_KEY
|
||||
secret_access_key: $S3_SECRET_KEY
|
||||
bucket: $S3_BUCKET
|
||||
skip_cleanup: true
|
||||
local_dir: swig/bin
|
||||
on:
|
||||
all_branches: true
|
4
frostwire-jlibtorrent/CHANGE_VERSION_CHECKLIST.txt
Normal file
4
frostwire-jlibtorrent/CHANGE_VERSION_CHECKLIST.txt
Normal file
@ -0,0 +1,4 @@
|
||||
bump version numberc in:
|
||||
- build.gradle 'version', then run swig/run-swig.sh, then build-xxx.sh and gradle build
|
||||
- changelog.txt
|
||||
|
1
frostwire-jlibtorrent/FUNDING.yml
Normal file
1
frostwire-jlibtorrent/FUNDING.yml
Normal file
@ -0,0 +1 @@
|
||||
github: gubatron
|
23
frostwire-jlibtorrent/LICENSE.md
Normal file
23
frostwire-jlibtorrent/LICENSE.md
Normal file
@ -0,0 +1,23 @@
|
||||
The MIT License
|
||||
===============
|
||||
|
||||
Copyright (C) 2016 FrostWire, LLC.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
"Software"), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject
|
||||
to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
|
||||
ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
|
||||
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
131
frostwire-jlibtorrent/README.md
Normal file
131
frostwire-jlibtorrent/README.md
Normal file
@ -0,0 +1,131 @@
|
||||
frostwire-jlibtorrent
|
||||
=====================
|
||||

|
||||
|
||||
A swig Java interface for libtorrent by the makers of FrostWire.
|
||||
|
||||
Develop libtorrent based apps with the joy of coding in Java.
|
||||
|
||||
[Discord Developer Chatroom](https://discord.com/channels/461752211802947585/461766946669461515)
|
||||
|
||||
Using
|
||||
========
|
||||
|
||||
[Download the latest release .jars](https://github.com/frostwire/frostwire-jlibtorrent/releases)
|
||||
|
||||
All platforms will need you to use at least 2 `.jar` files.
|
||||
|
||||
The `.jar` with the java classes -> `jlibtorrent-w.x.y.z.jar` and a secondary `.jar`s containing the JNI binary library for the particular OS and CPU architecture.
|
||||
|
||||
In the case of desktop operating systems, you might want to extract the shared library inside the jar (.dll, .so, .dylib) and place it in a folder specified by the `java.library.path`
|
||||
|
||||
The secondary jars are:
|
||||
- Windows: `jlibtorrent-windows-w.x.y.z.jar` (x86 and x86_64 .dlls)
|
||||
- Mac: `jlibtorrent-macosx-w.x.y.z.jar` (x86_64 .dylib)
|
||||
- Linux: `jlibtorrent-linux-w.x.y.z.jar` (x86 and x86_64 .so)
|
||||
|
||||
In the case of Android, make sure to put the following 3 jars in your project's `libs` folder (see [FrostWire for Android's](https://github.com/frostwire/frostwire/tree/master/android/libs) as an example):
|
||||
- `jlibtorrent-w.x.y.z.jar`
|
||||
- `jlibtorrent-android-arm-w.x.y.z.jar`
|
||||
- `jlibtorrent-android-x86-w.x.y.z.jar`
|
||||
|
||||
If you use ProGuard to obfuscate/minify make sure to add the following statement
|
||||
|
||||
`-keep class com.frostwire.jlibtorrent.swig.libtorrent_jni {*;}`
|
||||
|
||||
|
||||
Note that there are multiple version of jlibtorrent for different platforms: `jlibtorrent`, `jlibtorrent-windows`, `jlibtorrent-linux`, `jlibtorrent-macosx` and `jlibtorrent-android-<arch>`. These are all different artifacts.
|
||||
|
||||
For examples look at https://github.com/frostwire/frostwire-jlibtorrent/tree/master/src/test/java/com/frostwire/jlibtorrent/demo
|
||||
|
||||
Architectures supported:
|
||||
|
||||
- Android (armeabi-v7a, arm64-v8a, x86, x86_64)
|
||||
- Linux (x86, x86_64)
|
||||
- Windows (x86, x86_64)
|
||||
- Mac OS X (x86_64)
|
||||
|
||||
Building with Travis
|
||||
====================
|
||||
|
||||
You need:
|
||||
|
||||
- Setup a travis account at http://travis-ci.org and get familiar with
|
||||
the service if necessary.
|
||||
- Open an account with Amazon Web Services (AWS) and get familiar with
|
||||
S3 (for storage) and IAM (for users).
|
||||
- Some familiarity with `git` commands.
|
||||
|
||||
The process is:
|
||||
|
||||
- Create a user in amazon IAM, let's suppose it is `user1`. Download
|
||||
credentials for the keys.
|
||||
- Create a bucket in amazon S3, let's suppose it is `jlibtorrent1`.
|
||||
- Set the permission of the bucket according to your workflow, but at
|
||||
least the `user1` should have permission to put/upload to the bucket.
|
||||
See for example this bucket policy:
|
||||
```json
|
||||
{
|
||||
"Statement": [
|
||||
{
|
||||
"Effect": "Allow",
|
||||
"Principal": {"AWS":"arn:aws:iam::<user1's ARN here>:user/user1"},
|
||||
"Action": "s3:PutObject",
|
||||
"Resource": "arn:aws:s3:::jlibtorrent1/*"
|
||||
},
|
||||
{
|
||||
"Effect": "Allow",
|
||||
"Principal": "*",
|
||||
"Action": "s3:GetObject",
|
||||
"Resource": "arn:aws:s3:::jlibtorrent1/*"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
- Fork the project in github.
|
||||
- Go to travis and enable the repository.
|
||||
- Go to 'More options' > 'Settings' > 'Environment Variables' and set the
|
||||
`S3_ACCESS_KEY, S3_SECRET_KEY, S3_BUCKET` variables using the values in the
|
||||
credentials file for the user you created and the bucket name you created.
|
||||
- Clone locally your repo, let's assume to the `jlibtorrent` folder and
|
||||
checkout the stable branch:
|
||||
```bash
|
||||
$ git clone <your fork repo url> jlibtorrent
|
||||
$ cd jlibtorrent
|
||||
$ git checkout master
|
||||
```
|
||||
- Verify in your travis online if the build already started. The build
|
||||
could take about 40 minutes, be patient.
|
||||
- When finished, check your s3 bucket for the binaries.
|
||||
- To trigger a new build, just make a change or merge new changes from
|
||||
the stable branch, commit and push.
|
||||
|
||||
Building Locally (Mac and Linux)
|
||||
================================
|
||||
Building on Travis is something recommended only once you know you're done with your work as builds can take above 30 minutes to finish for all platforms and architectures.
|
||||
|
||||
When you're developing and debugging you need faster builds, and these can be performed locally with the help of build scripts in the `swig/` folder.
|
||||
|
||||
Thre's a build script for each operating system, for example if you're on macos you can use the `build-macos.sh`, running it without setting things up should tell you about certain environment variables you'll need to set up. To understand the build process we recommend you read your corresponding build script and [`build-utils.shinc`](https://github.com/frostwire/frostwire-jlibtorrent/blob/master/swig/build-utils.shinc)
|
||||
|
||||
The hacking and building process might require you to run the `run-swig.sh` script, we usually need to run this script if there are C++ api changes in libtorrent that require adjustments in `libtorrent.i` or `libtorrent.h`, this script will create automatic JNI wrappers in the outer source java folders. You should not run this script unless you know what you're doing.
|
||||
|
||||
Then you run the build script for your OS, get to the parent folder and invoke
|
||||
`gradle build`
|
||||
|
||||
The gradle build will look in the swig folder for the JNI shared libraries and it will automatically package the native holding `.jar` files, the final jars will be in the `build/libs` folder.
|
||||
|
||||
The windows build script is not finished, for now the windows build is done with travis builds.
|
||||
|
||||
Projects using jLibtorrent
|
||||
==========================
|
||||
- [FrostWire](http://www.frostwire.com) (both desktop and android editions)
|
||||
- [TorrentStream-Android](https://github.com/mianharisali/TorrentStream-Android)
|
||||
- [Simple-Torrent-Android](https://github.com/masterwok/simple-torrent-android)
|
||||
- [TorrentTunes-Client](https://github.com/dessalines/torrenttunes-client)
|
||||
- [LibreTorrent](https://github.com/proninyaroslav/libretorrent)
|
||||
|
||||
License
|
||||
========
|
||||
|
||||
This software is offered under the MIT License, available [here](License.md).
|
248
frostwire-jlibtorrent/build.gradle
Normal file
248
frostwire-jlibtorrent/build.gradle
Normal file
@ -0,0 +1,248 @@
|
||||
apply plugin: 'java'
|
||||
apply plugin: 'signing'
|
||||
apply plugin: 'maven'
|
||||
|
||||
group 'com.frostwire'
|
||||
archivesBaseName = 'jlibtorrent'
|
||||
// Just changing version here should be all that's necessary to bump the version on the library
|
||||
version '1.2.12.0'
|
||||
|
||||
sourceCompatibility = '1.8'
|
||||
targetCompatibility = '1.8'
|
||||
|
||||
if (!hasProperty('ossrhUsername')) {
|
||||
ext.ossrhUsername = ''
|
||||
}
|
||||
|
||||
if (!hasProperty('ossrhPassword')) {
|
||||
ext.ossrhPassword = ''
|
||||
}
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
testCompile 'junit:junit:4.12'
|
||||
}
|
||||
|
||||
tasks.withType(Test) {
|
||||
systemProperty "java.library.path", "."
|
||||
}
|
||||
|
||||
test {
|
||||
testLogging {
|
||||
events "passed", "skipped", "failed", "standard_out"
|
||||
}
|
||||
}
|
||||
|
||||
task sourcesJar(type: Jar) {
|
||||
classifier = 'sources'
|
||||
from sourceSets.main.allSource
|
||||
}
|
||||
|
||||
task javadoc2(type: Javadoc) {
|
||||
source = sourceSets.main.allJava
|
||||
}
|
||||
|
||||
task javadocJar(type: Jar, dependsOn: javadoc2) {
|
||||
classifier = 'javadoc'
|
||||
from javadoc2.destinationDir
|
||||
}
|
||||
|
||||
task nativeMacOSXJar(type: Zip) {
|
||||
destinationDir file("$buildDir/libs")
|
||||
baseName 'jlibtorrent-macosx'
|
||||
extension 'jar'
|
||||
from fileTree(dir: 'swig/bin/release/macosx', excludes: ['**/ed25519', '**/src'], include: '**/*libjlibtorrent.dylib')
|
||||
into 'lib/'
|
||||
rename(".dylib", "-${version}.dylib")
|
||||
}
|
||||
|
||||
task nativeWindowsJar(type: Zip) {
|
||||
destinationDir file("$buildDir/libs")
|
||||
baseName 'jlibtorrent-windows'
|
||||
extension 'jar'
|
||||
from fileTree(dir: 'swig/bin/release/windows', excludes: ['**/ed25519', '**/src'], include: '**/*jlibtorrent.dll')
|
||||
into 'lib/'
|
||||
rename(".dll", "-${version}.dll")
|
||||
}
|
||||
|
||||
task nativeLinuxJar(type: Zip) {
|
||||
destinationDir file("$buildDir/libs")
|
||||
baseName 'jlibtorrent-linux'
|
||||
extension 'jar'
|
||||
from fileTree(dir: 'swig/bin/release/linux', excludes: ['**/ed25519', '**/src'], include: '**/*libjlibtorrent.so')
|
||||
into 'lib/'
|
||||
rename(".so", "-${version}.so")
|
||||
}
|
||||
|
||||
task nativeAndroidArmJar(type: Zip) {
|
||||
destinationDir file("$buildDir/libs")
|
||||
baseName 'jlibtorrent-android-arm'
|
||||
extension 'jar'
|
||||
from fileTree(dir: 'swig/bin/release/android', include: 'armeabi-v7a/libjlibtorrent.so')
|
||||
into 'lib/'
|
||||
rename(".so", "-${version}.so")
|
||||
}
|
||||
|
||||
task nativeAndroidX86Jar(type: Zip) {
|
||||
destinationDir file("$buildDir/libs")
|
||||
baseName 'jlibtorrent-android-x86'
|
||||
extension 'jar'
|
||||
from fileTree(dir: 'swig/bin/release/android', include: 'x86/libjlibtorrent.so')
|
||||
into 'lib/'
|
||||
rename(".so", "-${version}.so")
|
||||
}
|
||||
|
||||
task nativeAndroidArm64Jar(type: Zip) {
|
||||
destinationDir file("$buildDir/libs")
|
||||
baseName 'jlibtorrent-android-arm64'
|
||||
extension 'jar'
|
||||
from fileTree(dir: 'swig/bin/release/android', include: 'arm64-v8a/libjlibtorrent.so')
|
||||
into 'lib/'
|
||||
rename(".so", "-${version}.so")
|
||||
}
|
||||
|
||||
task nativeAndroidX64Jar(type: Zip) {
|
||||
destinationDir file("$buildDir/libs")
|
||||
baseName 'jlibtorrent-android-x86_64'
|
||||
extension 'jar'
|
||||
from fileTree(dir: 'swig/bin/release/android', include: 'x86_64/libjlibtorrent.so')
|
||||
into 'lib/'
|
||||
rename(".so", "-${version}.so")
|
||||
}
|
||||
|
||||
artifacts {
|
||||
archives sourcesJar
|
||||
archives javadocJar
|
||||
archives nativeMacOSXJar
|
||||
archives nativeWindowsJar
|
||||
archives nativeLinuxJar
|
||||
archives nativeAndroidArmJar
|
||||
archives nativeAndroidX86Jar
|
||||
archives nativeAndroidArm64Jar
|
||||
archives nativeAndroidX64Jar
|
||||
}
|
||||
|
||||
signing {
|
||||
required { gradle.taskGraph.hasTask("uploadArchives") }
|
||||
sign configurations.archives
|
||||
}
|
||||
|
||||
uploadArchives {
|
||||
repositories {
|
||||
mavenDeployer {
|
||||
beforeDeployment { MavenDeployment deployment -> signing.signPom(deployment) }
|
||||
|
||||
addFilter('jlibtorrent') { artifact, file ->
|
||||
artifact.name == 'jlibtorrent'
|
||||
}
|
||||
addFilter('jlibtorrent-macosx') { artifact, file ->
|
||||
artifact.name == 'jlibtorrent-macosx'
|
||||
}
|
||||
addFilter('jlibtorrent-windows') { artifact, file ->
|
||||
artifact.name == 'jlibtorrent-windows'
|
||||
}
|
||||
addFilter('jlibtorrent-linux') { artifact, file ->
|
||||
artifact.name == 'jlibtorrent-linux'
|
||||
}
|
||||
addFilter('jlibtorrent-android-arm') { artifact, file ->
|
||||
artifact.name == 'jlibtorrent-android-arm'
|
||||
}
|
||||
addFilter('jlibtorrent-android-x86') { artifact, file ->
|
||||
artifact.name == 'jlibtorrent-android-x86'
|
||||
}
|
||||
addFilter('jlibtorrent-android-arm64') { artifact, file ->
|
||||
artifact.name == 'jlibtorrent-android-arm64'
|
||||
}
|
||||
addFilter('jlibtorrent-android-x86_64') { artifact, file ->
|
||||
artifact.name == 'jlibtorrent-android-x86_64'
|
||||
}
|
||||
|
||||
repository(url: "https://oss.sonatype.org/service/local/staging/deploy/maven2/") {
|
||||
authentication(userName: ossrhUsername, password: ossrhPassword)
|
||||
}
|
||||
|
||||
snapshotRepository(url: "https://oss.sonatype.org/content/repositories/snapshots/") {
|
||||
authentication(userName: ossrhUsername, password: ossrhPassword)
|
||||
}
|
||||
|
||||
pom('jlibtorrent').withXml {
|
||||
asNode().children().last() + pomData()
|
||||
}
|
||||
pom('jlibtorrent-macosx').withXml {
|
||||
asNode().children().last() + pomData()
|
||||
addDependency(asNode())
|
||||
|
||||
}
|
||||
pom('jlibtorrent-windows').withXml {
|
||||
asNode().children().last() + pomData()
|
||||
addDependency(asNode())
|
||||
}
|
||||
pom('jlibtorrent-linux').withXml {
|
||||
asNode().children().last() + pomData()
|
||||
addDependency(asNode())
|
||||
}
|
||||
pom('jlibtorrent-android-arm').withXml {
|
||||
asNode().children().last() + pomData()
|
||||
addDependency(asNode())
|
||||
}
|
||||
pom('jlibtorrent-android-x86').withXml {
|
||||
asNode().children().last() + pomData()
|
||||
addDependency(asNode())
|
||||
}
|
||||
pom('jlibtorrent-android-arm64').withXml {
|
||||
asNode().children().last() + pomData()
|
||||
addDependency(asNode())
|
||||
}
|
||||
pom('jlibtorrent-android-x86_64').withXml {
|
||||
asNode().children().last() + pomData()
|
||||
addDependency(asNode())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def pomData() {
|
||||
return {
|
||||
resolveStrategy = Closure.DELEGATE_FIRST
|
||||
name 'frostwire-jlibtorrent'
|
||||
description 'A swig Java interface for libtorrent by the makers of FrostWire.'
|
||||
url 'https://github.com/frostwire/frostwire-jlibtorrent'
|
||||
scm {
|
||||
connection 'scm:git:git://github.com/frostwire/frostwire-jlibtorrent.git'
|
||||
developerConnection 'scm:git:ssh:git@github.com/frostwire/frostwire-jlibtorrent.git'
|
||||
url 'https://github.com/frostwire/frostwire-jlibtorrent'
|
||||
}
|
||||
licenses {
|
||||
license {
|
||||
name 'The MIT License'
|
||||
url 'https://github.com/frostwire/frostwire-jlibtorrent/blob/master/LICENSE.md'
|
||||
}
|
||||
}
|
||||
developers {
|
||||
developer {
|
||||
id 'gubatron'
|
||||
name 'Angel Leon'
|
||||
email 'gubatron@gmail.com'
|
||||
}
|
||||
developer {
|
||||
id 'aldenml'
|
||||
name 'Alden Torres'
|
||||
email 'aldenml@gmail.com'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def addDependency(root) {
|
||||
def dependenciesNode = root.dependencies[0]
|
||||
if (!dependenciesNode) {
|
||||
dependenciesNode = root.appendNode('dependencies')
|
||||
}
|
||||
def depNode = dependenciesNode.appendNode('dependency')
|
||||
depNode.appendNode('groupId', group)
|
||||
depNode.appendNode('artifactId', archivesBaseName)
|
||||
depNode.appendNode('version', version)
|
||||
}
|
682
frostwire-jlibtorrent/changelog.txt
Normal file
682
frostwire-jlibtorrent/changelog.txt
Normal file
@ -0,0 +1,682 @@
|
||||
1.2.12.0
|
||||
* lt:fix loading of DHT node ID from previous session on startup
|
||||
* lt:use getrandom(), when available, and fall back to /dev/urandom
|
||||
* lt:fix uTP issue acking FIN packets
|
||||
* lt:validate HTTPS certificates by default (trackers and web seeds)
|
||||
* lt:load SSL certificates from windows system certificate store, to authenticate trackers
|
||||
* lt:introduce mitigation for Server Side Request Forgery in tracker and web seed URLs
|
||||
* lt:fix error handling for pool allocation failure
|
||||
|
||||
1.2.11.0
|
||||
* New TorrentHandle.inSession() [blocking method, do not use in main UI threads]
|
||||
* New ability for SessionManager to build a paused session
|
||||
* New SessionManager.start(SessionParams, session_flags_t)
|
||||
* New SessionHandle.PAUSED (session_flag_t) and corresponding unit tests
|
||||
* Removed TorrentStatus::State::ALLOCATING enum
|
||||
* Removed torrent_status.state_t.unused_enum_for_backwards_compatibility_allocating
|
||||
* libtorrent 1.2.11.0 update (471e772cb7038f1bf5f44c32a09eb42fbb80ee99)
|
||||
* lt: upgraded to openssl 1.1.1l
|
||||
* lt: fix issue with moving the session object
|
||||
* lt: deprecate torrent_status::allocating. This state is no longer used
|
||||
* lt: fix bug creating torrents with symbolic links
|
||||
* lt: remove special case to save metadata in resume data unconditionally when added throught magnet link
|
||||
* lt: fix bugs in mutable-torrent support (reusing identical files from different torrents)
|
||||
* lt: fix incorrectly inlined move-assignment of file_storage
|
||||
* lt: add session::paused flag, and the ability to construct a session in paused mode
|
||||
* lt: fix session-pause causing tracker announces to fail
|
||||
* lt: fix peer-exchange flags bug
|
||||
* lt: allow saving resume data before metadata has been downloaded (for magnet links)
|
||||
* lt: record blocks in the disk queue as downloaded in the resume data
|
||||
* lt: fix bug in set_piece_deadline() when set in a zero-priority piece
|
||||
* lt: fix issue in URL parser, causing issues with certain tracker URLs
|
||||
* lt: use a different error code than host-unreachable, when skipping tracker announces
|
||||
|
||||
1.2.10.0
|
||||
* libtorrent 1.2.10 update (70f1de3f7ec4012aaea420ff150ef0135d397706)
|
||||
* lt: improve stat_file() performance on Windows
|
||||
* lt: fix issue with loading invalid torrents with only 0-sized files
|
||||
* lt: fix to avoid large stack allocations
|
||||
* lt: add macro TORRENT_CXX11_ABI for clients building with C++14 against
|
||||
libtorrent build with C++11
|
||||
* lt: removed deprecated wstring overloads on non-windows systems
|
||||
* lt: drop dependency on Unicode's ConvertUTF code (which had a license
|
||||
incompatible with Debian)
|
||||
* lt: fix bugs exposed on big-endian systems
|
||||
* lt: fix detection of hard-links not being supported by filesystem
|
||||
* lt: fixed resume data regression for seeds with prio 0 files
|
||||
* binaries: compiler upgraded from g++-5 to g++-7
|
||||
|
||||
1.2.8.0
|
||||
* add router.utorrent.com to list of DHT bootstrap nodes
|
||||
* Android builds with new NDK r21d
|
||||
* lt: validate UTF-8 encoding of client version strings from peers
|
||||
* lt: don't time out tracker announces as eagerly while resolving hostnames
|
||||
* lt: fix NAT-PMP shutdown issue
|
||||
* lt: improve hostname lookup by merging identical lookups
|
||||
* lt: fix network route enumeration for large routing tables
|
||||
* lt: fixed issue where pop_alerts() could return old, invalid alerts
|
||||
* lt: fix issue when receiving have-all message before the metadata
|
||||
* lt: don't leave lingering part files handles open
|
||||
* lt: disallow calling add_piece() during checking
|
||||
* lt: fix incorrect filename truncation at multi-byte character
|
||||
* lt: always announce listen port 1 when using a proxy
|
||||
|
||||
1.2.7.0
|
||||
* libtorrent 1.2.7 update (ce0a85f783bec37484776a37fe3662279091ecc5)
|
||||
* upgraded to boost 1.73.0
|
||||
* upgraded to openssl 1.1.1g
|
||||
* lt: fix incorrect filename truncation at multi-byte character
|
||||
* lt: always announce listen port 1 when using a proxy
|
||||
* lt: add set_alert_fd in python binding, to supersede set_alert_notify
|
||||
* lt: fix bug in part files > 2 GiB
|
||||
* lt: add function to clear the peer list for a torrent
|
||||
* lt: fix resume data functions to save/restore more torrent flags
|
||||
* lt: limit number of concurrent HTTP announces
|
||||
* lt: fix queue position for force_rechecking a torrent that is not auto-managed
|
||||
* lt: improve rate-based choker documentation, and minor tweak
|
||||
* lt: undeprecate upnp_ignore_nonrouters (but refering to devices on our subnet)
|
||||
* lt: increase default tracker timeout
|
||||
* lt: retry failed socks5 server connections
|
||||
* lt: allow UPnP lease duration to be changed after device discovery
|
||||
* lt: fix IPv6 address change detection on Windows
|
||||
* lt: fix peer timeout logic
|
||||
* lt: simplify proxy handling. A proxy now overrides listen_interfaces
|
||||
* lt: fix issues when configured to use a non-default choking algorithm
|
||||
* lt: fix issue in reading resume data
|
||||
* lt: revert NXDOMAIN change from 1.2.4
|
||||
* lt: don't open any listen sockets if listen_interfaces is empty or misconfigured
|
||||
* lt: fix bug in auto disk cache size logic
|
||||
* lt: fix issue with outgoing_interfaces setting, where bind() would be called twice
|
||||
* lt: add build option to disable share-mode
|
||||
* lt: support validation of HTTPS trackers
|
||||
* lt: deprecate strict super seeding mode
|
||||
* lt: make UPnP port-mapping lease duration configurable
|
||||
* lt: deprecate the bittyrant choking algorithm
|
||||
* lt: add build option to disable streaming
|
||||
|
||||
1.2.6.0
|
||||
* There was no 1.2.6 release, we waited and jumped all the way to 1.2.7.0
|
||||
|
||||
1.2.5.0
|
||||
* libtorrent 1.2.5 update (0f337b9ce7a1b0fc87f48843933b1c5c4dd5a9ec)
|
||||
* New SettingsPack::dhtUploadRate(), SettingsPack::dhtUploadRate(int)
|
||||
* lt:announce port=1 instead of port=0, when there is no listen port
|
||||
* lt:fix LSD over IPv6
|
||||
* lt:support TCP_NOTSENT_LOWAT on Linux
|
||||
* lt:fix correct interface binding of local service discovery multicast
|
||||
* lt:fix issue with knowing which interfaces to announce to trackers and DHT
|
||||
* lt:undeprecate settings_pack::dht_upload_rate_limit
|
||||
|
||||
1.2.4.0
|
||||
* libtorrent 1.2.4 update (ad83b1c0eb293b63c69f7879ca6ba2381369f77f)
|
||||
* Java source compatibility upgraded from 1.7 to 1.8
|
||||
* lt:fix binding TCP and UDP sockets to the same port, when specifying port 0
|
||||
* lt:fix announce_to_all_trackers and announce_to_all_tiers behavior
|
||||
* lt:fix suggest_read_cache setting
|
||||
* lt:back-off tracker hostname looksups resulting in NXDOMAIN
|
||||
* lt:lower SOCKS5 UDP keepalive timeout
|
||||
* lt:fix external IP voting for multi-homed DHT nodes
|
||||
* lt:deprecate broadcast_lsd setting. Just use multicast
|
||||
* lt:deprecate upnp_ignore_nonrouters setting
|
||||
* lt:don't attempt sending event=stopped if event=start never succeeded
|
||||
* lt:make sure &key= stays consistent between different source IPs (as mandated by BEP7)
|
||||
* lt:fix binding sockets to outgoing interface
|
||||
* lt:add new socks5_alert to trouble shoot SOCKS5 proxies
|
||||
|
||||
1.2.3.0
|
||||
* libtorrent 1.2.3 update (b5bf6c3260bd726b0181671625c007be5ad49845)
|
||||
* using android NDK r20b
|
||||
* upgraded to boost 1.72.0
|
||||
* upgraded to openssl 1.1.1d
|
||||
* swig version 4.0.1 (from 3.0.12)
|
||||
* lt:fix erroneous event=completed tracker announce when checking files
|
||||
* lt:promote errors in parsing listen_interfaces to post listen_failed_alert
|
||||
* lt:fix bug in protocol encryption/obfuscation
|
||||
* lt:fix buffer overflow in SOCKS5 UDP logic
|
||||
* lt:fix issue of rapid calls to file_priority() clobbering each other
|
||||
* lt:clear tracker errors on success
|
||||
* lt:optimize setting with unlimited unchoke slots
|
||||
* lt:fixed restoring of trackers, comment, creation date and created-by in resume data
|
||||
* lt:fix handling of torrents with too large pieces
|
||||
* lt:fixed division by zero in anti-leech choker
|
||||
* lt:fixed bug in torrent_info::swap
|
||||
|
||||
1.2.2.0
|
||||
* libtorrent 1.2.2 update (d5b56ca1876dc7b96ef9aac7c7584e1f61d25774)
|
||||
* using android NDK r20 (released June 2019)
|
||||
* new local build script for android x86_64 (api level 20)
|
||||
* updated to boost 1.71.0
|
||||
* upgraded openssl to 1.1.1c
|
||||
* compiled with std=c++14 (up from c++11)
|
||||
* lt:pick contiguous pieces from peers with high download rate
|
||||
* lt:fix error handling of moving storage to a drive letter that isn't mounted
|
||||
* lt:fix integer overflow in http parser
|
||||
* lt:fix integer overflow in chunked http parser
|
||||
* lt:factor out and unit test parts of the DHT routing table logic
|
||||
* lt:improve sanitation of symlinks, to support more complex link targets (file_storage::sanitize_symlinks)
|
||||
* lt:avoid empty dht routing table buckets
|
||||
* lt:fix dht_stats_alert routing table stats for multi-homed clients
|
||||
* lt:fix entry assignment from bdecode_node and lazy_entry
|
||||
* lt:fix use-after-free issue in socket_type
|
||||
* lt:fix error code messages when building without deprecated functions
|
||||
* lt:feature to disable DHT, PEX and LSD per torrent
|
||||
* lt:fix seeding of random number generator on mingw
|
||||
* lt:fix issue where trackers from magnet links were not included in create_torrent()
|
||||
* lt:extend the whole_pieces_threshold setting to also request contiguous pieces from fast peers
|
||||
* lt:fix error handling of moving storage to a drive letter that isn't mounted
|
||||
* lt:don't leak exceptions out of handler callbacks in resolver
|
||||
* lt:ensure headers build independently
|
||||
* lt:fix unit template's mutating operators to give them proper ref qualifiers
|
||||
|
||||
1.2.1.0
|
||||
* using android NDK r19c (released January 2019)
|
||||
* updated to boost 1.70.0
|
||||
* lt:make sure session cleanup releases all its references to torrents
|
||||
* lt:track the mapped port for each NAT mapping transport
|
||||
* lt:optimize resolve_duplicate_filenames_slow()
|
||||
* lt:use a more restrictive limit on number of pieces allowed in a torrent
|
||||
* lt:improve disk I/O logging
|
||||
* lt:always flush disk I/O job queue before shutdown
|
||||
* lt:fix typo in validation of reject messages. Make on_choke a bit more defensive
|
||||
* lt:tighten up validation of dont-have messages
|
||||
* lt:tighten up validation of reject messages, to ensure consistency of stats counters
|
||||
* lt:tighten up message size checks
|
||||
* lt:update symlinks to conform to BEP 47
|
||||
* lt:source code cleanup, performance and stability
|
||||
|
||||
1.2.0.20
|
||||
* updated to libtorrent RC_1_2 HEAD
|
||||
* updated to OpenSSL 1.1.1b
|
||||
* lt:add support for creating symlinks, for torrents with symlinks in them
|
||||
* lt:allow padfiles of equal size to share the same filename
|
||||
* lt:fix seed_mode flag
|
||||
* lt:support numeric suffixes to magnet link parameter names
|
||||
* lt:added FrostWire's client ID
|
||||
* lt:don't try to hash empty read in do_uncached_hash
|
||||
* lt:don't copy a vector into the async_write operation for iovec
|
||||
* lt:on linux, link against lbdl when using openssl
|
||||
* lt:use UNC paths pervasively on windows
|
||||
* lt:source code cleanup, performance and stability
|
||||
|
||||
1.2.0.19
|
||||
* libtorrent release 1.2.0
|
||||
* using android NDK r18b
|
||||
* updated to boost 1.69.0
|
||||
* updated to OpenSSL 1.1.1a
|
||||
* fixed activeDhtLimit SettingsPack setter
|
||||
* development: new local build scripts for macosx, android, linux, windows
|
||||
* lt:only allow cwnd to be reduced so often (utp)
|
||||
* lt:avoid announcing local ip to private tracker
|
||||
* lt:don't treat loss of MTU probe packet as a congestion signal (utp)
|
||||
* lt:make sure we reset the duplicate ack counter every time we don't receive
|
||||
a duplicate ack (utp)
|
||||
* lt:remove old (incompatible) sequence number build option (utp)
|
||||
* lt:don't leave slow-start just because we hit the advertized receive window
|
||||
* lt:simplify and improve the uTP deferred ACK logic to respond earlier
|
||||
* lt:improve logic for fast-retransmitting packets on incoming SACK
|
||||
* lt:improve utp verbose logging a bit and make the parser pull out more
|
||||
metrics
|
||||
* lt:restore permissions on directories to 1.1. i.e. rely on umask
|
||||
* lt:minor fix to invalid_request_alert logging
|
||||
* lt:add assignment operator to span
|
||||
* lt:fix %u -> %d format codes
|
||||
* lt:fix deprecation markup in torrent_status
|
||||
* lt:tweak heuristic of how to interpret url seeds in multi-file torrents
|
||||
* lt:added more TORRENT_DEPRECATED_ENUM and deprecated unused aio_max in
|
||||
settings_pack
|
||||
* lt:take a string_view in setting_by_name
|
||||
* lt:fix typo in peer log
|
||||
* lt:deprecate start_default_features flag, it's only used in deprecated API
|
||||
* lt:remove verbose peer logging
|
||||
* lt:make stack_allocator::format_string() grow the buffer for large strings
|
||||
* lt:move where socket buffers are set up, to happen after the socket is
|
||||
opened. log errors in the peer's log instead of session and torrent
|
||||
* lt:add stats counter for the number of outstanding async_accept calls
|
||||
* lt:fix potential issue where the dht port message is sent before the peer
|
||||
handshake
|
||||
* lt:correct %u format code for pieces in printf() calls
|
||||
* lt:attempt to fix an assert for a newly connected peer that disconnects just
|
||||
as we receive the metadata
|
||||
* lt:don't use page aligned disk buffers
|
||||
* lt:include &ipv4= for private trackers
|
||||
* lt:add support for &ipv4= tracker argument
|
||||
* lt:use new bdecoder in ut_metadata class
|
||||
* lt:fix redundant bytes overflow
|
||||
* lt:check for self-assignment in bitfield operator=
|
||||
* lt:initialize bencoded ints with zero when constructed
|
||||
* lt:exit natpmp::on_reply earlier if we're shutting down
|
||||
* lt:fix setting ipv6 interface
|
||||
* lt:a better fix to the ssl port announce bug
|
||||
* lt:perfect forward async handlers for udp_socket to underlying asio socket
|
||||
* lt:move the whole add_torrent_params object into save_resume_data_alert
|
||||
* lt:actually fix the issue with the second tracker announce with port 0
|
||||
* lt:remove redundant MTU boundary checks
|
||||
* lt:fix of asio-debugging build in natpmp. resend_request could be called
|
||||
directly, not only as a handler for an async operation
|
||||
* lt:fix move_storage with save_path with a trailing slash
|
||||
* lt:only make snubbed peers invert the piece picking strategy when we're
|
||||
doing rarest first
|
||||
* lt:ssl listen port fix and improved tracker announce logging
|
||||
* lt:properly tear down the disk_io_thread object in set_piece_hashes() when
|
||||
exiting via an exception
|
||||
* lt:make throwing versions of read_resume_data
|
||||
* lt:fix overflow in sliding_average in the case of very high download rates
|
||||
* lt:renamed debug_notification to connect_notification
|
||||
* lt:fix issue in udp_socket with unusual socket failure
|
||||
* lt:utp close-reason use after free fix
|
||||
* lt:source code cleanup, performance and stability
|
||||
|
||||
|
||||
1.2.0.18
|
||||
|
||||
* using android NDK r17c
|
||||
* updated to boost 1.68.0
|
||||
* updated to OpenSSL 1.1.1
|
||||
* expose to java SWIG api the aux::arm_neon_support flag for android
|
||||
runtime verification
|
||||
* removed hack of custom getauxval definition
|
||||
* removed hack of fgetpos fsetpos
|
||||
* removed hack of mulodi4
|
||||
* null check protection in EnumNet
|
||||
* added new constructor to TorrentInfo from byte array
|
||||
* improved API for AnnounceEntry
|
||||
* added AnnounceEndpoint java API, it is a lightweight class
|
||||
* convert ErrorCode to a lightweight class
|
||||
* convert PeerInfo to a lightweight class, client is UTF-8 decoded
|
||||
* Vectors.byte_vector2string supports only ASCII and UTF-8
|
||||
* lt:fix redundant flushes of partfile metadata
|
||||
* lt:fix overflow in calc_bytes(), fix bug in piece picker accounting of
|
||||
filtered pad blocks
|
||||
* lt:improve type-safety of the severity parameter to
|
||||
peer_connection::disconnect()
|
||||
* lt:fix seed count when attaching a peer is aborted
|
||||
* lt:add option to ignore min-interval from tracker, when
|
||||
force-reannouncing a tracker
|
||||
* lt:raise default value for active_limit to 500, since it's supposed to be
|
||||
an upper sanity check limit
|
||||
* lt:make the print function for entry actually be json-like
|
||||
* lt:fall back to copy+remove if rename_file fails
|
||||
* lt:improve handling of filesystems not supporting fallocate()
|
||||
* lt:improve piece picker performance in tracking pad-blocks
|
||||
* lt:force proxy no longer disables the DHT
|
||||
* lt:simplify total_have/have_want/total_want. Make piece_picker track pad
|
||||
blocks and compute byte-progress at block granularity
|
||||
* lt:fix issue in self-connection detection introduced with the change to
|
||||
generate unique peer-ids for each connection.
|
||||
* lt:fix exporting files to avoid overwriting existing files, before
|
||||
exporting anything from a parts file, check whether it contains valid data
|
||||
* lt:improve connect-boost feature, to make new torrents quickly connect
|
||||
peers
|
||||
* lt:add a few more stats counters measuring outgoing connection attempts.
|
||||
simplify session_stats_header_alert by posting it on first call to
|
||||
post_session_stats() instead of making it gated by the alert_mask
|
||||
* lt:remove dead code from piece picker
|
||||
* lt:tweak the auto-cache-size logic to have slightly smaller cache
|
||||
* lt:fix deprecation of mmap_cache
|
||||
* lt:add missing increment of on_disk_counter and num_blocks_hashed counters
|
||||
* lt:apply piece priorities immediately, even though file priority updates
|
||||
are async. save both file- and piece priorities in fast resume
|
||||
* lt:simplify natpmp gateway and local address discovery
|
||||
* lt:fix typo in #if tests for TORRENT_DISABLE_ENCRYPTION
|
||||
* lt:in torrent_handle::id(), only shift down the pointer by 10 bits
|
||||
* lt:add piece index range checks on have_piece() and read_piece()
|
||||
* lt:make metric_type_t an enum class, deprecate the in-class enum values
|
||||
* lt:only post alerts for newly opened listen sockets, and only attempt to
|
||||
map ports for newly opened sockets
|
||||
* lt:remove special handling of uTP peers, uTP connections are no longer
|
||||
exempt from rate limits by default
|
||||
* lt:make natpmp deal with address_v6 instead of the bytes_type, and use
|
||||
write_address instead of memcpy
|
||||
* lt:fix exporting files from partfile while seeding
|
||||
* lt:set port in handshake based on source address
|
||||
* lt:fix Windows "file::preadv" emulation EOF handling
|
||||
* lt:fix windows async read EOF handling
|
||||
* lt:fix bug in read/write resume data functions
|
||||
* lt:dht don't set implied_port for SSL torrents
|
||||
* lt:dht announce with per-interface listen port
|
||||
* lt:deprecate (and disable) the force-proxy setting. Instead, always use
|
||||
the proxy when set, never fall back on circumventing it
|
||||
* lt:move the file priority vector throught the disk_io_job, to avoid copies
|
||||
* lt:raise priority of cache_flushed_alert and post it unconditionally when
|
||||
triggered explicitly by the client
|
||||
* lt:fix some validation issues in read_resume_data()
|
||||
* lt:bump the minimum number of hash jobs per thread from 2 to 4
|
||||
* lt:fix deadlock when loading libtorrent Dll
|
||||
* lt:fix torrent files prioritization
|
||||
* lt:fix some unintentional copies (with explicit moves)
|
||||
* lt:qualify some assignment operators to disallow assignment to temporaries
|
||||
* lt:fix missing move of file object in part_file
|
||||
* lt:use more threads when creating torrents
|
||||
* lt:bump checking_mem_usage default setting
|
||||
* lt:enable coalesce_reads and coalesce_writes by default on windows
|
||||
* lt:set the minimum number of checking jobs based on the number of hasher
|
||||
threads
|
||||
* lt:fix coalesce read bug
|
||||
* lt:introduce a fast-path for the hash disk job
|
||||
* lt:fix race condition in part_file
|
||||
* lt:fix parts file i/o errors
|
||||
* lt:fixed sign implicit conversion warnings and loop logic in new enum_net
|
||||
code
|
||||
* lt:improve the API for iterating over all files and pieces, with the new
|
||||
strong index types
|
||||
* lt:deprecate network-threads setting
|
||||
* lt:scrape_reply_alert should be high priority, since it's triggered by the
|
||||
client
|
||||
* lt:add support for multi-home NAT-PMP and Port Control Protocol (PCP)
|
||||
* lt:report transport version in NAT-PMP send/receive logs
|
||||
* lt:return a vector of mapping ids from add_port_mapping
|
||||
* lt:don't re-map all listen sockets when changing listen_interfaces
|
||||
* lt:create a natpmp instance for each listen socket
|
||||
* lt:enum_routes fixes on Linux
|
||||
* lt:fix scope_id in enum_routes on Windows
|
||||
* lt:remove UNC prefixes from device names on Windows
|
||||
* lt:fix netmask of routes on Windows
|
||||
* lt:deliver notification of alerts being dropped via alerts_dropped_alert
|
||||
* lt:raise priority of fastresume_rejected_alert
|
||||
* lt:don't use the partfile for existing files when their priority is 0
|
||||
* lt:set the hidden attribute when creating the part file
|
||||
* lt:only start a new accept request on new listen sockets, fix mapping new
|
||||
listen sockets when re-mapping is not requested
|
||||
* lt:don't change state to downloading if the torrent is finished
|
||||
* lt:bump `file_error_alert` priority
|
||||
* lt:fix address of point-to-point interfaces
|
||||
* lt:don't enable reuse-address for UDP sockets, as it will always succeed
|
||||
and not get any incoming packets
|
||||
* lt:account for partially downloaded pieces when announcing as a seed
|
||||
* lt:fix bandwidth allocation
|
||||
* lt:don't attempt to make uTP connections if we don't have any outgoing UDP
|
||||
sockets
|
||||
* lt:fix empty outgoing interfaces for UDP sockets
|
||||
* lt:only allow pinged nodes into the DHT routing table
|
||||
* lt:introduce a recursive mutex to protect the alert_manager, and hold the
|
||||
mutex while calling user callbacks and plugin hooks
|
||||
* lt:revise alert priorities / torrent::on_resume_data_checked issue
|
||||
* lt:save the number of idle threads locally in
|
||||
disk_io_thread_pool::thread_active
|
||||
* lt:fix use after free in flush_range and flush_iovec
|
||||
* lt:honor torrent abort even on file check error
|
||||
* lt:use settings_pack::urlseed_wait_retry for default retry with http seeds
|
||||
* lt:fix storage initialization
|
||||
* lt:strtoll() returns LLONG_MAX if the input overflows, handle this case
|
||||
properly in the http parser
|
||||
* lt:remove the global cache of the current time, just use clock::now()
|
||||
* lt:deprecated alert::progress_notification alert category, split into
|
||||
finer grained categories
|
||||
* lt:disk_io_thread abort_hash_jobs duplicate code refactor
|
||||
* lt:fix part-file header allocation
|
||||
* lt:fix potential fd leak in enum_net_interfaces
|
||||
* lt:don't perform DNS lookups for the DHT bootstrap unless DHT is enabled
|
||||
* lt:avoid calls to .address() when looking for endpoint protocol
|
||||
* lt:removed unnecessary loop in request_a_block
|
||||
* lt:fix changing file priorities while checking interrupts checking
|
||||
* lt:fix issue where the current tracker would be skipped for the next
|
||||
tracker in the same tier
|
||||
* lt:remove redundant check in tracker announce
|
||||
* lt:minor fixes in utp_socket_impl
|
||||
* lt:stat files in the disk thread, in default_storage::initialize()
|
||||
instead of the constructor
|
||||
* lt:dynamically load getauxval so as to support older android devices
|
||||
* lt:track whether a file is eligible for using the partfile on a per-file
|
||||
basis
|
||||
* lt:define NETLINK_NO_ENOBUFS and IFA_D_DADFAILED if they don't exist
|
||||
* lt:fix reporting &redundant= in tracker announces
|
||||
* lt:fix windows build with UNC paths disabled
|
||||
* lt:fix issue querying block size from torrent before metadata has been
|
||||
received
|
||||
* lt:source code cleanup, performance and stability
|
||||
|
||||
1.2.0.17
|
||||
|
||||
* added EnumNet java API to help query the device network state/status/info
|
||||
* compiling with -mstackrealign for android x86, some devices have stack
|
||||
alignment issues
|
||||
* lt:fix tie-break in duplicate peer connection disconnect logic
|
||||
* lt:fix issue with SSL tracker connections left in CLOSE_WAIT state
|
||||
* lt:defer truncating existing files until the first time we write to them
|
||||
* lt:fix issue when receiving a torrent with 0-sized padfiles as magnet link
|
||||
* lt:fix issue resuming 1.0.x downloads with a file priority 0
|
||||
* lt:fix torrent_status::next_announce
|
||||
* lt:turn piece picker option flags into a proper type
|
||||
* lt:fix pad-file scalability issue
|
||||
* lt:made coalesce_reads/coalesce_writes settings take effect on linux
|
||||
and windows
|
||||
* lt:source code cleanup, performance and stability
|
||||
|
||||
1.2.0.16
|
||||
|
||||
* using version in native library names
|
||||
* updated to boost 1.66.0
|
||||
* lt:use unique peer_ids per connection
|
||||
* lt:fix tracker connection bind issue for IPv6 trackers
|
||||
* lt:fix error handling of merkle torrents
|
||||
* lt:fix error handling of unsupported hard-links
|
||||
* lt:raise auto piece size selection limit to 16 MB in create_torrent()
|
||||
* lt:mark up performance counter operations as noexcept
|
||||
* lt:fix noexcept marking on entry, and make move assignment
|
||||
* lt:using make_address instead of deprecated from_string when boost>=1.66
|
||||
* lt:block_size is a constant, no need in passing it around as a variable
|
||||
* lt:remove_peer() and attach_peer() error handling
|
||||
* lt:support forced shutdown/destruction of torrent objects
|
||||
* lt:improve error handling during session shutdown
|
||||
* lt:handle serious errors in on_accept_connection handler
|
||||
* lt:deprecate save_encryption_settings
|
||||
* lt:handle errors in peer_connection
|
||||
* lt:support asio handler allocators in deferred_handler
|
||||
* lt:don't heap-allocate handlers for incoming UDP packets
|
||||
* lt:make the chunk header parser properly fail at end of buffer, and not
|
||||
require zero terminated strings
|
||||
* lt:add getters for peer_class_filter and peer_class_type_filter
|
||||
* lt:attempt to fix disconnections when torrents enter upload mode due to
|
||||
failures
|
||||
* lt:fix local network address mappings
|
||||
* lt:deprecate status_code from tracker_error_alert
|
||||
* lt:make torrent_handler::set_priority() to use peer_classes
|
||||
* lt:improve type safety of plugin interface
|
||||
* lt:introduce a proper type for pex flags to improve type-safety
|
||||
* lt:fix reopening of listen sockets when disabling force-proxy
|
||||
* lt:fix build against boost-1.66, specifically the boost.asio changes
|
||||
* lt:fix asio debugging
|
||||
* lt:fix rate limit utp feature
|
||||
* lt:fix i2p support
|
||||
* lt:source code cleanup, performance and stability
|
||||
|
||||
1.2.0.15
|
||||
|
||||
* added java API to download magnet uri
|
||||
* fixed issue with prioritize_files swig wrapper
|
||||
* API change in TorrentHandle#saveResumeData, now it pass empty flags
|
||||
by default
|
||||
* using android NDK r16b
|
||||
* updated to OpenSSL 1.1.0g
|
||||
* lt:fix loading resume data when in seed mode
|
||||
* lt:fix incorrect use of make_tick_handler
|
||||
* lt:fix issue with initializing settings on session construction
|
||||
* lt:implemented support for magnet URI extension, select specific file
|
||||
indices for download, BEP53
|
||||
* lt:fix issue with receiving interested before metadata
|
||||
* lt:generate random keys for use in tracker announces, unique per torrent
|
||||
and the listen interface
|
||||
* lt:fix IPv6 tracker announce issue
|
||||
* lt:don't early move shared_ptr plugin in torrent::add_extension_fun
|
||||
* lt:fix force-proxy regression (udp sockets would not be opened)
|
||||
* lt:restore path sanitization behavior of ':'
|
||||
* lt:make tracker announces happen even if there are no open listen sockets
|
||||
* lt:fix issue where new listen sockets would not be opened when leaving
|
||||
force_proxy mode
|
||||
* lt:make sure the cork destructor doesn't leak exceptions
|
||||
* lt:stop posting alerts when the session is shutting down, solves some
|
||||
issues around destruction order
|
||||
* lt:add API to query whether alerts have been dropped or not
|
||||
* lt:keep updating aux::time_now() while there are announces, fixes an
|
||||
infinite loop during shutdown
|
||||
* lt:source code cleanup, performance and stability
|
||||
|
||||
1.2.0.14
|
||||
|
||||
* fixed invalid handling of download_priority_t and swig wrapper
|
||||
|
||||
1.2.0.13
|
||||
|
||||
* enable full SSL support in libtorrent
|
||||
* compiling with -fvisibility=hidden and -Os
|
||||
* using android NDK r16 beta2
|
||||
* updated to boost 1.65.1
|
||||
* internal session in SessionManager blocks privileged ports and
|
||||
only allows 80 and 443 for possible web seeds connections
|
||||
* lt:enable/disable the internal ip notifier with new setting
|
||||
* lt:fix issue of null m_part_file in default_storage readv/writev
|
||||
* lt:added reopen_network_sockets method to allow manual reopen of
|
||||
listen/outgoing sockets
|
||||
* lt:using NETLINK_NO_ENOBUFS to ignore ENOBUFS in netlink based ip notifier
|
||||
* lt:add limit of max 50 upnp mappings and recover free global mappings
|
||||
* lt:creating part file if needed only in set_file_priorities
|
||||
* lt:fix full allocation failure on APFS
|
||||
* lt:make parse_magnet_uri return the add_torrent_params instead of
|
||||
taking an in-out parameter
|
||||
* lt:pick standard std::aligned_union if using clang
|
||||
* lt:make disk_buffer_holder know the size of the buffer it holds, to fix
|
||||
buffer overrun in chained_buffer
|
||||
* lt:fix infinite loop when parsing certain invalid magnet links
|
||||
* lt:don't delete pieces from cache with refcount > 0
|
||||
* lt:don't try to connect to a global address with a local source address
|
||||
* lt:fix parsing of torrents with certain invalid filenames
|
||||
* lt:fix leak of peer_class objects (when setting per-torrent rate limits)
|
||||
* lt:more strict filename sanitation
|
||||
* lt:improve handling of case where a torrent file has no files in it
|
||||
* lt:clean up and fix edge cases in update_path_index
|
||||
* lt:fix issue with the name in single file torrents being sanitized away
|
||||
* lt:make the chunk header parser a bit more strict and accurate
|
||||
* lt:fix integer overflow in torrent_info
|
||||
* lt:fix windows file preallocation issue
|
||||
* lt:fix integer overflow in whole_pieces_threshold logic
|
||||
* lt:DHT nodes should only handle requests on their socket
|
||||
* lt:bump priority of storage_moved_alert and storage_moved_failed_alert
|
||||
* lt:deprecate lock_files settings
|
||||
* lt:fix uTP path MTU discovery issue on windows, DF bit was not set
|
||||
correctly
|
||||
* lt:select which DHT port to report based on the connection's local
|
||||
endpoint
|
||||
* lt:avoid port mapping of local IPv6 addresses
|
||||
* lt:include endpoint in tracker alerts
|
||||
* lt:hold an owning reference to storage objects in try_flush_write_blocks
|
||||
* lt:read_piece: handle failure to allocate piece buffer
|
||||
* lt:treat unique local IPv6 addresses as local
|
||||
* lt:source code cleanup, performance and stability
|
||||
|
||||
1.2.0.12
|
||||
|
||||
* updated to boost 1.65
|
||||
* storing external address and listen endpoints as strings for better
|
||||
performance
|
||||
* improved creation of peers part of magnet links
|
||||
* lt:fixed netlink based network interface enumeration
|
||||
* lt:remove support for using a pool allocator for disk buffers
|
||||
* lt:fix IPv6 tracker support by performing the second announce in
|
||||
more cases
|
||||
* lt:fix issue in UTF-8 encoding validation
|
||||
* lt:fix infinite loop when parsing torrents whose filenames have zeroes
|
||||
* lt:fix invalid read in parse_int() in bdecode_node()
|
||||
* lt:don't create web seed connections if the torrent is upload only
|
||||
* lt:fix issue with very long tracker and web seed URLs
|
||||
* lt:fix issue where paths were not correctly coalesced when adding files
|
||||
to file_storage (used more memory than necessary)
|
||||
* lt:fix issue of force-recheck or seeding from read-only media, torrents
|
||||
with empty files in them
|
||||
* lt:fix force-recheck issue (new files would not be picked up)
|
||||
* lt:source code cleanup, performance and stability
|
||||
|
||||
1.2.0.11
|
||||
|
||||
* using android NDK r15c
|
||||
* using -O2 for all architectures
|
||||
* lt:fix to clearing of piece picker in suggest_read_cache mode
|
||||
* lt:fix memory issues with listen sockets references
|
||||
* lt:fix bug where the resume data would fail to load the piece bitmask for
|
||||
seeds when suggest_cache was enabled
|
||||
* lt:submit disk jobs in read_piece()
|
||||
* lt:add reserve entry::to_string() (optimization)
|
||||
* lt:refactor several flags to torrent_handle::get_flags/set_flags
|
||||
* lt:added block_uploaded_alert to allow client to track upload activity
|
||||
* lt:fix inconsistency in file_priorities and override_resume_data behavior
|
||||
* lt:remove call _strchr (optimization)
|
||||
* lt:fix bandwidth rate limit calculation
|
||||
* lt:fix handling of SSL listen sockets
|
||||
* lt:don't move listen_socket_t when deleting sockets
|
||||
* lt:avoid executing timed async task if the dht node is already removed
|
||||
* lt:reject DHT put messages with incorrect bencoding
|
||||
* lt:fix backwards compatibility issue when loading the torrent info dict
|
||||
from resume data
|
||||
* lt:fix regression where paused torrents could not have their queue
|
||||
position changed
|
||||
* lt:use netlink to enumerate network interfaces on linux
|
||||
* lt:fix out-of-bounds read in bdecode
|
||||
* lt:fix re-check issue after move_storage
|
||||
* lt:avoid runtime fail with wrong arguments in upnp::update_map
|
||||
* lt:handle invalid arguments to set_piece_deadline()
|
||||
* lt:fix that move_storage did not work for torrents without metadata
|
||||
* lt:fix check for fully allocated file on windows
|
||||
* lt:defer reconnecting peers to after the second_tick loop
|
||||
* lt:implemented support for BEP 51
|
||||
* lt:source code cleanup and stability
|
||||
|
||||
1.2.0.10
|
||||
|
||||
* added swig interface to announce_endpoint
|
||||
|
||||
1.2.0.9
|
||||
|
||||
* updated to OpenSSL 1.1.0f
|
||||
* updated to boost 1.64
|
||||
* using android NDK r15
|
||||
* avoid automatic UTF-8 conversion in JNI side when using string_view
|
||||
* lt:fix bandwidth rate limit calculation
|
||||
* lt:fix for what appears to be an clang/llvm miscompilation
|
||||
* lt:only listen on preferred IPv6 addresses on Windows
|
||||
* lt:when stopping a torrent, never perform a name lookup on the tracker,
|
||||
only announce to trackers whose IP we already know. This is expected to
|
||||
make shutdowns not hang
|
||||
* lt:fix previously faulty fix to enum_routes
|
||||
* lt:delay 5 seconds before reconnecting socks5 proxy for UDP ASSOCIATE
|
||||
* lt:fix NAT-PMP crash when removing a mapping at the wrong time
|
||||
* lt:fix race condition in storage tick handling in disk_io_thread
|
||||
* lt:keep iterating over endpoints if one is found to be done in
|
||||
tracker announce loop
|
||||
* lt:don't abort the existing torrent when attempting to add it again
|
||||
* lt:fix IPv6 UTP assertion failure, close listen sockets after closing
|
||||
all connections
|
||||
* lt:fix branch factor overflow in DHT traversal algorithm
|
||||
* lt:bind upnp requests to correct local address
|
||||
* lt:don't combine reuseaddr and exclusive addruse on windows
|
||||
* lt:save resume data when removing web seeds
|
||||
* lt:fix proxying of https connections
|
||||
* lt:fix race condition in disk I/O storage class
|
||||
* lt:avoid extra sha1_hash memory copy in create_torrent
|
||||
* lt:fix http connection timeout on multi-homed hosts
|
||||
* lt:implemented multi-home support
|
||||
* lt:make DHT bootstrapping more robust by not throwing away nodes
|
||||
* lt:need_save_resume_data() will no longer return true every 15 minutes
|
||||
* lt:create a separate DHT node for each listen socket
|
||||
* lt:avoid connections to trackers when the event is stopped and
|
||||
stop_tracker_timeout <= 0
|
||||
* lt:fix storage destruction order issue
|
||||
* lt:fix memory leak in the disk cache
|
||||
* lt:magnet links: unescape hash parameter
|
||||
* lt:fix double free in disk cache
|
||||
* lt:fix typo in natpmp::start
|
||||
* lt:remove mutex-release hack in file_pool
|
||||
* lt:source code cleanup and stability
|
||||
|
||||
1.2.0.8
|
||||
|
||||
* fixed synchronization issues in SessionManager#stop
|
||||
|
||||
1.2.0.7
|
||||
|
||||
* added support for ip_notifier in macOS
|
||||
* added resolver_cache_timeout setting for internal host name resolver
|
||||
* improved public API
|
||||
* internal fixes in libtorrent
|
||||
|
||||
1.2.0.7-RC3
|
||||
|
||||
* start of changelog
|
3802
frostwire-jlibtorrent/logo/jlibtorrent_logo.ai
Normal file
3802
frostwire-jlibtorrent/logo/jlibtorrent_logo.ai
Normal file
File diff suppressed because one or more lines are too long
BIN
frostwire-jlibtorrent/logo/jlibtorrent_logo_color.png
Normal file
BIN
frostwire-jlibtorrent/logo/jlibtorrent_logo_color.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 9.3 KiB |
BIN
frostwire-jlibtorrent/logo/jlibtorrent_logo_white.png
Normal file
BIN
frostwire-jlibtorrent/logo/jlibtorrent_logo_white.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 8.5 KiB |
BIN
frostwire-jlibtorrent/logo/jlibtorrent_type_color.png
Normal file
BIN
frostwire-jlibtorrent/logo/jlibtorrent_type_color.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.6 KiB |
BIN
frostwire-jlibtorrent/logo/jlibtorrent_type_white.png
Normal file
BIN
frostwire-jlibtorrent/logo/jlibtorrent_type_white.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.6 KiB |
@ -0,0 +1,542 @@
|
||||
package com.frostwire.jlibtorrent;
|
||||
|
||||
import com.frostwire.jlibtorrent.swig.add_torrent_params;
|
||||
import com.frostwire.jlibtorrent.swig.error_code;
|
||||
import com.frostwire.jlibtorrent.swig.int_vector;
|
||||
import com.frostwire.jlibtorrent.swig.storage_mode_t;
|
||||
import com.frostwire.jlibtorrent.swig.string_int_pair;
|
||||
import com.frostwire.jlibtorrent.swig.string_int_pair_vector;
|
||||
import com.frostwire.jlibtorrent.swig.string_vector;
|
||||
import com.frostwire.jlibtorrent.swig.tcp_endpoint_vector;
|
||||
import com.frostwire.jlibtorrent.swig.torrent_flags_t;
|
||||
import com.frostwire.jlibtorrent.swig.torrent_info;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* The {@link AddTorrentParams} is a parameter pack for adding torrents to a
|
||||
* session. The key fields when adding a torrent are:
|
||||
* <ul>
|
||||
* <li>ti - when you have a .torrent file</li>
|
||||
* <li>url - when you have a magnet link or http URL to the .torrent file</li>
|
||||
* <li>info_hash - when all you have is an info-hash (this is similar to a magnet link)</li>
|
||||
* </ul>
|
||||
* One of those fields need to be set. Another mandatory field is
|
||||
* {@link #savePath()}. The {@link AddTorrentParams} object is passed into one of the
|
||||
* {@link SessionHandle#addTorrent(AddTorrentParams, ErrorCode)} overloads or
|
||||
* {@link SessionHandle#asyncAddTorrent(AddTorrentParams)}.
|
||||
* <p>
|
||||
* If you only specify the info-hash, the torrent file will be downloaded
|
||||
* from peers, which requires them to support the metadata extension. It also
|
||||
* takes an optional {@link #name()} argument. This may be left empty in case no
|
||||
* name should be assigned to the torrent. In case it's not, the name is
|
||||
* used for the torrent as long as it doesn't have metadata.
|
||||
*
|
||||
* @author gubatron
|
||||
* @author aldenml
|
||||
*/
|
||||
public final class AddTorrentParams {
|
||||
|
||||
private final add_torrent_params p;
|
||||
|
||||
/**
|
||||
* The native object
|
||||
*
|
||||
* @param p the native object
|
||||
*/
|
||||
public AddTorrentParams(add_torrent_params p) {
|
||||
this.p = p;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an empty parameters object with the default storage.
|
||||
*/
|
||||
public AddTorrentParams() {
|
||||
this(add_torrent_params.create_instance());
|
||||
}
|
||||
|
||||
/**
|
||||
* @return an instance with the default storage
|
||||
*/
|
||||
public static AddTorrentParams createInstance() {
|
||||
return new AddTorrentParams(add_torrent_params.create_instance());
|
||||
}
|
||||
|
||||
/**
|
||||
* @return an instance with a disabled storage
|
||||
*/
|
||||
public static AddTorrentParams createInstanceDisabledStorage() {
|
||||
return new AddTorrentParams(add_torrent_params.create_instance_disabled_storage());
|
||||
}
|
||||
|
||||
/**
|
||||
* @return an instance with a zero storage
|
||||
*/
|
||||
public static AddTorrentParams createInstanceZeroStorage() {
|
||||
return new AddTorrentParams(add_torrent_params.create_instance_zero_storage());
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to parse a magnet uri and fill the parameters.
|
||||
*
|
||||
* @param uri the magnet uri
|
||||
* @return the params object filled with the data from the magnet
|
||||
*/
|
||||
public static AddTorrentParams parseMagnetUri(String uri) {
|
||||
error_code ec = new error_code();
|
||||
add_torrent_params params = add_torrent_params.parse_magnet_uri(uri, ec);
|
||||
if (ec.value() != 0) {
|
||||
throw new IllegalArgumentException("Invalid magnet uri: " + ec.message());
|
||||
}
|
||||
return new AddTorrentParams(params);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the native object
|
||||
*/
|
||||
public add_torrent_params swig() {
|
||||
return p;
|
||||
}
|
||||
|
||||
/**
|
||||
* Filled in by the constructor. It is used for forward binary compatibility.
|
||||
*
|
||||
* @return the version
|
||||
*/
|
||||
public int version() {
|
||||
return p.getVersion();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link TorrentInfo} object with the torrent to add.
|
||||
*
|
||||
* @return the torrent info or null if not set
|
||||
*/
|
||||
public TorrentInfo torrentInfo() {
|
||||
torrent_info ti = p.ti_ptr();
|
||||
return ti != null && ti.is_valid() ? new TorrentInfo(ti) : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link TorrentInfo} object with the torrent to add.
|
||||
*
|
||||
* @param ti the torrent info
|
||||
*/
|
||||
public void torrentInfo(TorrentInfo ti) {
|
||||
p.set_ti(ti.swig());
|
||||
}
|
||||
|
||||
/**
|
||||
* If the torrent doesn't have a tracker, but relies on the DHT to find
|
||||
* peers, the {@link #trackers(List)} can specify tracker URLs for the
|
||||
* torrent.
|
||||
*
|
||||
* @return the list of trackers
|
||||
*/
|
||||
public ArrayList<String> trackers() {
|
||||
string_vector v = p.get_trackers();
|
||||
int size = (int) v.size();
|
||||
ArrayList<String> l = new ArrayList<>();
|
||||
|
||||
for (int i = 0; i < size; i++) {
|
||||
l.add(v.get(i));
|
||||
}
|
||||
|
||||
return l;
|
||||
}
|
||||
|
||||
/**
|
||||
* If the torrent doesn't have a tracker, but relies on the DHT to find
|
||||
* peers, this method can specify tracker URLs for the torrent.
|
||||
*
|
||||
* @param value the list of trackers
|
||||
*/
|
||||
public void trackers(List<String> value) {
|
||||
string_vector v = new string_vector();
|
||||
|
||||
for (String s : value) {
|
||||
v.push_back(s);
|
||||
}
|
||||
|
||||
p.set_trackers(v);
|
||||
}
|
||||
|
||||
/**
|
||||
* The tiers the URLs in {@link #trackers()} belong to. Trackers belonging to
|
||||
* different tiers may be treated differently, as defined by the multi
|
||||
* tracker extension. This is optional, if not specified trackers are
|
||||
* assumed to be part of tier 0, or whichever the last tier was as
|
||||
* iterating over the trackers.
|
||||
*
|
||||
* @return the list of trackers tiers
|
||||
*/
|
||||
public ArrayList<Integer> trackerTiers() {
|
||||
int_vector v = p.get_tracker_tiers();
|
||||
int size = (int) v.size();
|
||||
ArrayList<Integer> l = new ArrayList<>();
|
||||
|
||||
for (int i = 0; i < size; i++) {
|
||||
l.add(v.get(i));
|
||||
}
|
||||
|
||||
return l;
|
||||
}
|
||||
|
||||
/**
|
||||
* The tiers the URLs in {@link #trackers()} belong to. Trackers belonging to
|
||||
* different tiers may be treated differently, as defined by the multi
|
||||
* tracker extension. This is optional, if not specified trackers are
|
||||
* assumed to be part of tier 0, or whichever the last tier was as
|
||||
* iterating over the trackers.
|
||||
*
|
||||
* @param value the list of trackers tiers
|
||||
*/
|
||||
public void trackerTiers(List<Integer> value) {
|
||||
int_vector v = new int_vector();
|
||||
|
||||
for (Integer t : value) {
|
||||
v.push_back(t);
|
||||
}
|
||||
|
||||
p.set_tracker_tiers(v);
|
||||
}
|
||||
|
||||
/**
|
||||
* A list of hostname and port pairs, representing DHT nodes to be added
|
||||
* to the session (if DHT is enabled). The hostname may be an IP address.
|
||||
*
|
||||
* @return the list of DHT nodes
|
||||
*/
|
||||
public ArrayList<Pair<String, Integer>> dhtNodes() {
|
||||
string_int_pair_vector v = p.get_dht_nodes();
|
||||
int size = (int) v.size();
|
||||
ArrayList<Pair<String, Integer>> l = new ArrayList<>();
|
||||
|
||||
for (int i = 0; i < size; i++) {
|
||||
string_int_pair n = v.get(i);
|
||||
l.add(new Pair<>(n.getFirst(), n.getSecond()));
|
||||
}
|
||||
|
||||
return l;
|
||||
}
|
||||
|
||||
/**
|
||||
* A list of hostname and port pairs, representing DHT nodes to be added
|
||||
* to the session (if DHT is enabled). The hostname may be an IP address.
|
||||
*
|
||||
* @param value the list of DHT nodes
|
||||
*/
|
||||
public void dhtNodes(List<Pair<String, Integer>> value) {
|
||||
string_int_pair_vector v = new string_int_pair_vector();
|
||||
|
||||
for (Pair<String, Integer> p : value) {
|
||||
v.push_back(p.to_string_int_pair());
|
||||
}
|
||||
|
||||
p.set_dht_nodes(v);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the name
|
||||
*/
|
||||
public String name() {
|
||||
return p.getName();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param value the name
|
||||
*/
|
||||
public void name(String value) {
|
||||
p.setName(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* The path where the torrent is or will be stored. Note that this may
|
||||
* also be stored in resume data. If you want the save path saved in
|
||||
* the resume data to be used, you need to set the
|
||||
* flag_use_resume_save_path flag.
|
||||
* <p>
|
||||
* .. note::
|
||||
* On windows this path (and other paths) are interpreted as UNC
|
||||
* paths. This means they must use backslashes as directory separators
|
||||
*
|
||||
* @return the save path
|
||||
*/
|
||||
public String savePath() {
|
||||
return p.getSave_path();
|
||||
}
|
||||
|
||||
/**
|
||||
* The path where the torrent is or will be stored. Note that this may
|
||||
* also be stored in resume data. If you want the save path saved in
|
||||
* the resume data to be used, you need to set the
|
||||
* flag_use_resume_save_path flag.
|
||||
* <p>
|
||||
* .. note::
|
||||
* On windows this path (and other paths) are interpreted as UNC
|
||||
* paths. This means they must use backslashes as directory separators
|
||||
*
|
||||
* @param value the save path
|
||||
*/
|
||||
public void savePath(String value) {
|
||||
p.setSave_path(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the storage mode
|
||||
* @see StorageMode
|
||||
*/
|
||||
public StorageMode storageMode() {
|
||||
return StorageMode.fromSwig(p.getStorage_mode().swigValue());
|
||||
}
|
||||
|
||||
/**
|
||||
* @param value the storage mode
|
||||
* @see StorageMode
|
||||
*/
|
||||
public void storageMode(StorageMode value) {
|
||||
p.setStorage_mode(storage_mode_t.swigToEnum(value.swig()));
|
||||
}
|
||||
|
||||
/**
|
||||
* The default tracker id to be used when announcing to trackers. By
|
||||
* default this is empty, and no tracker ID is used, since this is an
|
||||
* optional argument. If a tracker returns a tracker ID, that ID is used
|
||||
* instead of this.
|
||||
*
|
||||
* @return the trackerid url parameter
|
||||
*/
|
||||
public String trackerId() {
|
||||
return p.getTrackerid();
|
||||
}
|
||||
|
||||
/**
|
||||
* The default tracker id to be used when announcing to trackers. By
|
||||
* default this is empty, and no tracker ID is used, since this is an
|
||||
* optional argument. If a tracker returns a tracker ID, that ID is used
|
||||
* instead of this.
|
||||
*
|
||||
* @param value the trackerid url parameter
|
||||
*/
|
||||
public void trackerId(String value) {
|
||||
p.setTrackerid(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set this to the info hash of the torrent to add in case the info-hash
|
||||
* is the only known property of the torrent. i.e. you don't have a
|
||||
* .torrent file nor a magnet link.
|
||||
*
|
||||
* @return the info-hash
|
||||
*/
|
||||
public Sha1Hash infoHash() {
|
||||
return new Sha1Hash(p.getInfo_hash());
|
||||
}
|
||||
|
||||
/**
|
||||
* Set this to the info hash of the torrent to add in case the info-hash
|
||||
* is the only known property of the torrent. i.e. you don't have a
|
||||
* .torrent file nor a magnet link.
|
||||
*
|
||||
* @param value the info-hash
|
||||
*/
|
||||
public void infoHash(Sha1Hash value) {
|
||||
p.setInfo_hash(value.swig());
|
||||
}
|
||||
|
||||
/**
|
||||
* @return max uploads limit
|
||||
*/
|
||||
public int maxUploads() {
|
||||
return p.getMax_uploads();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param value max uploads limit
|
||||
*/
|
||||
public void maxUploads(int value) {
|
||||
p.setMax_uploads(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return max connections limit
|
||||
*/
|
||||
public int maxConnections() {
|
||||
return p.getMax_connections();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param value max connections limit
|
||||
*/
|
||||
public void maxConnections(int value) {
|
||||
p.setMax_connections(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return upload limit
|
||||
*/
|
||||
public int uploadLimit() {
|
||||
return p.getUpload_limit();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param value upload limit
|
||||
*/
|
||||
public void uploadLimit(int value) {
|
||||
p.setUpload_limit(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return download limit
|
||||
*/
|
||||
public int downloadLimit() {
|
||||
return p.getDownload_limit();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param value download limit
|
||||
*/
|
||||
public void downloadLimit(int value) {
|
||||
p.setDownload_limit(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Flags controlling aspects of this torrent and how it's added.
|
||||
*
|
||||
* @return the flags
|
||||
*/
|
||||
public torrent_flags_t flags() {
|
||||
return p.getFlags();
|
||||
}
|
||||
|
||||
/**
|
||||
* Flags controlling aspects of this torrent and how it's added.
|
||||
*
|
||||
* @param flags the flags
|
||||
*/
|
||||
public void flags(torrent_flags_t flags) {
|
||||
p.setFlags(flags);
|
||||
}
|
||||
|
||||
/**
|
||||
* Url seeds to be added to the torrent (`BEP 17`_).
|
||||
*
|
||||
* @return the url seeds
|
||||
*/
|
||||
public ArrayList<String> urlSeeds() {
|
||||
string_vector v = p.get_url_seeds();
|
||||
int size = (int) v.size();
|
||||
ArrayList<String> l = new ArrayList<>();
|
||||
|
||||
for (int i = 0; i < size; i++) {
|
||||
l.add(v.get(i));
|
||||
}
|
||||
|
||||
return l;
|
||||
}
|
||||
|
||||
/**
|
||||
* Url seeds to be added to the torrent (`BEP 17`_).
|
||||
*
|
||||
* @param value the url seeds
|
||||
*/
|
||||
public void urlSeeds(List<String> value) {
|
||||
string_vector v = new string_vector();
|
||||
|
||||
for (String s : value) {
|
||||
v.push_back(s);
|
||||
}
|
||||
|
||||
p.set_url_seeds(v);
|
||||
}
|
||||
|
||||
/**
|
||||
* Can be set to control the initial file priorities when adding a
|
||||
* torrent. The semantics are the same as for
|
||||
* {@link TorrentHandle#prioritizeFiles(Priority[])}.
|
||||
*
|
||||
* @param priorities the priorities
|
||||
*/
|
||||
public void filePriorities(Priority[] priorities) {
|
||||
p.set_file_priorities2(Priority.array2byte_vector(priorities));
|
||||
}
|
||||
|
||||
/**
|
||||
* This sets the priorities for each individual piece in the torrent. Each
|
||||
* element in the vector represent the piece with the same index. If you
|
||||
* set both file- and piece priorities, file priorities will take
|
||||
* precedence.
|
||||
*
|
||||
* @param priorities the priorities
|
||||
*/
|
||||
public void piecePriorities(Priority[] priorities) {
|
||||
p.set_piece_priorities2(Priority.array2byte_vector(priorities));
|
||||
}
|
||||
|
||||
/**
|
||||
* Peers to add to the torrent, to be tried to be connected to as
|
||||
* bittorrent peers.
|
||||
*
|
||||
* @return the peers list
|
||||
*/
|
||||
public ArrayList<TcpEndpoint> peers() {
|
||||
tcp_endpoint_vector v = p.get_peers();
|
||||
int size = (int) v.size();
|
||||
ArrayList<TcpEndpoint> l = new ArrayList<>();
|
||||
|
||||
for (int i = 0; i < size; i++) {
|
||||
l.add(new TcpEndpoint(v.get(i)));
|
||||
}
|
||||
|
||||
return l;
|
||||
}
|
||||
|
||||
/**
|
||||
* Peers to add to the torrent, to be tried to be connected to as
|
||||
* bittorrent peers.
|
||||
*
|
||||
* @param value the peers list
|
||||
*/
|
||||
public void peers(List<TcpEndpoint> value) {
|
||||
tcp_endpoint_vector v = new tcp_endpoint_vector();
|
||||
|
||||
for (TcpEndpoint endp : value) {
|
||||
v.push_back(endp.swig());
|
||||
}
|
||||
|
||||
p.set_peers(v);
|
||||
}
|
||||
|
||||
/**
|
||||
* Peers banned from this torrent. The will not be connected to.
|
||||
*
|
||||
* @return the peers list
|
||||
*/
|
||||
public ArrayList<TcpEndpoint> bannedPeers() {
|
||||
tcp_endpoint_vector v = p.get_banned_peers();
|
||||
int size = (int) v.size();
|
||||
ArrayList<TcpEndpoint> l = new ArrayList<>();
|
||||
|
||||
for (int i = 0; i < size; i++) {
|
||||
l.add(new TcpEndpoint(v.get(i)));
|
||||
}
|
||||
|
||||
return l;
|
||||
}
|
||||
|
||||
/**
|
||||
* Peers banned from this torrent. The will not be connected to.
|
||||
*
|
||||
* @param value the peers list
|
||||
*/
|
||||
public void bannedPeers(List<TcpEndpoint> value) {
|
||||
tcp_endpoint_vector v = new tcp_endpoint_vector();
|
||||
|
||||
for (TcpEndpoint endp : value) {
|
||||
v.push_back(endp.swig());
|
||||
}
|
||||
|
||||
p.set_banned_peers(v);
|
||||
}
|
||||
}
|
@ -0,0 +1,128 @@
|
||||
package com.frostwire.jlibtorrent;
|
||||
|
||||
import com.frostwire.jlibtorrent.swig.address;
|
||||
import com.frostwire.jlibtorrent.swig.error_code;
|
||||
|
||||
/**
|
||||
* @author gubatron
|
||||
* @author aldenml
|
||||
*/
|
||||
public final class Address implements Comparable<Address>, Cloneable {
|
||||
|
||||
private final address addr;
|
||||
|
||||
/**
|
||||
* @param addr the native object
|
||||
*/
|
||||
public Address(address addr) {
|
||||
this.addr = addr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an address from an IPv4 address string in dotted decimal form,
|
||||
* or from an IPv6 address in hexadecimal notation.
|
||||
*
|
||||
* @param ip the ip string representation
|
||||
*/
|
||||
public Address(String ip) {
|
||||
error_code ec = new error_code();
|
||||
this.addr = address.from_string(ip, ec);
|
||||
if (ec.value() != 0) {
|
||||
throw new IllegalArgumentException(ec.message());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public Address() {
|
||||
this(new address());
|
||||
}
|
||||
|
||||
static String toString(address a) {
|
||||
error_code ec = new error_code();
|
||||
String s = a.to_string(ec);
|
||||
if (ec.value() != 0) {
|
||||
s = "<invalid address>";
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return native object
|
||||
*/
|
||||
public address swig() {
|
||||
return addr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get whether the address is an IP version 4 address.
|
||||
*
|
||||
* @return if it's an IPv4 address
|
||||
*/
|
||||
public boolean isV4() {
|
||||
return addr.is_v4();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get whether the address is an IP version 6 address.
|
||||
*
|
||||
* @return if it's an IPv6 address
|
||||
*/
|
||||
public boolean isV6() {
|
||||
return addr.is_v6();
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the address is a loopback address.
|
||||
*
|
||||
* @return if it's a loopback address
|
||||
*/
|
||||
public boolean isLoopback() {
|
||||
return addr.is_loopback();
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the address is unspecified.
|
||||
*
|
||||
* @return if it's an unspecified address
|
||||
*/
|
||||
public boolean isUnspecified() {
|
||||
return addr.is_unspecified();
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the address is a multicast address.
|
||||
*
|
||||
* @return if it's an multicast address
|
||||
*/
|
||||
public boolean isMulticast() {
|
||||
return addr.is_multicast();
|
||||
}
|
||||
|
||||
/**
|
||||
* Compare addresses for ordering.
|
||||
*
|
||||
* @param o the other address
|
||||
* @return -1, 0 or 1
|
||||
*/
|
||||
@Override
|
||||
public int compareTo(Address o) {
|
||||
return address.compare(this.addr, o.addr);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the address as a string in dotted decimal format.
|
||||
*
|
||||
* @return string representation
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return toString(addr);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Address clone() {
|
||||
return new Address(new address(addr));
|
||||
}
|
||||
}
|
@ -0,0 +1,23 @@
|
||||
package com.frostwire.jlibtorrent;
|
||||
|
||||
import com.frostwire.jlibtorrent.alerts.Alert;
|
||||
|
||||
/**
|
||||
* @author gubatron
|
||||
* @author aldenml
|
||||
*/
|
||||
public interface AlertListener {
|
||||
|
||||
/**
|
||||
* List of alert types filtered by this listener.
|
||||
* Return `null` if you intend to listen to all alerts.
|
||||
*
|
||||
* @return the types filter
|
||||
*/
|
||||
int[] types();
|
||||
|
||||
/**
|
||||
* @param alert the alert
|
||||
*/
|
||||
void alert(Alert<?> alert);
|
||||
}
|
@ -0,0 +1,64 @@
|
||||
package com.frostwire.jlibtorrent;
|
||||
|
||||
import com.frostwire.jlibtorrent.alerts.Alert;
|
||||
|
||||
/**
|
||||
* @author gubatron
|
||||
* @author aldenml
|
||||
*/
|
||||
final class AlertMulticaster implements AlertListener {
|
||||
|
||||
private final AlertListener a;
|
||||
private final AlertListener b;
|
||||
|
||||
public AlertMulticaster(AlertListener a, AlertListener b) {
|
||||
this.a = a;
|
||||
this.b = b;
|
||||
}
|
||||
|
||||
public static AlertListener add(AlertListener a, AlertListener b) {
|
||||
return addInternal(a, b);
|
||||
}
|
||||
|
||||
public static AlertListener remove(AlertListener l, AlertListener oldl) {
|
||||
return removeInternal(l, oldl);
|
||||
}
|
||||
|
||||
private static AlertListener addInternal(AlertListener a, AlertListener b) {
|
||||
if (a == null) return b;
|
||||
if (b == null) return a;
|
||||
return new AlertMulticaster(a, b);
|
||||
}
|
||||
|
||||
private static AlertListener removeInternal(AlertListener l, AlertListener oldl) {
|
||||
if (l == oldl || l == null) {
|
||||
return null;
|
||||
} else if (l instanceof AlertMulticaster) {
|
||||
return ((AlertMulticaster) l).remove(oldl);
|
||||
} else {
|
||||
return l; // it's not here
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int[] types() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void alert(Alert<?> alert) {
|
||||
a.alert(alert);
|
||||
b.alert(alert);
|
||||
}
|
||||
|
||||
private AlertListener remove(AlertListener oldl) {
|
||||
if (oldl == a) return b;
|
||||
if (oldl == b) return a;
|
||||
AlertListener a2 = removeInternal(a, oldl);
|
||||
AlertListener b2 = removeInternal(b, oldl);
|
||||
if (a2 == a && b2 == b) {
|
||||
return this; // it's not here
|
||||
}
|
||||
return addInternal(a2, b2);
|
||||
}
|
||||
}
|
@ -0,0 +1,166 @@
|
||||
package com.frostwire.jlibtorrent;
|
||||
|
||||
import com.frostwire.jlibtorrent.swig.announce_endpoint;
|
||||
|
||||
/**
|
||||
* Announces are sent to each tracker using every listen socket, this class
|
||||
* holds information about one listen socket for one tracker.
|
||||
* <p>
|
||||
* This class is a lightweight version of the native {@link announce_endpoint},
|
||||
* and only carries a subset of all the information. However, it's completely
|
||||
* open for custom use or optimization to accommodate client necessities.
|
||||
*
|
||||
* @author gubatron
|
||||
* @author aldenml
|
||||
*/
|
||||
public class AnnounceEndpoint {
|
||||
|
||||
protected String message;
|
||||
protected ErrorCode lastError;
|
||||
protected String localEndpoint;
|
||||
protected long nextAnnounce;
|
||||
protected long minAnnounce;
|
||||
protected int scrapeIncomplete;
|
||||
protected int scrapeComplete;
|
||||
protected int scrapeDownloaded;
|
||||
protected int fails;
|
||||
protected boolean updating;
|
||||
protected boolean isWorking;
|
||||
|
||||
/**
|
||||
* @param e the native object
|
||||
*/
|
||||
public AnnounceEndpoint(announce_endpoint e) {
|
||||
init(e);
|
||||
}
|
||||
|
||||
/**
|
||||
* If this tracker has returned an error or warning message
|
||||
* that message is stored here.
|
||||
*
|
||||
* @return the error or warning message
|
||||
*/
|
||||
public String message() {
|
||||
return message;
|
||||
}
|
||||
|
||||
/**
|
||||
* If this tracker failed the last time it was contacted
|
||||
* this error code specifies what error occurred.
|
||||
*
|
||||
* @return the last error code
|
||||
*/
|
||||
public ErrorCode lastError() {
|
||||
return lastError;
|
||||
}
|
||||
|
||||
/**
|
||||
* The local endpoint of the listen interface associated with this endpoint.
|
||||
*
|
||||
* @return the local endpoint
|
||||
*/
|
||||
public String localEndpoint() {
|
||||
return localEndpoint;
|
||||
}
|
||||
|
||||
/**
|
||||
* The time of next tracker announce in milliseconds.
|
||||
*
|
||||
* @return the time of next tracker announce in milliseconds
|
||||
*/
|
||||
public long nextAnnounce() {
|
||||
return nextAnnounce;
|
||||
}
|
||||
|
||||
/**
|
||||
* No announces before this time.
|
||||
*/
|
||||
public long minAnnounce() {
|
||||
return minAnnounce;
|
||||
}
|
||||
|
||||
/**
|
||||
* This is either -1 or the scrape information this tracker last
|
||||
* responded with. Incomplete is the current number of downloaders in
|
||||
* the swarm.
|
||||
* <p>
|
||||
* If this tracker has returned scrape data, these fields are filled in
|
||||
* with valid numbers. Otherwise they are set to -1.
|
||||
*
|
||||
* @return the number of current downloaders
|
||||
*/
|
||||
public int scrapeIncomplete() {
|
||||
return scrapeIncomplete;
|
||||
}
|
||||
|
||||
/**
|
||||
* This is either -1 or the scrape information this tracker last
|
||||
* responded with. Complete is the current number of seeds in the swarm.
|
||||
* <p>
|
||||
* If this tracker has returned scrape data, these fields are filled in
|
||||
* with valid numbers. Otherwise they are set to -1.
|
||||
*
|
||||
* @return the current number of seeds
|
||||
*/
|
||||
public int scrapeComplete() {
|
||||
return scrapeComplete;
|
||||
}
|
||||
|
||||
/**
|
||||
* This is either -1 or the scrape information this tracker last
|
||||
* responded with. Downloaded is the cumulative number of completed
|
||||
* downloads of this torrent, since the beginning of time
|
||||
* (from this tracker's point of view).
|
||||
* <p>
|
||||
* If this tracker has returned scrape data, these fields are filled in
|
||||
* with valid numbers. Otherwise they are set to -1.
|
||||
*
|
||||
* @return the cumulative number of completed downloads
|
||||
*/
|
||||
public int scrapeDownloaded() {
|
||||
return scrapeDownloaded;
|
||||
}
|
||||
|
||||
/**
|
||||
* The number of times in a row we have failed to announce to this tracker.
|
||||
*
|
||||
* @return the number of fails
|
||||
*/
|
||||
public int fails() {
|
||||
return fails;
|
||||
}
|
||||
|
||||
/**
|
||||
* True while we're waiting for a response from the tracker.
|
||||
*/
|
||||
public boolean updating() {
|
||||
return updating;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the last time we tried to announce to this
|
||||
* tracker succeeded, or if we haven't tried yet.
|
||||
*/
|
||||
public boolean isWorking() {
|
||||
return isWorking;
|
||||
}
|
||||
|
||||
/**
|
||||
* NOTE: use this with care and only if necessary.
|
||||
*
|
||||
* @param e the native object
|
||||
*/
|
||||
protected void init(announce_endpoint e) {
|
||||
message = Vectors.byte_vector2ascii(e.get_message());
|
||||
lastError = new ErrorCode(e.getLast_error());
|
||||
localEndpoint = new TcpEndpoint(e.getLocal_endpoint()).toString();
|
||||
nextAnnounce = e.get_next_announce();
|
||||
minAnnounce = e.get_min_announce();
|
||||
scrapeIncomplete = e.getScrape_incomplete();
|
||||
scrapeComplete = e.getScrape_complete();
|
||||
scrapeDownloaded = e.getScrape_downloaded();
|
||||
fails = e.getFails();
|
||||
updating = e.getUpdating();
|
||||
isWorking = e.is_working();
|
||||
}
|
||||
}
|
@ -0,0 +1,128 @@
|
||||
package com.frostwire.jlibtorrent;
|
||||
|
||||
import com.frostwire.jlibtorrent.swig.announce_endpoint_vector;
|
||||
import com.frostwire.jlibtorrent.swig.announce_entry;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* This class holds information about one bittorrent tracker, as it
|
||||
* relates to a specific torrent.
|
||||
*
|
||||
* @author gubatron
|
||||
* @author aldenml
|
||||
*/
|
||||
public final class AnnounceEntry {
|
||||
|
||||
private final announce_entry e;
|
||||
|
||||
/**
|
||||
* @param e the native object
|
||||
*/
|
||||
public AnnounceEntry(announce_entry e) {
|
||||
this.e = e;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a tracker announce entry with {@code u} as the URL.
|
||||
*
|
||||
* @param url the tracker url
|
||||
*/
|
||||
public AnnounceEntry(String url) {
|
||||
this(new announce_entry(Vectors.ascii2byte_vector(url)));
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the native object
|
||||
*/
|
||||
public announce_entry swig() {
|
||||
return e;
|
||||
}
|
||||
|
||||
public List<AnnounceEndpoint> endpoints() {
|
||||
announce_endpoint_vector v = e.getEndpoints();
|
||||
int size = (int) v.size();
|
||||
ArrayList<AnnounceEndpoint> l = new ArrayList<>(size);
|
||||
|
||||
for (int i = 0; i < size; i++) {
|
||||
l.add(new AnnounceEndpoint(v.get(i)));
|
||||
}
|
||||
|
||||
return l;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tracker URL as it appeared in the torrent file.
|
||||
*
|
||||
* @return the tracker url
|
||||
*/
|
||||
public String url() {
|
||||
return Vectors.byte_vector2ascii(e.get_url());
|
||||
}
|
||||
|
||||
public void url(String value) {
|
||||
e.set_url(Vectors.ascii2byte_vector(value));
|
||||
}
|
||||
|
||||
/**
|
||||
* The current {@code &trackerid=} argument passed to the tracker.
|
||||
* this is optional and is normally empty (in which case no
|
||||
* trackerid is sent).
|
||||
*
|
||||
* @return the trackerid url argument
|
||||
*/
|
||||
public String trackerId() {
|
||||
return Vectors.byte_vector2ascii(e.get_trackerid());
|
||||
}
|
||||
|
||||
public void trackerId(String value) {
|
||||
e.set_trackerid(Vectors.ascii2byte_vector(value));
|
||||
}
|
||||
|
||||
/**
|
||||
* The tier this tracker belongs to.
|
||||
*
|
||||
* @return the tier number
|
||||
*/
|
||||
public int tier() {
|
||||
return e.getTier();
|
||||
}
|
||||
|
||||
public void tier(short value) {
|
||||
e.setTier(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* The max number of failures to announce to this tracker in
|
||||
* a row, before this tracker is not used anymore. 0 means unlimited.
|
||||
*
|
||||
* @return the max number of failures allowed
|
||||
*/
|
||||
public int failLimit() {
|
||||
return e.getFail_limit();
|
||||
}
|
||||
|
||||
public void failLimit(short value) {
|
||||
e.setFail_limit(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* A bitmask specifying which sources we got this tracker from.
|
||||
*
|
||||
* @return the source bitmask
|
||||
*/
|
||||
public int source() {
|
||||
return e.getSource();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set to true the first time we receive a valid response
|
||||
* from this tracker.
|
||||
*
|
||||
* @return if the tracker has received a valid response
|
||||
*/
|
||||
public boolean isVerified() {
|
||||
return e.getVerified();
|
||||
}
|
||||
}
|
@ -0,0 +1,76 @@
|
||||
package com.frostwire.jlibtorrent;
|
||||
|
||||
import com.frostwire.jlibtorrent.swig.bdecode_node;
|
||||
import com.frostwire.jlibtorrent.swig.byte_vector;
|
||||
import com.frostwire.jlibtorrent.swig.error_code;
|
||||
|
||||
/**
|
||||
* @author gubatron
|
||||
* @author aldenml
|
||||
*/
|
||||
public final class BDecodeNode {
|
||||
|
||||
private final bdecode_node n;
|
||||
private final byte_vector buffer;
|
||||
|
||||
/**
|
||||
* @param n the native object
|
||||
*/
|
||||
public BDecodeNode(bdecode_node n) {
|
||||
this(n, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to keep the buffer reference around.
|
||||
*
|
||||
* @param n the native object
|
||||
* @param buffer the buffer backing up the native object
|
||||
*/
|
||||
public BDecodeNode(bdecode_node n, byte_vector buffer) {
|
||||
this.n = n;
|
||||
this.buffer = buffer;
|
||||
}
|
||||
|
||||
public static BDecodeNode bdecode(byte[] data) {
|
||||
byte_vector buffer = Vectors.bytes2byte_vector(data);
|
||||
bdecode_node n = new bdecode_node();
|
||||
error_code ec = new error_code();
|
||||
int ret = bdecode_node.bdecode(buffer, n, ec);
|
||||
|
||||
if (ret == 0) {
|
||||
return new BDecodeNode(n, buffer);
|
||||
} else {
|
||||
throw new IllegalArgumentException("Can't decode data: " + ec.message());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the native object
|
||||
*/
|
||||
public bdecode_node swig() {
|
||||
return n;
|
||||
}
|
||||
|
||||
/**
|
||||
* This methods returns the internal buffer or null
|
||||
* if it was constructed without one.
|
||||
* <p>
|
||||
* This also prevent premature garbage collection in case
|
||||
* the node was created from a constructed buffer.
|
||||
*
|
||||
* @return the pinned buffer
|
||||
*/
|
||||
public byte_vector buffer() {
|
||||
return buffer;
|
||||
}
|
||||
|
||||
/**
|
||||
* A JSON style string representation
|
||||
*
|
||||
* @return the string representation
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return bdecode_node.to_string(n, false, 2);
|
||||
}
|
||||
}
|
@ -0,0 +1,135 @@
|
||||
package com.frostwire.jlibtorrent;
|
||||
|
||||
import com.frostwire.jlibtorrent.swig.block_info;
|
||||
|
||||
/**
|
||||
* Holds the state of a block in a piece. Who we requested
|
||||
* it from and how far along we are at downloading it.
|
||||
*
|
||||
* @author gubatron
|
||||
* @author aldenml
|
||||
*/
|
||||
public final class BlockInfo {
|
||||
|
||||
private final block_info b;
|
||||
|
||||
/**
|
||||
* @param b the native object
|
||||
*/
|
||||
public BlockInfo(block_info b) {
|
||||
this.b = b;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the native object
|
||||
*/
|
||||
public block_info swig() {
|
||||
return b;
|
||||
}
|
||||
|
||||
/**
|
||||
* The peer is the ip address of the peer this block was downloaded from.
|
||||
*
|
||||
* @return the peer tcp endpoint
|
||||
*/
|
||||
public TcpEndpoint peer() {
|
||||
return new TcpEndpoint(b.peer());
|
||||
}
|
||||
|
||||
/**
|
||||
* The number of bytes that have been received for this block.
|
||||
*
|
||||
* @return the number of bytes received
|
||||
*/
|
||||
public int bytesProgress() {
|
||||
return (int) b.getBytes_progress();
|
||||
}
|
||||
|
||||
/**
|
||||
* The total number of bytes in this block.
|
||||
*
|
||||
* @return otal number of bytes
|
||||
*/
|
||||
public int blockSize() {
|
||||
return (int) b.getBlock_size();
|
||||
}
|
||||
|
||||
/**
|
||||
* The state this block is in.
|
||||
*
|
||||
* @return the block's state
|
||||
*/
|
||||
public BlockState state() {
|
||||
return BlockState.fromSwig((int) b.getState());
|
||||
}
|
||||
|
||||
/**
|
||||
* The number of peers that is currently requesting this block. Typically
|
||||
* this is 0 or 1, but at the end of the torrent blocks may be requested
|
||||
* by more peers in parallel to speed things up.
|
||||
*
|
||||
* @return number of peers
|
||||
*/
|
||||
public int numPeers() {
|
||||
return (int) b.getNum_peers();
|
||||
}
|
||||
|
||||
/**
|
||||
* This is the enum used for {@link #state()}.
|
||||
*/
|
||||
public enum BlockState {
|
||||
|
||||
/**
|
||||
* This block has not been downloaded or requested form any peer.
|
||||
*/
|
||||
NONE(block_info.block_state_t.none.swigValue()),
|
||||
|
||||
/**
|
||||
* The block has been requested, but not completely downloaded yet.
|
||||
*/
|
||||
REQUESTED(block_info.block_state_t.requested.swigValue()),
|
||||
|
||||
/**
|
||||
* The block has been downloaded and is currently queued for being
|
||||
* written to disk.
|
||||
*/
|
||||
WRITING(block_info.block_state_t.writing.swigValue()),
|
||||
|
||||
/**
|
||||
* The block has been written to disk.
|
||||
*/
|
||||
FINISHED(block_info.block_state_t.finished.swigValue()),
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
UNKNOWN(-1);
|
||||
|
||||
private final int swigValue;
|
||||
|
||||
BlockState(int swigValue) {
|
||||
this.swigValue = swigValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param swigValue the native value
|
||||
* @return the state
|
||||
*/
|
||||
public static BlockState fromSwig(int swigValue) {
|
||||
BlockState[] enumValues = BlockState.class.getEnumConstants();
|
||||
for (BlockState ev : enumValues) {
|
||||
if (ev.swig() == swigValue) {
|
||||
return ev;
|
||||
}
|
||||
}
|
||||
return UNKNOWN;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the native value
|
||||
*/
|
||||
public int swig() {
|
||||
return swigValue;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,130 @@
|
||||
package com.frostwire.jlibtorrent;
|
||||
|
||||
import com.frostwire.jlibtorrent.swig.dht_lookup;
|
||||
|
||||
/**
|
||||
* Holds statistics about a current dht_lookup operation.
|
||||
* a DHT lookup is the traversal of nodes, looking up a
|
||||
* set of target nodes in the DHT for retrieving and possibly
|
||||
* storing information in the DHT
|
||||
*
|
||||
* @author gubatron
|
||||
* @author aldenml
|
||||
*/
|
||||
public final class DhtLookup {
|
||||
|
||||
private final dht_lookup l;
|
||||
|
||||
/**
|
||||
* internal use
|
||||
*
|
||||
* @param l
|
||||
*/
|
||||
public DhtLookup(dht_lookup l) {
|
||||
this.l = l;
|
||||
}
|
||||
|
||||
/**
|
||||
* The native object.
|
||||
*
|
||||
* @return the native object
|
||||
*/
|
||||
public dht_lookup swig() {
|
||||
return l;
|
||||
}
|
||||
|
||||
/**
|
||||
* string literal indicating which kind of lookup this is.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public String type() {
|
||||
return l.get_type();
|
||||
}
|
||||
|
||||
/**
|
||||
* the number of outstanding request to individual nodes
|
||||
* this lookup has right now.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public int outstandingRequests() {
|
||||
return l.getOutstanding_requests();
|
||||
}
|
||||
|
||||
/**
|
||||
* the total number of requests that have timed out so far
|
||||
* for this lookup.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public int timeouts() {
|
||||
return l.getTimeouts();
|
||||
}
|
||||
|
||||
/**
|
||||
* the total number of responses we have received for this
|
||||
* lookup so far for this lookup.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public int responses() {
|
||||
return l.getResponses();
|
||||
}
|
||||
|
||||
/**
|
||||
* the branch factor for this lookup. This is the number of
|
||||
* nodes we keep outstanding requests to in parallel by default.
|
||||
* when nodes time out we may increase this.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public int branchFactor() {
|
||||
return l.getBranch_factor();
|
||||
}
|
||||
|
||||
/**
|
||||
* the number of nodes left that could be queries for this
|
||||
* lookup. Many of these are likely to be part of the trail
|
||||
* while performing the lookup and would never end up actually
|
||||
* being queried.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public int nodesLeft() {
|
||||
return l.getNodes_left();
|
||||
}
|
||||
|
||||
/**
|
||||
* the number of seconds ago the
|
||||
* last message was sent that's still
|
||||
* outstanding.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public int lastSent() {
|
||||
return l.getLast_sent();
|
||||
}
|
||||
|
||||
/**
|
||||
* the number of outstanding requests
|
||||
* that have exceeded the short timeout
|
||||
* and are considered timed out in the
|
||||
* sense that they increased the branch
|
||||
* factor.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public int firstTimeout() {
|
||||
return l.getFirst_timeout();
|
||||
}
|
||||
|
||||
/**
|
||||
* The node-id or info-hash target for this lookup.
|
||||
*
|
||||
* @return the target
|
||||
*/
|
||||
public Sha1Hash target() {
|
||||
return new Sha1Hash(l.getTarget());
|
||||
}
|
||||
}
|
@ -0,0 +1,49 @@
|
||||
package com.frostwire.jlibtorrent;
|
||||
|
||||
import com.frostwire.jlibtorrent.swig.dht_routing_bucket;
|
||||
|
||||
/**
|
||||
* Hold information about a single DHT routing table bucket
|
||||
*
|
||||
* @author gubatron
|
||||
* @author aldenml
|
||||
*/
|
||||
public final class DhtRoutingBucket {
|
||||
|
||||
private final dht_routing_bucket t;
|
||||
|
||||
public DhtRoutingBucket(dht_routing_bucket t) {
|
||||
this.t = t;
|
||||
}
|
||||
|
||||
public dht_routing_bucket swig() {
|
||||
return t;
|
||||
}
|
||||
|
||||
/**
|
||||
* The total number of nodes in the routing table.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public int numNodes() {
|
||||
return t.getNum_nodes();
|
||||
}
|
||||
|
||||
/**
|
||||
* The total number of replacement nodes in the routing table.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public int numReplacements() {
|
||||
return t.getNum_replacements();
|
||||
}
|
||||
|
||||
/**
|
||||
* Number of seconds since last activity.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public int lastActive() {
|
||||
return t.getLast_active();
|
||||
}
|
||||
}
|
@ -0,0 +1,452 @@
|
||||
package com.frostwire.jlibtorrent;
|
||||
|
||||
import com.frostwire.jlibtorrent.swig.dht_settings;
|
||||
|
||||
/**
|
||||
* Structure used to hold configuration options for the DHT.
|
||||
*
|
||||
* @author gubatron
|
||||
* @author aldenml
|
||||
*/
|
||||
public final class DhtSettings {
|
||||
|
||||
private final dht_settings s;
|
||||
|
||||
public DhtSettings(dht_settings s) {
|
||||
this.s = s;
|
||||
}
|
||||
|
||||
public DhtSettings() {
|
||||
this(new dht_settings());
|
||||
}
|
||||
|
||||
public dht_settings swig() {
|
||||
return s;
|
||||
}
|
||||
|
||||
/**
|
||||
* the maximum number of peers to send in a reply to ``get_peers``.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public int maxPeersReply() {
|
||||
return s.getMax_peers_reply();
|
||||
}
|
||||
|
||||
/**
|
||||
* the maximum number of peers to send in a reply to ``get_peers``.
|
||||
*
|
||||
* @param value
|
||||
*/
|
||||
public void maxPeersReply(int value) {
|
||||
s.setMax_peers_reply(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* the number of concurrent search request the node will send when
|
||||
* announcing and refreshing the routing table. This parameter is called
|
||||
* alpha in the kademlia paper.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public int getSearchBranching() {
|
||||
return s.getSearch_branching();
|
||||
}
|
||||
|
||||
/**
|
||||
* the number of concurrent search request the node will send when
|
||||
* announcing and refreshing the routing table. This parameter is called
|
||||
* alpha in the kademlia paper.
|
||||
*
|
||||
* @param value
|
||||
*/
|
||||
public void setSearchBranching(int value) {
|
||||
s.setSearch_branching(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* the maximum number of failed tries to contact a node before it is
|
||||
* removed from the routing table. If there are known working nodes that
|
||||
* are ready to replace a failing node, it will be replaced immediately,
|
||||
* this limit is only used to clear out nodes that don't have any node
|
||||
* that can replace them.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public int getMaxFailCount() {
|
||||
return s.getMax_fail_count();
|
||||
}
|
||||
|
||||
/**
|
||||
* the maximum number of failed tries to contact a node before it is
|
||||
* removed from the routing table. If there are known working nodes that
|
||||
* are ready to replace a failing node, it will be replaced immediately,
|
||||
* this limit is only used to clear out nodes that don't have any node
|
||||
* that can replace them.
|
||||
*
|
||||
* @param value
|
||||
*/
|
||||
public void setMaxFailCount(int value) {
|
||||
s.setMax_fail_count(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* the total number of torrents to track from the DHT. This is simply an
|
||||
* upper limit to make sure malicious DHT nodes cannot make us allocate
|
||||
* an unbounded amount of memory.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public int maxTorrents() {
|
||||
return s.getMax_torrents();
|
||||
}
|
||||
|
||||
/**
|
||||
* the total number of torrents to track from the DHT. This is simply an
|
||||
* upper limit to make sure malicious DHT nodes cannot make us allocate
|
||||
* an unbounded amount of memory.
|
||||
*
|
||||
* @param value
|
||||
*/
|
||||
public void maxTorrents(int value) {
|
||||
s.setMax_torrents(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* max number of items the DHT will store.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public int maxDhtItems() {
|
||||
return s.getMax_dht_items();
|
||||
}
|
||||
|
||||
/**
|
||||
* max number of items the DHT will store.
|
||||
*
|
||||
* @param value
|
||||
*/
|
||||
public void maxDhtItems(int value) {
|
||||
s.setMax_dht_items(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* The max number of peers to store per torrent (for the DHT).
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public int maxPeers() {
|
||||
return s.getMax_peers();
|
||||
}
|
||||
|
||||
/**
|
||||
* The max number of peers to store per torrent (for the DHT).
|
||||
*
|
||||
* @param value
|
||||
*/
|
||||
public void maxPeers(int value) {
|
||||
s.setMax_peers(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* the max number of torrents to return in a torrent search query to the
|
||||
* DHT.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public int getMaxTorrentSearchReply() {
|
||||
return s.getMax_torrent_search_reply();
|
||||
}
|
||||
|
||||
/**
|
||||
* the max number of torrents to return in a torrent search query to the
|
||||
* DHT.
|
||||
*
|
||||
* @param value
|
||||
*/
|
||||
public void setMaxTorrentSearchReply(int value) {
|
||||
s.setMax_torrent_search_reply(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* determines if the routing table entries should restrict entries to one
|
||||
* per IP. This defaults to true, which helps mitigate some attacks on
|
||||
* the DHT. It prevents adding multiple nodes with IPs with a very close
|
||||
* CIDR distance.
|
||||
* <p>
|
||||
* when set, nodes whose IP address that's in the same /24 (or /64 for
|
||||
* IPv6) range in the same routing table bucket. This is an attempt to
|
||||
* mitigate node ID spoofing attacks also restrict any IP to only have a
|
||||
* single entry in the whole routing table.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public boolean isRestrictRoutingIPs() {
|
||||
return s.getRestrict_routing_ips();
|
||||
}
|
||||
|
||||
/**
|
||||
* determines if the routing table entries should restrict entries to one
|
||||
* per IP. This defaults to true, which helps mitigate some attacks on
|
||||
* the DHT. It prevents adding multiple nodes with IPs with a very close
|
||||
* CIDR distance.
|
||||
* <p>
|
||||
* when set, nodes whose IP address that's in the same /24 (or /64 for
|
||||
* IPv6) range in the same routing table bucket. This is an attempt to
|
||||
* mitigate node ID spoofing attacks also restrict any IP to only have a
|
||||
* single entry in the whole routing table.
|
||||
*
|
||||
* @param value
|
||||
*/
|
||||
public void setRestrictRoutingIPs(boolean value) {
|
||||
s.setRestrict_routing_ips(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* determines if DHT searches should prevent adding nodes with IPs with
|
||||
* very close CIDR distance. This also defaults to true and helps
|
||||
* mitigate certain attacks on the DHT.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public boolean isRestrictSearchIPs() {
|
||||
return s.getRestrict_search_ips();
|
||||
}
|
||||
|
||||
/**
|
||||
* determines if DHT searches should prevent adding nodes with IPs with
|
||||
* very close CIDR distance. This also defaults to true and helps
|
||||
* mitigate certain attacks on the DHT.
|
||||
*
|
||||
* @param value
|
||||
*/
|
||||
public void setRestrictSearchIPs(boolean value) {
|
||||
s.setRestrict_search_ips(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* makes the first buckets in the DHT routing table fit 128, 64, 32 and
|
||||
* 16 nodes respectively, as opposed to the standard size of 8. All other
|
||||
* buckets have size 8 still.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public boolean isExtendedRoutingTable() {
|
||||
return s.getExtended_routing_table();
|
||||
}
|
||||
|
||||
/**
|
||||
* makes the first buckets in the DHT routing table fit 128, 64, 32 and
|
||||
* 16 nodes respectively, as opposed to the standard size of 8. All other
|
||||
* buckets have size 8 still.
|
||||
*
|
||||
* @param value
|
||||
*/
|
||||
public void setExtendedRoutingTable(boolean value) {
|
||||
s.setExtended_routing_table(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* slightly changes the lookup behavior in terms of how many outstanding
|
||||
* requests we keep. Instead of having branch factor be a hard limit, we
|
||||
* always keep *branch factor* outstanding requests to the closest nodes.
|
||||
* i.e. every time we get results back with closer nodes, we query them
|
||||
* right away. It lowers the lookup times at the cost of more outstanding
|
||||
* queries.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public boolean isAggressiveLookups() {
|
||||
return s.getAggressive_lookups();
|
||||
}
|
||||
|
||||
/**
|
||||
* slightly changes the lookup behavior in terms of how many outstanding
|
||||
* requests we keep. Instead of having branch factor be a hard limit, we
|
||||
* always keep *branch factor* outstanding requests to the closest nodes.
|
||||
* i.e. every time we get results back with closer nodes, we query them
|
||||
* right away. It lowers the lookup times at the cost of more outstanding
|
||||
* queries.
|
||||
*
|
||||
* @param value
|
||||
*/
|
||||
public void getAggressiveLookups(boolean value) {
|
||||
s.setAggressive_lookups(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* when set, perform lookups in a way that is slightly more expensive,
|
||||
* but which minimizes the amount of information leaked about you.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public boolean isPrivacyLookups() {
|
||||
return s.getPrivacy_lookups();
|
||||
}
|
||||
|
||||
/**
|
||||
* when set, perform lookups in a way that is slightly more expensive,
|
||||
* but which minimizes the amount of information leaked about you.
|
||||
*
|
||||
* @param value
|
||||
*/
|
||||
public void setPrivacyLookups(boolean value) {
|
||||
s.setPrivacy_lookups(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* when set, node's whose IDs that are not correctly generated based on
|
||||
* its external IP are ignored. When a query arrives from such node, an
|
||||
* error message is returned with a message saying "invalid node ID".
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public boolean isEnforceNodeId() {
|
||||
return s.getEnforce_node_id();
|
||||
}
|
||||
|
||||
/**
|
||||
* when set, node's whose IDs that are not correctly generated based on
|
||||
* its external IP are ignored. When a query arrives from such node, an
|
||||
* error message is returned with a message saying "invalid node ID".
|
||||
*
|
||||
* @param value
|
||||
*/
|
||||
public void setEnforceNodeId(boolean value) {
|
||||
s.setEnforce_node_id(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* ignore DHT messages from parts of the internet we wouldn't expect to
|
||||
* see any traffic from
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public boolean isIgnoreDarkInternet() {
|
||||
return s.getIgnore_dark_internet();
|
||||
}
|
||||
|
||||
/**
|
||||
* ignore DHT messages from parts of the internet we wouldn't expect to
|
||||
* see any traffic from
|
||||
*
|
||||
* @param value
|
||||
*/
|
||||
public void setIgnoreDarkInternet(boolean value) {
|
||||
s.setIgnore_dark_internet(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* The number of seconds a DHT node is banned if it exceeds the rate
|
||||
* limit. The rate limit is averaged over 10 seconds to allow for bursts
|
||||
* above the limit.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public int blockTimeout() {
|
||||
return s.getBlock_timeout();
|
||||
}
|
||||
|
||||
/**
|
||||
* The number of seconds a DHT node is banned if it exceeds the rate
|
||||
* limit. The rate limit is averaged over 10 seconds to allow for bursts
|
||||
* above the limit.
|
||||
*
|
||||
* @param value
|
||||
*/
|
||||
public void blockTimeout(int value) {
|
||||
s.setBlock_timeout(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* The max number of packets per second a DHT node is allowed to send
|
||||
* without getting banned.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public int blockRatelimit() {
|
||||
return s.getBlock_ratelimit();
|
||||
}
|
||||
|
||||
/**
|
||||
* The max number of packets per second a DHT node is allowed to send
|
||||
* without getting banned.
|
||||
*
|
||||
* @param value
|
||||
*/
|
||||
public void blockRatelimit(int value) {
|
||||
s.setBlock_ratelimit(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* When set, the other nodes won't keep this node in their routing
|
||||
* tables, it's meant for low-power and/or ephemeral devices that
|
||||
* cannot support the DHT, it is also useful for mobile devices which
|
||||
* are sensitive to network traffic and battery life.
|
||||
* this node no longer responds to 'query' messages, and will place a
|
||||
* 'ro' key (value = 1) in the top-level message dictionary of outgoing
|
||||
* query messages.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public boolean readOnly() {
|
||||
return s.getRead_only();
|
||||
}
|
||||
|
||||
/**
|
||||
* When set, the other nodes won't keep this node in their routing
|
||||
* tables, it's meant for low-power and/or ephemeral devices that
|
||||
* cannot support the DHT, it is also useful for mobile devices which
|
||||
* are sensitive to network traffic and battery life.
|
||||
* this node no longer responds to 'query' messages, and will place a
|
||||
* 'ro' key (value = 1) in the top-level message dictionary of outgoing
|
||||
* query messages.
|
||||
*
|
||||
* @param value
|
||||
*/
|
||||
public void readOnly(boolean value) {
|
||||
s.setRead_only(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* The number of seconds a immutable/mutable item will be expired.
|
||||
* default is 0, means never expires.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public int itemLifetime() {
|
||||
return s.getItem_lifetime();
|
||||
}
|
||||
|
||||
/**
|
||||
* The number of seconds a immutable/mutable item will be expired.
|
||||
* default is 0, means never expires.
|
||||
*
|
||||
* @param value
|
||||
*/
|
||||
public void itemLifetime(int value) {
|
||||
s.setItem_lifetime(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* The number of bytes per second (on average) the DHT is allowed to send.
|
||||
* If the incoming requests causes to many bytes to be sent in responses,
|
||||
* incoming requests will be dropped until the quota has been replenished.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public int uploadRateLimit() {
|
||||
return s.getUpload_rate_limit();
|
||||
}
|
||||
|
||||
/**
|
||||
* The number of bytes per second (on average) the DHT is allowed to send.
|
||||
* If the incoming requests causes to many bytes to be sent in responses,
|
||||
* incoming requests will be dropped until the quota has been replenished.
|
||||
*
|
||||
* @param value
|
||||
*/
|
||||
public void uploadRateLimit(int value) {
|
||||
s.setUpload_rate_limit(value);
|
||||
}
|
||||
}
|
@ -0,0 +1,146 @@
|
||||
package com.frostwire.jlibtorrent;
|
||||
|
||||
import com.frostwire.jlibtorrent.swig.byte_vector;
|
||||
import com.frostwire.jlibtorrent.swig.byte_vectors_pair;
|
||||
|
||||
import static com.frostwire.jlibtorrent.swig.libtorrent.ed25519_add_scalar_public;
|
||||
import static com.frostwire.jlibtorrent.swig.libtorrent.ed25519_add_scalar_secret;
|
||||
import static com.frostwire.jlibtorrent.swig.libtorrent.ed25519_create_keypair;
|
||||
import static com.frostwire.jlibtorrent.swig.libtorrent.ed25519_create_seed;
|
||||
import static com.frostwire.jlibtorrent.swig.libtorrent.ed25519_key_exchange;
|
||||
import static com.frostwire.jlibtorrent.swig.libtorrent.ed25519_sign;
|
||||
import static com.frostwire.jlibtorrent.swig.libtorrent.ed25519_verify;
|
||||
|
||||
/**
|
||||
* @author gubatron
|
||||
* @author aldenml
|
||||
*/
|
||||
public final class Ed25519 {
|
||||
|
||||
public final static int SEED_SIZE = 32;
|
||||
public final static int PUBLIC_KEY_SIZE = 32;
|
||||
public final static int SECRET_KEY_SIZE = 64;
|
||||
public final static int SIGNATURE_SIZE = 64;
|
||||
public final static int SCALAR_SIZE = 32;
|
||||
public final static int SHARED_SECRET_SIZE = 32;
|
||||
|
||||
private Ed25519() {
|
||||
}
|
||||
|
||||
/**
|
||||
* @return
|
||||
*/
|
||||
public static byte[] createSeed() {
|
||||
byte_vector seed = ed25519_create_seed();
|
||||
|
||||
return Vectors.byte_vector2bytes(seed);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param seed
|
||||
* @return
|
||||
*/
|
||||
public static Pair<byte[], byte[]> createKeypair(byte[] seed) {
|
||||
if (seed == null || seed.length != SEED_SIZE) {
|
||||
throw new IllegalArgumentException("seed must be not null and of size " + SEED_SIZE);
|
||||
}
|
||||
|
||||
byte_vectors_pair keypair = ed25519_create_keypair(Vectors.bytes2byte_vector(seed));
|
||||
|
||||
return new Pair<>(Vectors.byte_vector2bytes(keypair.getFirst()),
|
||||
Vectors.byte_vector2bytes(keypair.getSecond()));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param message
|
||||
* @param publicKey
|
||||
* @param secretKey
|
||||
* @return
|
||||
*/
|
||||
public static byte[] sign(byte[] message, byte[] publicKey, byte[] secretKey) {
|
||||
if (publicKey == null || publicKey.length != PUBLIC_KEY_SIZE) {
|
||||
throw new IllegalArgumentException("public key must be not null and of size " + PUBLIC_KEY_SIZE);
|
||||
}
|
||||
if (secretKey == null || secretKey.length != SECRET_KEY_SIZE) {
|
||||
throw new IllegalArgumentException("secret key must be not null and of size " + SECRET_KEY_SIZE);
|
||||
}
|
||||
|
||||
byte_vector signature = ed25519_sign(Vectors.bytes2byte_vector(message),
|
||||
Vectors.bytes2byte_vector(publicKey),
|
||||
Vectors.bytes2byte_vector(secretKey));
|
||||
|
||||
return Vectors.byte_vector2bytes(signature);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param signature
|
||||
* @param message
|
||||
* @param publicKey
|
||||
* @return
|
||||
*/
|
||||
public static boolean verify(byte[] signature, byte[] message, byte[] publicKey) {
|
||||
if (signature == null || signature.length != SIGNATURE_SIZE) {
|
||||
throw new IllegalArgumentException("signature must be not null and of size " + SIGNATURE_SIZE);
|
||||
}
|
||||
if (publicKey == null || publicKey.length != PUBLIC_KEY_SIZE) {
|
||||
throw new IllegalArgumentException("public key must be not null and of size " + PUBLIC_KEY_SIZE);
|
||||
}
|
||||
return ed25519_verify(Vectors.bytes2byte_vector(signature),
|
||||
Vectors.bytes2byte_vector(message), Vectors.bytes2byte_vector(publicKey));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param publicKey
|
||||
* @param scalar
|
||||
* @return
|
||||
*/
|
||||
public static byte[] addScalarPublic(byte[] publicKey, byte[] scalar) {
|
||||
if (publicKey == null || publicKey.length != PUBLIC_KEY_SIZE) {
|
||||
throw new IllegalArgumentException("public key must be not null and of size " + PUBLIC_KEY_SIZE);
|
||||
}
|
||||
if (scalar == null || scalar.length != SCALAR_SIZE) {
|
||||
throw new IllegalArgumentException("scalar must be not null and of size " + SCALAR_SIZE);
|
||||
}
|
||||
|
||||
byte_vector ret = ed25519_add_scalar_public(Vectors.bytes2byte_vector(publicKey), Vectors.bytes2byte_vector(scalar));
|
||||
|
||||
return Vectors.byte_vector2bytes(ret);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param secretKey
|
||||
* @param scalar
|
||||
* @return
|
||||
*/
|
||||
public static byte[] addScalarSecret(byte[] secretKey, byte[] scalar) {
|
||||
if (secretKey == null || secretKey.length != SECRET_KEY_SIZE) {
|
||||
throw new IllegalArgumentException("public key must be not null and of size " + SECRET_KEY_SIZE);
|
||||
}
|
||||
if (scalar == null || scalar.length != SCALAR_SIZE) {
|
||||
throw new IllegalArgumentException("scalar must be not null and of size " + SCALAR_SIZE);
|
||||
}
|
||||
|
||||
byte_vector ret = ed25519_add_scalar_secret(Vectors.bytes2byte_vector(secretKey), Vectors.bytes2byte_vector(scalar));
|
||||
|
||||
return Vectors.byte_vector2bytes(ret);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param publicKey
|
||||
* @param secretKey
|
||||
* @return
|
||||
*/
|
||||
public byte[] keyExchange(byte[] publicKey, byte[] secretKey) {
|
||||
if (publicKey == null || publicKey.length != PUBLIC_KEY_SIZE) {
|
||||
throw new IllegalArgumentException("public key must be not null and of size " + PUBLIC_KEY_SIZE);
|
||||
}
|
||||
if (secretKey == null || secretKey.length != SECRET_KEY_SIZE) {
|
||||
throw new IllegalArgumentException("private key must be not null and of size " + SECRET_KEY_SIZE);
|
||||
}
|
||||
|
||||
byte_vector secret = ed25519_key_exchange(Vectors.bytes2byte_vector(publicKey),
|
||||
Vectors.bytes2byte_vector(secretKey));
|
||||
|
||||
return Vectors.byte_vector2bytes(secret);
|
||||
}
|
||||
}
|
@ -0,0 +1,226 @@
|
||||
package com.frostwire.jlibtorrent;
|
||||
|
||||
import com.frostwire.jlibtorrent.swig.entry;
|
||||
import com.frostwire.jlibtorrent.swig.entry_vector;
|
||||
import com.frostwire.jlibtorrent.swig.string_entry_map;
|
||||
import com.frostwire.jlibtorrent.swig.string_vector;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.AbstractList;
|
||||
import java.util.AbstractMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* The Entry class represents one node in a bencoded hierarchy. It works as a
|
||||
* variant type, it can be either a list, a dictionary, an integer
|
||||
* or a string.
|
||||
*
|
||||
* @author gubatron
|
||||
* @author aldenml
|
||||
*/
|
||||
public final class Entry {
|
||||
|
||||
private final entry e;
|
||||
|
||||
public Entry(entry e) {
|
||||
this.e = e;
|
||||
}
|
||||
|
||||
public Entry(String s) {
|
||||
this(new entry(s));
|
||||
}
|
||||
|
||||
public Entry(long n) {
|
||||
this(new entry(n));
|
||||
}
|
||||
|
||||
public static Entry bdecode(byte[] data) {
|
||||
return new Entry(entry.bdecode(Vectors.bytes2byte_vector(data)));
|
||||
}
|
||||
|
||||
public static Entry bdecode(File file) throws IOException {
|
||||
byte[] data = Files.bytes(file);
|
||||
return bdecode(data);
|
||||
}
|
||||
|
||||
public static Entry fromList(List<?> list) {
|
||||
entry e = new entry(entry.data_type.list_t);
|
||||
|
||||
entry_vector d = e.list();
|
||||
for (Object v : list) {
|
||||
if (v instanceof String) {
|
||||
d.push_back(new entry((String) v));
|
||||
} else if (v instanceof Integer) {
|
||||
d.push_back(new entry((Integer) v));
|
||||
} else if (v instanceof Entry) {
|
||||
d.push_back(((Entry) v).swig());
|
||||
} else if (v instanceof entry) {
|
||||
d.push_back((entry) v);
|
||||
} else if (v instanceof List) {
|
||||
d.push_back(fromList((List<?>) v).swig());
|
||||
} else if (v instanceof Map) {
|
||||
d.push_back(fromMap((Map<String, ?>) v).swig());
|
||||
} else {
|
||||
d.push_back(new entry(v.toString()));
|
||||
}
|
||||
}
|
||||
|
||||
return new Entry(e);
|
||||
}
|
||||
|
||||
public static Entry fromMap(Map<String, ?> map) {
|
||||
entry e = new entry(entry.data_type.dictionary_t);
|
||||
|
||||
string_entry_map d = e.dict();
|
||||
for (String k : map.keySet()) {
|
||||
Object v = map.get(k);
|
||||
|
||||
if (v instanceof String) {
|
||||
d.set(k, new entry((String) v));
|
||||
} else if (v instanceof Integer) {
|
||||
d.set(k, new entry((Integer) v));
|
||||
} else if (v instanceof Entry) {
|
||||
d.set(k, ((Entry) v).swig());
|
||||
} else if (v instanceof entry) {
|
||||
d.set(k, (entry) v);
|
||||
} else if (v instanceof List) {
|
||||
d.set(k, fromList((List<?>) v).swig());
|
||||
} else if (v instanceof Map) {
|
||||
d.set(k, fromMap((Map<String, ?>) v).swig());
|
||||
} else {
|
||||
d.set(k, new entry(v.toString()));
|
||||
}
|
||||
}
|
||||
|
||||
return new Entry(e);
|
||||
}
|
||||
|
||||
public entry swig() {
|
||||
return e;
|
||||
}
|
||||
|
||||
public byte[] bencode() {
|
||||
return Vectors.byte_vector2bytes(e.bencode());
|
||||
}
|
||||
|
||||
public String string() {
|
||||
return e.string();
|
||||
}
|
||||
|
||||
public long integer() {
|
||||
return e.integer();
|
||||
}
|
||||
|
||||
public List<Entry> list() {
|
||||
return new EntryList(e.list());
|
||||
}
|
||||
|
||||
public Map<String, Entry> dictionary() {
|
||||
return new EntryMap(e.dict());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return e.to_string();
|
||||
}
|
||||
|
||||
private static final class EntryList extends AbstractList<Entry> {
|
||||
|
||||
private final entry_vector v;
|
||||
|
||||
public EntryList(entry_vector v) {
|
||||
this.v = v;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Entry get(int index) {
|
||||
return new Entry(v.get(index));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean add(Entry entry) {
|
||||
v.push_back(entry.swig());
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return (int) v.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
v.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return v.empty();
|
||||
}
|
||||
}
|
||||
|
||||
private static final class EntryMap extends AbstractMap<String, Entry> {
|
||||
|
||||
private final string_entry_map m;
|
||||
|
||||
public EntryMap(string_entry_map m) {
|
||||
this.m = m;
|
||||
}
|
||||
|
||||
@Override
|
||||
public com.frostwire.jlibtorrent.Entry get(Object key) {
|
||||
String k = key.toString();
|
||||
return m.has_key(k) ? new com.frostwire.jlibtorrent.Entry(m.get(key.toString())) : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public com.frostwire.jlibtorrent.Entry put(String key, com.frostwire.jlibtorrent.Entry value) {
|
||||
com.frostwire.jlibtorrent.Entry r = get(key);
|
||||
m.set(key, value.swig());
|
||||
return r;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return (int) m.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
m.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsKey(Object key) {
|
||||
return m.has_key(key.toString());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return m.empty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> keySet() {
|
||||
HashSet<String> s = new HashSet<>();
|
||||
|
||||
string_vector v = m.keys();
|
||||
int size = (int) v.size();
|
||||
|
||||
for (int i = 0; i < size; i++) {
|
||||
s.add(v.get(i));
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<Entry<String, com.frostwire.jlibtorrent.Entry>> entrySet() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,182 @@
|
||||
/*
|
||||
* Created by Angel Leon (@gubatron), Alden Torres (aldenml)
|
||||
*
|
||||
* Licensed under the MIT License.
|
||||
*/
|
||||
|
||||
package com.frostwire.jlibtorrent;
|
||||
|
||||
import com.frostwire.jlibtorrent.swig.ip_interface;
|
||||
import com.frostwire.jlibtorrent.swig.ip_interface_vector;
|
||||
import com.frostwire.jlibtorrent.swig.ip_route;
|
||||
import com.frostwire.jlibtorrent.swig.ip_route_vector;
|
||||
import com.frostwire.jlibtorrent.swig.libtorrent;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author gubatron
|
||||
* @author aldenml
|
||||
*/
|
||||
public final class EnumNet {
|
||||
|
||||
private EnumNet() {
|
||||
}
|
||||
|
||||
public static List<IpInterface> enumInterfaces(SessionManager session) {
|
||||
if (session.swig() == null) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
ip_interface_vector v = libtorrent.enum_net_interfaces(session.swig());
|
||||
int size = (int) v.size();
|
||||
ArrayList<IpInterface> l = new ArrayList<>(size);
|
||||
|
||||
for (int i = 0; i < size; i++) {
|
||||
l.add(new IpInterface(v.get(i)));
|
||||
}
|
||||
|
||||
return l;
|
||||
}
|
||||
|
||||
public static List<IpRoute> enumRoutes(SessionManager session) {
|
||||
if (session.swig() == null) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
ip_route_vector v = libtorrent.enum_routes(session.swig());
|
||||
int size = (int) v.size();
|
||||
ArrayList<IpRoute> l = new ArrayList<>(size);
|
||||
|
||||
for (int i = 0; i < size; i++) {
|
||||
l.add(new IpRoute(v.get(i)));
|
||||
}
|
||||
|
||||
return l;
|
||||
}
|
||||
|
||||
public static Address getGateway(SessionManager session, IpInterface ipInterface, ip_route_vector routes) {
|
||||
return new Address(libtorrent.get_gateway(ipInterface.swig(), routes));
|
||||
}
|
||||
|
||||
public static final class IpInterface {
|
||||
|
||||
private final Address interfaceAddress;
|
||||
private final Address netmask;
|
||||
private final String name;
|
||||
private final String friendlyName;
|
||||
private final String description;
|
||||
private final boolean preferred;
|
||||
private final ip_interface s;
|
||||
|
||||
IpInterface(ip_interface iface) {
|
||||
this.s = iface;
|
||||
this.interfaceAddress = new Address(iface.getInterface_address());
|
||||
this.netmask = new Address(iface.getNetmask());
|
||||
this.name = Vectors.byte_vector2ascii(iface.getName());
|
||||
this.friendlyName = Vectors.byte_vector2ascii(iface.getFriendly_name());
|
||||
this.description = Vectors.byte_vector2ascii(iface.getDescription());
|
||||
this.preferred = iface.getPreferred();
|
||||
}
|
||||
|
||||
public ip_interface swig() {
|
||||
return s;
|
||||
}
|
||||
|
||||
public Address interfaceAddress() {
|
||||
return interfaceAddress;
|
||||
}
|
||||
|
||||
public Address netmask() {
|
||||
return netmask;
|
||||
}
|
||||
|
||||
public String name() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public String friendlyName() {
|
||||
return friendlyName;
|
||||
}
|
||||
|
||||
public String description() {
|
||||
return description;
|
||||
}
|
||||
|
||||
public boolean preferred() {
|
||||
return preferred;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
sb.append("address: ").append(interfaceAddress);
|
||||
sb.append(", netmask: ").append(netmask);
|
||||
sb.append(", name: ").append(name);
|
||||
sb.append(", friendlyName: ").append(friendlyName);
|
||||
sb.append(", description: ").append(description);
|
||||
sb.append(", preferred: ").append(preferred);
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
|
||||
public static final class IpRoute {
|
||||
|
||||
private final Address destination;
|
||||
private final Address netmask;
|
||||
private final Address gateway;
|
||||
private final String name;
|
||||
private final int mtu;
|
||||
private final ip_route s;
|
||||
|
||||
IpRoute(ip_route route) {
|
||||
this.s = route;
|
||||
this.destination = new Address(route.getDestination());
|
||||
this.netmask = new Address(route.getNetmask());
|
||||
this.gateway = new Address(route.getGateway());
|
||||
this.name = Vectors.byte_vector2ascii(route.getName());
|
||||
this.mtu = route.getMtu();
|
||||
}
|
||||
|
||||
public ip_route swig() {
|
||||
return this.s;
|
||||
}
|
||||
|
||||
public Address destination() {
|
||||
return destination;
|
||||
}
|
||||
|
||||
public Address netmask() {
|
||||
return netmask;
|
||||
}
|
||||
|
||||
public Address gateway() {
|
||||
return gateway;
|
||||
}
|
||||
|
||||
public String name() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public int mtu() {
|
||||
return mtu;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
sb.append("destination: ").append(destination);
|
||||
sb.append(", netmask: ").append(netmask);
|
||||
sb.append(", gateway: ").append(gateway);
|
||||
sb.append(", name: ").append(name);
|
||||
sb.append(", mtu: ").append(mtu);
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,50 @@
|
||||
package com.frostwire.jlibtorrent;
|
||||
|
||||
import com.frostwire.jlibtorrent.swig.error_code;
|
||||
|
||||
/**
|
||||
* @author gubatron
|
||||
* @author aldenml
|
||||
*/
|
||||
public final class ErrorCode {
|
||||
|
||||
private int value;
|
||||
private String message;
|
||||
private boolean isError;
|
||||
|
||||
/**
|
||||
* @param ec the native object
|
||||
*/
|
||||
public ErrorCode(error_code ec) {
|
||||
assign(ec);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the internal error code value
|
||||
*/
|
||||
public int value() {
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the error message
|
||||
*/
|
||||
public String message() {
|
||||
return message;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns if this error code actually represents an error.
|
||||
*
|
||||
* @return true if an actual error
|
||||
*/
|
||||
public boolean isError() {
|
||||
return isError;
|
||||
}
|
||||
|
||||
void assign(error_code ec) {
|
||||
value = ec.value();
|
||||
message = ec.message();
|
||||
isError = ec.op_bool();
|
||||
}
|
||||
}
|
@ -0,0 +1,66 @@
|
||||
package com.frostwire.jlibtorrent;
|
||||
|
||||
import com.frostwire.jlibtorrent.swig.file_slice;
|
||||
|
||||
/**
|
||||
* Represents a window of a file in a torrent.
|
||||
* <p>
|
||||
* The {@link #fileIndex()} refers to the index of the file (in the {@link com.frostwire.jlibtorrent.TorrentInfo}).
|
||||
* To get the path and filename, use {@link TorrentInfo#files()}. The {@link #offset()} is the byte offset in the
|
||||
* file where the range starts, and {@link #size()} is the number of bytes this range is. The {@code size + offset}
|
||||
* will never be greater than the file size.
|
||||
* <p>
|
||||
* Implementation note: This class does not store internally a reference to the native swig
|
||||
* {@link com.frostwire.jlibtorrent.swig.file_slice}. This is because we are dealing with only three integral
|
||||
* values and we want to avoid keeping a reference to a memory in the native heap.
|
||||
*
|
||||
* @author gubatron
|
||||
* @author aldenml
|
||||
*/
|
||||
public final class FileSlice {
|
||||
|
||||
private final int fileIndex;
|
||||
private final long offset;
|
||||
private final long size;
|
||||
|
||||
/**
|
||||
* @param fs the native object
|
||||
*/
|
||||
public FileSlice(file_slice fs) {
|
||||
this.fileIndex = fs.getFile_index();
|
||||
this.offset = fs.getOffset();
|
||||
this.size = fs.getSize();
|
||||
}
|
||||
|
||||
/**
|
||||
* The index of the file.
|
||||
*
|
||||
* @return the index
|
||||
*/
|
||||
public int fileIndex() {
|
||||
return fileIndex;
|
||||
}
|
||||
|
||||
/**
|
||||
* The offset from the start of the file, in bytes.
|
||||
*
|
||||
* @return the offset
|
||||
*/
|
||||
public long offset() {
|
||||
return offset;
|
||||
}
|
||||
|
||||
/**
|
||||
* The size of the window, in bytes.
|
||||
*
|
||||
* @return the size
|
||||
*/
|
||||
public long size() {
|
||||
return size;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format("FileSlice(fileIndex: %d, offset: %d, size: %d)", fileIndex, offset, size);
|
||||
}
|
||||
}
|
@ -0,0 +1,471 @@
|
||||
package com.frostwire.jlibtorrent;
|
||||
|
||||
import com.frostwire.jlibtorrent.swig.byte_vector;
|
||||
import com.frostwire.jlibtorrent.swig.file_flags_t;
|
||||
import com.frostwire.jlibtorrent.swig.file_slice_vector;
|
||||
import com.frostwire.jlibtorrent.swig.file_storage;
|
||||
import com.frostwire.jlibtorrent.swig.string_vector;
|
||||
import com.frostwire.jlibtorrent.swig.torrent_info;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
|
||||
/**
|
||||
* This class represents a file list and the piece
|
||||
* size. Everything necessary to interpret a regular bittorrent storage
|
||||
* file structure.
|
||||
*
|
||||
* @author gubatron
|
||||
* @author aldenml
|
||||
*/
|
||||
public final class FileStorage {
|
||||
|
||||
/**
|
||||
* This file is a pad file. The creator of the
|
||||
* torrent promises the file is entirely filled with
|
||||
* zeroes and does not need to be downloaded. The
|
||||
* purpose is just to align the next file to either
|
||||
* a block or piece boundary.
|
||||
*/
|
||||
public static final file_flags_t FLAG_PAD_FILE = file_storage.flag_pad_file;
|
||||
/**
|
||||
* This file is hidden (sets the hidden attribute
|
||||
* on windows).
|
||||
*/
|
||||
public static final file_flags_t FLAG_HIDDEN = file_storage.flag_hidden;
|
||||
/**
|
||||
* This file is executable (sets the executable bit
|
||||
* on posix like systems).
|
||||
*/
|
||||
public static final file_flags_t FLAG_EXECUTABLE = file_storage.flag_executable;
|
||||
/**
|
||||
* This file is a symlink. The symlink target is
|
||||
* specified in a separate field
|
||||
*/
|
||||
public static final file_flags_t FLAG_SYMLINK = file_storage.flag_symlink;
|
||||
private final file_storage fs;
|
||||
private final torrent_info ti;
|
||||
|
||||
/**
|
||||
* @param fs the native object
|
||||
*/
|
||||
public FileStorage(file_storage fs) {
|
||||
this(fs, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to keep the torrent info reference around.
|
||||
*
|
||||
* @param fs the native object
|
||||
* @param ti the torrent info to pin
|
||||
*/
|
||||
FileStorage(file_storage fs, torrent_info ti) {
|
||||
this.fs = fs;
|
||||
this.ti = ti;
|
||||
}
|
||||
|
||||
static ArrayList<FileSlice> mapBlock(file_slice_vector v) {
|
||||
int size = (int) v.size();
|
||||
|
||||
ArrayList<FileSlice> l = new ArrayList<>(size);
|
||||
for (int i = 0; i < size; i++) {
|
||||
l.add(new FileSlice(v.get(i)));
|
||||
}
|
||||
|
||||
return l;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the native object
|
||||
*/
|
||||
public file_storage swig() {
|
||||
return fs;
|
||||
}
|
||||
|
||||
/**
|
||||
* This methods returns the internal torrent info or null
|
||||
* if it was constructed without one.
|
||||
* <p>
|
||||
* This also prevent premature garbage collection in case
|
||||
* the storage was created from a torrent info.
|
||||
*
|
||||
* @return the pinned torrent info
|
||||
*/
|
||||
public torrent_info ti() {
|
||||
return ti;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the piece length has been initialized
|
||||
* on the file_storage. This is typically taken as a proxy
|
||||
* of whether the file_storage as a whole is initialized or
|
||||
* not.
|
||||
*
|
||||
* @return true if valid
|
||||
*/
|
||||
public boolean isValid() {
|
||||
return fs.is_valid();
|
||||
}
|
||||
|
||||
/**
|
||||
* Allocates space for {@code numFiles} in the internal file list. This can
|
||||
* be used to avoid reallocating the internal file list when the number
|
||||
* of files to be added is known up-front.
|
||||
*
|
||||
* @param numFiles the number of files
|
||||
*/
|
||||
public void reserve(int numFiles) {
|
||||
fs.reserve(numFiles);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a file to the file storage. The {@code flags} argument sets attributes on the file.
|
||||
* The file attributes is an extension and may not work in all bittorrent clients.
|
||||
* <p>
|
||||
* If more files than one are added, certain restrictions to their paths apply.
|
||||
* In a multi-file file storage (torrent), all files must share the same root directory.
|
||||
* <p>
|
||||
* That is, the first path element of all files must be the same.
|
||||
* This shared path element is also set to the name of the torrent. It
|
||||
* can be changed by calling {@link #name(String)}.
|
||||
* <p>
|
||||
* The built in functions to traverse a directory to add files will
|
||||
* make sure this requirement is fulfilled.
|
||||
*
|
||||
* @param path the path
|
||||
* @param size the file size
|
||||
* @param flags the file flags
|
||||
* @param mtime the time
|
||||
* @param symlink the symlink
|
||||
*/
|
||||
public void addFile(String path, long size, file_flags_t flags, int mtime, String symlink) {
|
||||
fs.add_file(path, size, flags, mtime, symlink);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a file to the file storage. The {@code flags} argument sets attributes on the file.
|
||||
* The file attributes is an extension and may not work in all bittorrent clients.
|
||||
* <p>
|
||||
* If more files than one are added, certain restrictions to their paths apply.
|
||||
* In a multi-file file storage (torrent), all files must share the same root directory.
|
||||
* <p>
|
||||
* That is, the first path element of all files must be the same.
|
||||
* This shared path element is also set to the name of the torrent. It
|
||||
* can be changed by calling {@link #name(String)}.
|
||||
* <p>
|
||||
* The built in functions to traverse a directory to add files will
|
||||
* make sure this requirement is fulfilled.
|
||||
*
|
||||
* @param path the path
|
||||
* @param size the file size
|
||||
* @param flags the file flags
|
||||
* @param mtime the time
|
||||
*/
|
||||
public void addFile(String path, long size, file_flags_t flags, int mtime) {
|
||||
fs.add_file(path, size, flags, mtime);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a file to the file storage. The {@code flags} argument sets attributes on the file.
|
||||
* The file attributes is an extension and may not work in all bittorrent clients.
|
||||
* <p>
|
||||
* If more files than one are added, certain restrictions to their paths apply.
|
||||
* In a multi-file file storage (torrent), all files must share the same root directory.
|
||||
* <p>
|
||||
* That is, the first path element of all files must be the same.
|
||||
* This shared path element is also set to the name of the torrent. It
|
||||
* can be changed by calling {@link #name(String)}.
|
||||
* <p>
|
||||
* The built in functions to traverse a directory to add files will
|
||||
* make sure this requirement is fulfilled.
|
||||
*
|
||||
* @param path the path
|
||||
* @param size the file size
|
||||
* @param flags the file flags
|
||||
*/
|
||||
public void addFile(String path, long size, file_flags_t flags) {
|
||||
fs.add_file(path, size, flags);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a file to the file storage.
|
||||
* <p>
|
||||
* If more files than one are added, certain restrictions to their paths apply.
|
||||
* In a multi-file file storage (torrent), all files must share the same root directory.
|
||||
* <p>
|
||||
* That is, the first path element of all files must be the same.
|
||||
* This shared path element is also set to the name of the torrent. It
|
||||
* can be changed by calling {@link #name(String)}.
|
||||
* <p>
|
||||
* The built in functions to traverse a directory to add files will
|
||||
* make sure this requirement is fulfilled.
|
||||
*
|
||||
* @param p
|
||||
* @param size
|
||||
*/
|
||||
public void addFile(String p, long size) {
|
||||
fs.add_file(p, size);
|
||||
}
|
||||
|
||||
/**
|
||||
* Renames the file at {@code index} to {@code newFilename}. Keep in mind
|
||||
* that filenames are expected to be UTF-8 encoded.
|
||||
*
|
||||
* @param index
|
||||
* @param newFilename
|
||||
*/
|
||||
public void renameFile(int index, String newFilename) {
|
||||
fs.rename_file(index, newFilename);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of {@link com.frostwire.jlibtorrent.FileSlice} objects representing the portions of
|
||||
* files the specified piece index, byte offset and size range overlaps.
|
||||
* <p>
|
||||
* This is the inverse mapping of {@link #mapFile(int, long, int)}.
|
||||
*
|
||||
* @param piece
|
||||
* @param offset
|
||||
* @param size
|
||||
* @return
|
||||
*/
|
||||
public ArrayList<FileSlice> mapBlock(int piece, long offset, int size) {
|
||||
return mapBlock(fs.map_block(piece, offset, size));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@link com.frostwire.jlibtorrent.PeerRequest} representing the
|
||||
* piece index, byte offset and size the specified file range overlaps.
|
||||
* This is the inverse mapping of {@link #mapBlock(int, long, int)}.
|
||||
* <p>
|
||||
* Note that the {@link PeerRequest} return type
|
||||
* is meant to hold bittorrent block requests, which may not be larger
|
||||
* than 16 kiB. Mapping a range larger than that may return an overflown
|
||||
* integer.
|
||||
*
|
||||
* @param file
|
||||
* @param offset
|
||||
* @param size
|
||||
* @return
|
||||
*/
|
||||
public PeerRequest mapFile(int file, long offset, int size) {
|
||||
return new PeerRequest(fs.map_file(file, offset, size));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of files in the file_storage.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public int numFiles() {
|
||||
return fs.num_files();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the total number of bytes all the files in this torrent spans.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public long totalSize() {
|
||||
return fs.total_size();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of pieces in the torrent.
|
||||
*
|
||||
* @return the number of pieces in the torrent
|
||||
*/
|
||||
public int numPieces() {
|
||||
return fs.num_pieces();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the number of pieces in the torrent.
|
||||
*
|
||||
* @param n
|
||||
*/
|
||||
public void numPieces(int n) {
|
||||
fs.set_num_pieces(n);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the size of each piece in this torrent. This size is typically an even power
|
||||
* of 2. It doesn't have to be though. It should be divisible by 16kiB however.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public int pieceLength() {
|
||||
return fs.piece_length();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the size of each piece in this torrent. This size is typically an even power
|
||||
* of 2. It doesn't have to be though. It should be divisible by 16kiB however.
|
||||
*
|
||||
* @param l
|
||||
*/
|
||||
public void pieceLength(int l) {
|
||||
fs.set_piece_length(l);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the piece size of {@code index}. This will be the same as {@link #pieceLength()},
|
||||
* except for the last piece, which may be shorter.
|
||||
*
|
||||
* @param index
|
||||
* @return
|
||||
*/
|
||||
public int pieceSize(int index) {
|
||||
return fs.piece_size(index);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the name of this torrent. For multi-file torrents, this is also
|
||||
* the name of the root directory all the files are stored in.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public String name() {
|
||||
return fs.name();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the name of this torrent. For multi-file torrents, this is also
|
||||
* the name of the root directory all the files are stored in.
|
||||
*
|
||||
* @param name
|
||||
*/
|
||||
public void name(String name) {
|
||||
fs.set_name(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Is a sha-1 hash of the file, or 0 if none was
|
||||
* provided in the torrent file. This can potentially be used to
|
||||
* join a bittorrent network with other file sharing networks.
|
||||
*
|
||||
* @param index
|
||||
* @return
|
||||
*/
|
||||
public Sha1Hash hash(int index) {
|
||||
return new Sha1Hash(fs.hash(index));
|
||||
}
|
||||
|
||||
/**
|
||||
* returns the full path to a file.
|
||||
*
|
||||
* @param index
|
||||
* @param savePath
|
||||
* @return
|
||||
*/
|
||||
public String filePath(int index, String savePath) {
|
||||
// not calling the corresponding swig function because internally,
|
||||
// the use of the function GetStringUTFChars does not consider the case of
|
||||
// a copy not made
|
||||
return savePath + File.separator + fs.file_path(index);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the full path to a file.
|
||||
*
|
||||
* @param index the file index
|
||||
* @return the full path
|
||||
*/
|
||||
public String filePath(int index) {
|
||||
return fs.file_path(index);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns only the name of the file, whereas
|
||||
* {@link #filePath(int)} returns the path (inside the torrent file) with
|
||||
* the filename appended.
|
||||
*
|
||||
* @param index the file index
|
||||
* @return the file name
|
||||
*/
|
||||
public String fileName(int index) {
|
||||
byte_vector v = fs.file_name(index).to_bytes();
|
||||
return Vectors.byte_vector2utf8(v);
|
||||
}
|
||||
|
||||
/**
|
||||
* returns the size of a file.
|
||||
*
|
||||
* @param index
|
||||
* @return
|
||||
*/
|
||||
public long fileSize(int index) {
|
||||
return fs.file_size(index);
|
||||
}
|
||||
|
||||
/**
|
||||
* returns true if the file at the given
|
||||
* index is a pad-file.
|
||||
*
|
||||
* @param index
|
||||
* @return
|
||||
*/
|
||||
public boolean padFileAt(int index) {
|
||||
return fs.pad_file_at(index);
|
||||
}
|
||||
|
||||
/**
|
||||
* returns the byte offset within the torrent file
|
||||
* where this file starts. It can be used to map the file to a piece
|
||||
* index (given the piece size).
|
||||
*
|
||||
* @param index
|
||||
* @return
|
||||
*/
|
||||
public long fileOffset(int index) {
|
||||
return fs.file_offset(index);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return
|
||||
*/
|
||||
public ArrayList<String> paths() {
|
||||
string_vector v = fs.paths();
|
||||
int size = (int) v.size();
|
||||
ArrayList<String> l = new ArrayList<>(size);
|
||||
|
||||
for (int i = 0; i < size; i++) {
|
||||
l.add(v.get(i));
|
||||
}
|
||||
|
||||
return l;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a bitmask of flags from {@link file_flags_t} that apply
|
||||
* to file at {@code index}.
|
||||
*
|
||||
* @param index
|
||||
* @return the flags
|
||||
*/
|
||||
public file_flags_t fileFlags(int index) {
|
||||
return fs.file_flags(index);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the file at the specified index has been renamed to
|
||||
* have an absolute path, i.e. is not anchored in the save path of the
|
||||
* torrent.
|
||||
*
|
||||
* @param index
|
||||
* @return
|
||||
*/
|
||||
public boolean fileAbsolutePath(int index) {
|
||||
return fs.file_absolute_path(index);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the index of the file at the given offset in the torrent.
|
||||
*
|
||||
* @param offset
|
||||
* @return
|
||||
*/
|
||||
public int fileIndexAtOffset(long offset) {
|
||||
return fs.file_index_at_offset(offset);
|
||||
}
|
||||
}
|
@ -0,0 +1,206 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.frostwire.jlibtorrent;
|
||||
|
||||
import java.io.Closeable;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
final class Files {
|
||||
|
||||
private static final int EOF = -1;
|
||||
|
||||
private Files() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads the contents of a file into a byte array.
|
||||
* The file is always closed.
|
||||
*
|
||||
* @param file the file to read, must not be {@code null}
|
||||
* @return the file contents, never {@code null}
|
||||
* @throws IOException in case of an I/O error
|
||||
* @since 1.1
|
||||
*/
|
||||
public static byte[] bytes(File file) throws IOException {
|
||||
InputStream in = null;
|
||||
try {
|
||||
in = openInputStream(file);
|
||||
return toByteArray(in, file.length());
|
||||
} finally {
|
||||
closeQuietly(in);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens a {@link java.io.FileInputStream} for the specified file, providing better
|
||||
* error messages than simply calling <code>new FileInputStream(file)</code>.
|
||||
* <p>
|
||||
* At the end of the method either the stream will be successfully opened,
|
||||
* or an exception will have been thrown.
|
||||
* <p>
|
||||
* An exception is thrown if the file does not exist.
|
||||
* An exception is thrown if the file object exists but is a directory.
|
||||
* An exception is thrown if the file exists but cannot be read.
|
||||
*
|
||||
* @param file the file to open for input, must not be {@code null}
|
||||
* @return a new {@link java.io.FileInputStream} for the specified file
|
||||
* @throws java.io.FileNotFoundException if the file does not exist
|
||||
* @throws IOException if the file object is a directory
|
||||
* @throws IOException if the file cannot be read
|
||||
* @since 1.3
|
||||
*/
|
||||
private static FileInputStream openInputStream(File file) throws IOException {
|
||||
if (file.exists()) {
|
||||
if (file.isDirectory()) {
|
||||
throw new IOException("File '" + file + "' exists but is a directory");
|
||||
}
|
||||
if (file.canRead() == false) {
|
||||
throw new IOException("File '" + file + "' cannot be read");
|
||||
}
|
||||
} else {
|
||||
throw new FileNotFoundException("File '" + file + "' does not exist");
|
||||
}
|
||||
return new FileInputStream(file);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get contents of an <code>InputStream</code> as a <code>byte[]</code>.
|
||||
* Use this method instead of <code>toByteArray(InputStream)</code>
|
||||
* when <code>InputStream</code> size is known.
|
||||
* <b>NOTE:</b> the method checks that the length can safely be cast to an int without truncation
|
||||
* before using {@link #toByteArray(java.io.InputStream, int)} to read into the byte array.
|
||||
* (Arrays can have no more than Integer.MAX_VALUE entries anyway)
|
||||
*
|
||||
* @param input the <code>InputStream</code> to read from
|
||||
* @param size the size of <code>InputStream</code>
|
||||
* @return the requested byte array
|
||||
* @throws IOException if an I/O error occurs or <code>InputStream</code> size differ from parameter size
|
||||
* @throws IllegalArgumentException if size is less than zero or size is greater than Integer.MAX_VALUE
|
||||
* @see #toByteArray(java.io.InputStream, int)
|
||||
* @since 2.1
|
||||
*/
|
||||
private static byte[] toByteArray(InputStream input, long size) throws IOException {
|
||||
|
||||
if (size > Integer.MAX_VALUE) {
|
||||
throw new IllegalArgumentException("Size cannot be greater than Integer max value: " + size);
|
||||
}
|
||||
|
||||
return toByteArray(input, (int) size);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the contents of an <code>InputStream</code> as a <code>byte[]</code>.
|
||||
* Use this method instead of <code>toByteArray(InputStream)</code>
|
||||
* when <code>InputStream</code> size is known
|
||||
*
|
||||
* @param input the <code>InputStream</code> to read from
|
||||
* @param size the size of <code>InputStream</code>
|
||||
* @return the requested byte array
|
||||
* @throws java.io.IOException if an I/O error occurs or <code>InputStream</code> size differ from parameter size
|
||||
* @throws IllegalArgumentException if size is less than zero
|
||||
* @since 2.1
|
||||
*/
|
||||
private static byte[] toByteArray(InputStream input, int size) throws IOException {
|
||||
|
||||
if (size < 0) {
|
||||
throw new IllegalArgumentException("Size must be equal or greater than zero: " + size);
|
||||
}
|
||||
|
||||
if (size == 0) {
|
||||
return new byte[0];
|
||||
}
|
||||
|
||||
byte[] data = new byte[size];
|
||||
int offset = 0;
|
||||
int readed;
|
||||
|
||||
while (offset < size && (readed = input.read(data, offset, size - offset)) != EOF) {
|
||||
offset += readed;
|
||||
}
|
||||
|
||||
if (offset != size) {
|
||||
throw new IOException("Unexpected readed size. current: " + offset + ", excepted: " + size);
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Unconditionally close an <code>InputStream</code>.
|
||||
* <p>
|
||||
* Equivalent to {@link InputStream#close()}, except any exceptions will be ignored.
|
||||
* This is typically used in finally blocks.
|
||||
* <p>
|
||||
* Example code:
|
||||
* <pre>
|
||||
* byte[] data = new byte[1024];
|
||||
* InputStream in = null;
|
||||
* try {
|
||||
* in = new FileInputStream("foo.txt");
|
||||
* in.read(data);
|
||||
* in.close(); //close errors are handled
|
||||
* } catch (Exception e) {
|
||||
* // error handling
|
||||
* } finally {
|
||||
* IOUtils.closeQuietly(in);
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* @param input the InputStream to close, may be null or already closed
|
||||
*/
|
||||
static void closeQuietly(InputStream input) {
|
||||
closeQuietly((Closeable) input);
|
||||
}
|
||||
|
||||
/**
|
||||
* Unconditionally close a <code>Closeable</code>.
|
||||
* <p>
|
||||
* Equivalent to {@link java.io.Closeable#close()}, except any exceptions will be ignored.
|
||||
* This is typically used in finally blocks.
|
||||
* <p>
|
||||
* Example code:
|
||||
* <pre>
|
||||
* Closeable closeable = null;
|
||||
* try {
|
||||
* closeable = new FileReader("foo.txt");
|
||||
* // process closeable
|
||||
* closeable.close();
|
||||
* } catch (Exception e) {
|
||||
* // error handling
|
||||
* } finally {
|
||||
* IOUtils.closeQuietly(closeable);
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* @param closeable the object to close, may be null or already closed
|
||||
* @since 2.0
|
||||
*/
|
||||
static void closeQuietly(Closeable closeable) {
|
||||
try {
|
||||
if (closeable != null) {
|
||||
closeable.close();
|
||||
}
|
||||
} catch (IOException ioe) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,111 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.frostwire.jlibtorrent;
|
||||
|
||||
/**
|
||||
* Converts hexadecimal Strings.
|
||||
*/
|
||||
final class Hex {
|
||||
|
||||
/**
|
||||
* Used to build output as Hex
|
||||
*/
|
||||
private static final char[] DIGITS_LOWER =
|
||||
{'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
|
||||
|
||||
private Hex() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts an array of characters representing hexadecimal values into an array of bytes of those same values. The
|
||||
* returned array will be half the length of the passed array, as it takes two characters to represent any given
|
||||
* byte. An exception is thrown if the passed char array has an odd number of elements.
|
||||
*
|
||||
* @param data An array of characters containing hexadecimal digits
|
||||
* @return A byte array containing binary data decoded from the supplied char array.
|
||||
*/
|
||||
public static byte[] decode(final char[] data) {
|
||||
|
||||
final int len = data.length;
|
||||
|
||||
final byte[] out = new byte[len >> 1];
|
||||
|
||||
// two characters form the hex value.
|
||||
for (int i = 0, j = 0; j < len; i++) {
|
||||
int f = toDigit(data[j], j) << 4;
|
||||
j++;
|
||||
f = f | toDigit(data[j], j);
|
||||
j++;
|
||||
out[i] = (byte) (f & 0xFF);
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
public static byte[] decode(String data) {
|
||||
return decode(data.toCharArray());
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts an array of bytes into an array of characters representing the hexadecimal values of each byte in order.
|
||||
* The returned array will be double the length of the passed array, as it takes two characters to represent any
|
||||
* given byte.
|
||||
*
|
||||
* @param data a byte[] to convert to Hex characters
|
||||
* @return A char[] containing hexadecimal characters
|
||||
*/
|
||||
public static String encode(final byte[] data) {
|
||||
return new String(encode(data, DIGITS_LOWER));
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts an array of bytes into an array of characters representing the hexadecimal values of each byte in order.
|
||||
* The returned array will be double the length of the passed array, as it takes two characters to represent any
|
||||
* given byte.
|
||||
*
|
||||
* @param data a byte[] to convert to Hex characters
|
||||
* @param toDigits the output alphabet
|
||||
* @return A char[] containing hexadecimal characters
|
||||
* @since 1.4
|
||||
*/
|
||||
private static char[] encode(final byte[] data, final char[] toDigits) {
|
||||
final int l = data.length;
|
||||
final char[] out = new char[l << 1];
|
||||
// two characters form the hex value.
|
||||
for (int i = 0, j = 0; i < l; i++) {
|
||||
out[j++] = toDigits[(0xF0 & data[i]) >>> 4];
|
||||
out[j++] = toDigits[0x0F & data[i]];
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a hexadecimal character to an integer.
|
||||
*
|
||||
* @param ch A character to convert to an integer digit
|
||||
* @param index The index of the character in the source
|
||||
* @return An integer
|
||||
*/
|
||||
private static int toDigit(final char ch, final int index) {
|
||||
final int digit = Character.digit(ch, 16);
|
||||
if (digit == -1) {
|
||||
throw new IllegalArgumentException("Illegal hexadecimal character " + ch + " at index " + index);
|
||||
}
|
||||
return digit;
|
||||
}
|
||||
}
|
@ -0,0 +1,109 @@
|
||||
package com.frostwire.jlibtorrent;
|
||||
|
||||
/**
|
||||
* This is a limited capability data point series backed by
|
||||
* a circular buffer logic. Used to hold equally timed sample
|
||||
* of statistics.
|
||||
*
|
||||
* @author aldenml
|
||||
* @author gubatron
|
||||
*/
|
||||
public final class IntSeries {
|
||||
|
||||
private final long[] buffer;
|
||||
|
||||
private int head;
|
||||
private int end;
|
||||
private int size;
|
||||
|
||||
IntSeries(long[] buffer) {
|
||||
if (buffer == null) {
|
||||
throw new IllegalArgumentException("buffer to hold data can't be null");
|
||||
}
|
||||
if (buffer.length == 0) {
|
||||
throw new IllegalArgumentException("buffer to hold data can't be of size 0");
|
||||
}
|
||||
this.buffer = buffer;
|
||||
|
||||
head = -1;
|
||||
end = -1;
|
||||
size = 0;
|
||||
}
|
||||
|
||||
IntSeries(int capacity) {
|
||||
this(new long[capacity]);
|
||||
}
|
||||
|
||||
void add(long value) {
|
||||
if (head == -1) { // first element add
|
||||
head = end = 0;
|
||||
buffer[end] = value;
|
||||
size = 1;
|
||||
return;
|
||||
}
|
||||
|
||||
// update buffer and pointers
|
||||
end = (end + 1) % buffer.length;
|
||||
buffer[end] = value;
|
||||
if (end <= head) {
|
||||
head = (head + 1) % buffer.length;
|
||||
}
|
||||
|
||||
// update size
|
||||
if (head <= end) {
|
||||
size = 1 + (end - head);
|
||||
} else {
|
||||
size = buffer.length;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This method will always returns a value, but keep in mind that
|
||||
* due to the nature of the circular buffer internal logic, if you pass
|
||||
* past the size, you will get the sames values again.
|
||||
* Use {@link #size()} for a proper boundary check.
|
||||
* <p>
|
||||
* Usage example:
|
||||
* <pre>
|
||||
* {@code
|
||||
* for (int i = min(series.size(), desired_count); i >= 0; i--) {
|
||||
* plotMyValueAt(i, series.get(i));
|
||||
* }
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* @param index the value's index
|
||||
* @return the value in the series
|
||||
*/
|
||||
public long get(int index) {
|
||||
return buffer[(head + index) % size];
|
||||
}
|
||||
|
||||
/**
|
||||
* This method will always returns a value, if the series is empty
|
||||
* {@code 0} is returned.
|
||||
*
|
||||
* @return the last value in the series
|
||||
*/
|
||||
public long last() {
|
||||
return end != 0 ? buffer[end] : 0;
|
||||
}
|
||||
|
||||
public int size() {
|
||||
return size;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("[ ");
|
||||
for (int i = 0; i < buffer.length; i++) {
|
||||
sb.append(buffer[i]);
|
||||
if (i != buffer.length - 1) {
|
||||
sb.append(", ");
|
||||
}
|
||||
}
|
||||
sb.append(" ]");
|
||||
return "{ head: " + head + ", end: " + end + ", size: " + size() + ", buffer: " + sb.toString() + " }";
|
||||
}
|
||||
}
|
@ -0,0 +1,115 @@
|
||||
package com.frostwire.jlibtorrent;
|
||||
|
||||
import com.frostwire.jlibtorrent.swig.libtorrent;
|
||||
import com.frostwire.jlibtorrent.swig.libtorrent_jni;
|
||||
import com.frostwire.jlibtorrent.swig.stats_metric_vector;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author gubatron
|
||||
* @author aldenml
|
||||
*/
|
||||
public final class LibTorrent {
|
||||
|
||||
private LibTorrent() {
|
||||
}
|
||||
|
||||
/**
|
||||
* The version number as reported by libtorrent
|
||||
*
|
||||
* @return the version number
|
||||
*/
|
||||
public static int versionNum() {
|
||||
return libtorrent.LIBTORRENT_VERSION_NUM;
|
||||
}
|
||||
|
||||
/**
|
||||
* The version string as reported by libtorrent
|
||||
*
|
||||
* @return the version string
|
||||
*/
|
||||
public static String version() {
|
||||
return libtorrent.version();
|
||||
}
|
||||
|
||||
/**
|
||||
* The git revision of libtorrent the native library is using.
|
||||
* <p>
|
||||
* This is not the internal revision libtorrent reports, since
|
||||
* that string is updated from time to time. This library can be
|
||||
* using an up to date revision, this string is manually
|
||||
* hardcoded in each version of jlibtorrent. See
|
||||
* {@link libtorrent#LIBTORRENT_REVISION} for the libtorrent string.
|
||||
*
|
||||
* @return the git revision
|
||||
*/
|
||||
public static String revision() {
|
||||
return "b5bf6c3260bd726b0181671625c007be5ad49845";
|
||||
}
|
||||
|
||||
public static int boostVersionNum() {
|
||||
return libtorrent.boost_version();
|
||||
}
|
||||
|
||||
public static String boostVersion() {
|
||||
return libtorrent.boost_lib_version();
|
||||
}
|
||||
|
||||
public static int opensslVersionNum() {
|
||||
return libtorrent.openssl_version_number();
|
||||
}
|
||||
|
||||
public static String opensslVersion() {
|
||||
return libtorrent.openssl_version_text();
|
||||
}
|
||||
|
||||
public static String jlibtorrentVersion() {
|
||||
return libtorrent_jni.jlibtorrentVersion();
|
||||
}
|
||||
|
||||
/**
|
||||
* This free function returns the list of available metrics exposed by
|
||||
* libtorrent's statistics API. Each metric has a name and a *value index*.
|
||||
* The value index is the index into the array in session_stats_alert where
|
||||
* this metric's value can be found when the session stats is sampled (by
|
||||
* calling post_session_stats()).
|
||||
*
|
||||
* @return the list of all metrics
|
||||
*/
|
||||
public static List<StatsMetric> sessionStatsMetrics() {
|
||||
stats_metric_vector v = libtorrent.session_stats_metrics();
|
||||
int size = (int) v.size();
|
||||
|
||||
ArrayList<StatsMetric> l = new ArrayList<>(size);
|
||||
|
||||
for (int i = 0; i < size; i++) {
|
||||
l.add(new StatsMetric(v.get(i)));
|
||||
}
|
||||
|
||||
return l;
|
||||
}
|
||||
|
||||
/**
|
||||
* given a name of a metric, this function returns the counter index of it,
|
||||
* or -1 if it could not be found. The counter index is the index into the
|
||||
* values array returned by session_stats_alert.
|
||||
*
|
||||
* @param name the name of the metric
|
||||
* @return the index of the metric
|
||||
*/
|
||||
public static int findMetricIdx(String name) {
|
||||
return libtorrent.find_metric_idx_s(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* If the native library is an ARM architecture variant, returns true
|
||||
* if the running platform has NEON support.
|
||||
*
|
||||
* @return true if the running platform has NEON support
|
||||
*/
|
||||
public static boolean hasArmNeonSupport() {
|
||||
return libtorrent.arm_neon_support();
|
||||
}
|
||||
}
|
@ -0,0 +1,56 @@
|
||||
package com.frostwire.jlibtorrent;
|
||||
|
||||
import java.util.logging.Level;
|
||||
|
||||
import static java.util.logging.Level.INFO;
|
||||
|
||||
/**
|
||||
* @author gubatron
|
||||
* @author aldenml
|
||||
*/
|
||||
final class Logger {
|
||||
|
||||
private final java.util.logging.Logger jul;
|
||||
private final String name;
|
||||
|
||||
Logger(java.util.logging.Logger jul) {
|
||||
this.jul = jul;
|
||||
this.name = jul.getName();
|
||||
}
|
||||
|
||||
public static Logger getLogger(Class<?> clazz) {
|
||||
return new Logger(java.util.logging.Logger.getLogger(clazz.getName()));
|
||||
}
|
||||
|
||||
public void info(String msg) {
|
||||
jul.logp(INFO, name, "", msg);
|
||||
}
|
||||
|
||||
public void info(String msg, Throwable e) {
|
||||
jul.logp(Level.INFO, name, "", msg, e);
|
||||
}
|
||||
|
||||
public void warn(String msg) {
|
||||
jul.logp(INFO, name, "", msg);
|
||||
}
|
||||
|
||||
public void warn(String msg, Throwable e) {
|
||||
jul.logp(Level.INFO, name, "", msg, e);
|
||||
}
|
||||
|
||||
public void error(String msg) {
|
||||
jul.logp(INFO, name, "", msg);
|
||||
}
|
||||
|
||||
public void error(String msg, Throwable e) {
|
||||
jul.logp(Level.INFO, name, "", msg, e);
|
||||
}
|
||||
|
||||
public void debug(String msg) {
|
||||
jul.logp(INFO, name, "", msg);
|
||||
}
|
||||
|
||||
public void debug(String msg, Throwable e) {
|
||||
jul.logp(Level.INFO, name, "", msg, e);
|
||||
}
|
||||
}
|
@ -0,0 +1,62 @@
|
||||
package com.frostwire.jlibtorrent;
|
||||
|
||||
import com.frostwire.jlibtorrent.swig.move_flags_t;
|
||||
|
||||
/**
|
||||
* Flags for asynchronous move of a torrent handle storage.
|
||||
*
|
||||
* @author gubatron
|
||||
* @author aldenml
|
||||
* @see TorrentHandle#moveStorage(String, MoveFlags)
|
||||
*/
|
||||
public enum MoveFlags {
|
||||
|
||||
/**
|
||||
* Replace any files in the destination when copying
|
||||
* or moving the storage.
|
||||
*/
|
||||
ALWAYS_REPLACE_FILES(move_flags_t.always_replace_files),
|
||||
|
||||
/**
|
||||
* If any files that we want to copy exist in the destination,
|
||||
* fail the whole operation and don't perform
|
||||
* any copy or move. There is an inherent race condition
|
||||
* in this mode. The files are checked for existence before
|
||||
* the operation starts. In between the check and performing
|
||||
* the copy, the destination files may be created, in which
|
||||
* case they are replaced.
|
||||
*/
|
||||
FAIL_IF_EXIST(move_flags_t.fail_if_exist),
|
||||
|
||||
/**
|
||||
* If any files exist in the target, take those files instead
|
||||
* of the ones we may have in the source.
|
||||
*/
|
||||
DONT_REPLACE(move_flags_t.dont_replace);
|
||||
|
||||
private final move_flags_t swigValue;
|
||||
|
||||
MoveFlags(move_flags_t swigValue) {
|
||||
this.swigValue = swigValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param swigValue the native value
|
||||
*/
|
||||
public static MoveFlags fromSwig(move_flags_t swigValue) {
|
||||
MoveFlags[] enumValues = MoveFlags.class.getEnumConstants();
|
||||
for (MoveFlags ev : enumValues) {
|
||||
if (ev.swig() == swigValue) {
|
||||
return ev;
|
||||
}
|
||||
}
|
||||
throw new IllegalArgumentException("Enum value not supported");
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the native value
|
||||
*/
|
||||
public move_flags_t swig() {
|
||||
return swigValue;
|
||||
}
|
||||
}
|
@ -0,0 +1,254 @@
|
||||
package com.frostwire.jlibtorrent;
|
||||
|
||||
import com.frostwire.jlibtorrent.swig.libtorrent;
|
||||
import com.frostwire.jlibtorrent.swig.operation_t;
|
||||
|
||||
/**
|
||||
* These constants are used to identify the operation that failed, causing a
|
||||
* peer to disconnect.
|
||||
*
|
||||
* @author gubatron
|
||||
* @author aldenml
|
||||
*/
|
||||
public enum Operation {
|
||||
|
||||
/**
|
||||
* The error was unexpected and it is unknown which operation caused it.
|
||||
*/
|
||||
UNKNOWN(operation_t.unknown.swigValue()),
|
||||
|
||||
/**
|
||||
* This is used when the bittorrent logic determines to disconnect.
|
||||
*/
|
||||
BITTORRENT(operation_t.bittorrent.swigValue()),
|
||||
|
||||
/**
|
||||
* A call to iocontrol failed.
|
||||
*/
|
||||
IOCONTROL(operation_t.iocontrol.swigValue()),
|
||||
|
||||
/**
|
||||
* A call to getpeername failed (querying the remote IP of a connection).
|
||||
*/
|
||||
GETPEERNAME(operation_t.getpeername.swigValue()),
|
||||
|
||||
/**
|
||||
* A call to getname failed (querying the local IP of a connection).
|
||||
*/
|
||||
GETNAME(operation_t.getname.swigValue()),
|
||||
|
||||
/**
|
||||
* An attempt to allocate a receive buffer failed.
|
||||
*/
|
||||
ALLOC_RECVBUF(operation_t.alloc_recvbuf.swigValue()),
|
||||
|
||||
/**
|
||||
* An attempt to allocate a send buffer failed.
|
||||
*/
|
||||
ALLOC_SNDBUF(operation_t.alloc_sndbuf.swigValue()),
|
||||
|
||||
/**
|
||||
* Writing to a file failed.
|
||||
*/
|
||||
FILE_WRITE(operation_t.file_write.swigValue()),
|
||||
|
||||
/**
|
||||
* Reading from a file failed.
|
||||
*/
|
||||
FILE_READ(operation_t.file_read.swigValue()),
|
||||
|
||||
/**
|
||||
* A non-read and non-write file operation failed.
|
||||
*/
|
||||
FILE(operation_t.file.swigValue()),
|
||||
|
||||
/**
|
||||
* A socket write operation failed.
|
||||
*/
|
||||
SOCK_WRITE(operation_t.sock_write.swigValue()),
|
||||
|
||||
/**
|
||||
* A socket read operation failed.
|
||||
*/
|
||||
SOCK_READ(operation_t.sock_read.swigValue()),
|
||||
|
||||
/**
|
||||
* A call to open(), to create a socket socket failed.
|
||||
*/
|
||||
SOCK_OPEN(operation_t.sock_open.swigValue()),
|
||||
|
||||
/**
|
||||
* A call to bind() on a socket failed.
|
||||
*/
|
||||
SOCK_BIND(operation_t.sock_bind.swigValue()),
|
||||
|
||||
/**
|
||||
* An attempt to query the number of bytes available to read from a socket
|
||||
* failed.
|
||||
*/
|
||||
AVAILABLE(operation_t.available.swigValue()),
|
||||
|
||||
/**
|
||||
* A call related to bittorrent protocol encryption failed.
|
||||
*/
|
||||
ENCRYPTION(operation_t.encryption.swigValue()),
|
||||
|
||||
/**
|
||||
* An attempt to connect a socket failed.
|
||||
*/
|
||||
CONNECT(operation_t.connect.swigValue()),
|
||||
|
||||
/**
|
||||
* Establishing an SSL connection failed.
|
||||
*/
|
||||
SSL_HANDSHAKE(operation_t.ssl_handshake.swigValue()),
|
||||
|
||||
/**
|
||||
* A connection failed to satisfy the bind interface setting.
|
||||
*/
|
||||
GET_INTERFACE(operation_t.get_interface.swigValue()),
|
||||
|
||||
/**
|
||||
* A call to listen() on a socket.
|
||||
*/
|
||||
SOCK_LISTEN(operation_t.sock_listen.swigValue()),
|
||||
|
||||
/**
|
||||
* A call to the ioctl to bind a socket to a specific network device or
|
||||
* adaptor.
|
||||
*/
|
||||
SOCK_BIND_TO_DEVICE(operation_t.sock_bind_to_device.swigValue()),
|
||||
|
||||
/**
|
||||
* A call to accept() on a socket.
|
||||
*/
|
||||
SOCK_ACCEPT(operation_t.sock_accept.swigValue()),
|
||||
|
||||
/**
|
||||
* Convert a string into a valid network address.
|
||||
*/
|
||||
PARSE_ADDRESS(operation_t.parse_address.swigValue()),
|
||||
|
||||
/**
|
||||
* Enumeration network devices or adapters.
|
||||
*/
|
||||
ENUM_IF(operation_t.enum_if.swigValue()),
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
FILE_STAT(operation_t.file_stat.swigValue()),
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
FILE_COPY(operation_t.file_copy.swigValue()),
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
FILE_FALLOCATE(operation_t.file_fallocate.swigValue()),
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
FILE_HARD_LINK(operation_t.file_hard_link.swigValue()),
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
FILE_REMOVE(operation_t.file_remove.swigValue()),
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
FILE_RENAME(operation_t.file_rename.swigValue()),
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
FILE_OPEN(operation_t.file_open.swigValue()),
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
MKDIR(operation_t.mkdir.swigValue()),
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
CHECK_RESUME(operation_t.check_resume.swigValue()),
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
EXCEPTION(operation_t.exception.swigValue()),
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
ALLOC_CACHE_PIECE(operation_t.alloc_cache_piece.swigValue()),
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
PARTFILE_MOVE(operation_t.partfile_move.swigValue()),
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
PARTFILE_READ(operation_t.partfile_read.swigValue()),
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
PARTFILE_WRITE(operation_t.partfile_write.swigValue()),
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
HOSTNAME_LOOKUP(operation_t.hostname_lookup.swigValue());
|
||||
|
||||
private final int swigValue;
|
||||
|
||||
Operation(int swigValue) {
|
||||
this.swigValue = swigValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param swigValue the native value
|
||||
* @return the swig enum.
|
||||
*/
|
||||
public static Operation fromSwig(int swigValue) {
|
||||
Operation[] enumValues = Operation.class.getEnumConstants();
|
||||
for (Operation ev : enumValues) {
|
||||
if (ev.swig() == swigValue) {
|
||||
return ev;
|
||||
}
|
||||
}
|
||||
return UNKNOWN;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param swigValue the native enum
|
||||
* @return the swig enum.
|
||||
*/
|
||||
public static Operation fromSwig(operation_t swigValue) {
|
||||
return fromSwig(swigValue.swigValue());
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the native value.
|
||||
*/
|
||||
public int swig() {
|
||||
return swigValue;
|
||||
}
|
||||
|
||||
public String nativeName() {
|
||||
try {
|
||||
return libtorrent.operation_name(operation_t.swigToEnum(swigValue));
|
||||
} catch (Throwable e) {
|
||||
return "invalid enum value";
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,53 @@
|
||||
package com.frostwire.jlibtorrent;
|
||||
|
||||
import com.frostwire.jlibtorrent.swig.string_int_pair;
|
||||
import com.frostwire.jlibtorrent.swig.string_string_pair;
|
||||
|
||||
/**
|
||||
* Utility function to mirror the C++ std::pair class
|
||||
*
|
||||
* @author gubatron
|
||||
* @author aldenml
|
||||
*/
|
||||
public final class Pair<T1, T2> {
|
||||
|
||||
/**
|
||||
* the first element
|
||||
*/
|
||||
public final T1 first;
|
||||
/**
|
||||
* the second element
|
||||
*/
|
||||
public final T2 second;
|
||||
|
||||
/**
|
||||
* @param first first element
|
||||
* @param second second element
|
||||
*/
|
||||
public Pair(T1 first, T2 second) {
|
||||
this.first = first;
|
||||
this.second = second;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return a native object
|
||||
*/
|
||||
string_string_pair to_string_string_pair() {
|
||||
if (!String.class.equals(first.getClass()) || !String.class.equals(second.getClass())) {
|
||||
throw new IllegalArgumentException("Incompatible types");
|
||||
}
|
||||
|
||||
return new string_string_pair((String) first, (String) second);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return a native object
|
||||
*/
|
||||
string_int_pair to_string_int_pair() {
|
||||
if (!String.class.equals(first.getClass()) || !Integer.class.equals(second.getClass())) {
|
||||
throw new IllegalArgumentException("Incompatible types");
|
||||
}
|
||||
|
||||
return new string_int_pair((String) first, (Integer) second);
|
||||
}
|
||||
}
|
@ -0,0 +1,77 @@
|
||||
package com.frostwire.jlibtorrent;
|
||||
|
||||
import com.frostwire.jlibtorrent.swig.partial_piece_info;
|
||||
|
||||
/**
|
||||
* This class holds information about pieces that have outstanding
|
||||
* requests or outstanding writes.
|
||||
*
|
||||
* @author gubatron
|
||||
* @author aldenml
|
||||
*/
|
||||
public final class PartialPieceInfo {
|
||||
|
||||
private final partial_piece_info p;
|
||||
|
||||
/**
|
||||
* @param p the native object
|
||||
*/
|
||||
public PartialPieceInfo(partial_piece_info p) {
|
||||
this.p = p;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the native object
|
||||
*/
|
||||
public partial_piece_info swig() {
|
||||
return p;
|
||||
}
|
||||
|
||||
/**
|
||||
* The index of the piece in question. {@link #blocksInPiece()} is
|
||||
* the number of blocks in this particular piece. This number will
|
||||
* be the same for most pieces, but the last piece may have fewer
|
||||
* blocks than the standard pieces.
|
||||
*
|
||||
* @return the piece index
|
||||
*/
|
||||
public int pieceIndex() {
|
||||
return p.getPiece_index();
|
||||
}
|
||||
|
||||
/**
|
||||
* The number of blocks in this piece.
|
||||
*
|
||||
* @return the number of blocks
|
||||
*/
|
||||
public int blocksInPiece() {
|
||||
return p.getBlocks_in_piece();
|
||||
}
|
||||
|
||||
/**
|
||||
* The number of blocks that are in the finished state.
|
||||
*
|
||||
* @return the number of finished blocks
|
||||
*/
|
||||
public int finished() {
|
||||
return p.getFinished();
|
||||
}
|
||||
|
||||
/**
|
||||
* The number of blocks that are in the writing state.
|
||||
*
|
||||
* @return the number of blocks in writing state
|
||||
*/
|
||||
public int writing() {
|
||||
return p.getWriting();
|
||||
}
|
||||
|
||||
/**
|
||||
* The number of blocks that are in the requested state.
|
||||
*
|
||||
* @return the number of blocks in requested state
|
||||
*/
|
||||
public int requested() {
|
||||
return p.getRequested();
|
||||
}
|
||||
}
|
@ -0,0 +1,218 @@
|
||||
package com.frostwire.jlibtorrent;
|
||||
|
||||
import com.frostwire.jlibtorrent.swig.peer_info;
|
||||
|
||||
/**
|
||||
* Holds information and statistics about one peer
|
||||
* that libtorrent is connected to.
|
||||
* <p>
|
||||
* This class is a lightweight version of the native {@link peer_info}, and
|
||||
* only carries a subset of all the information. However, it's completely open
|
||||
* for custom use or optimization to accommodate client necessities.
|
||||
*
|
||||
* @author gubatron
|
||||
* @author aldenml
|
||||
*/
|
||||
public class PeerInfo {
|
||||
|
||||
protected String client;
|
||||
protected long totalDownload;
|
||||
protected long totalUpload;
|
||||
protected int flags;
|
||||
protected byte source;
|
||||
protected int upSpeed;
|
||||
protected int downSpeed;
|
||||
protected ConnectionType connectionType;
|
||||
protected float progress;
|
||||
protected int progressPpm;
|
||||
protected String ip;
|
||||
|
||||
public PeerInfo(peer_info p) {
|
||||
init(p);
|
||||
}
|
||||
|
||||
/**
|
||||
* This describe the software at the other end of the connection.
|
||||
* In some cases this information is not available, then it will contain
|
||||
* a string that may give away something about which software is running
|
||||
* in the other end. In the case of a web seed, the server type and
|
||||
* version will be a part of this string.
|
||||
*
|
||||
* @return the client string
|
||||
*/
|
||||
public String client() {
|
||||
return client;
|
||||
}
|
||||
|
||||
/**
|
||||
* The total number of bytes downloaded from this peer.
|
||||
* These numbers do not include the protocol chatter, but only the
|
||||
* payload data.
|
||||
*
|
||||
* @return number of bytes downloaded
|
||||
*/
|
||||
public long totalDownload() {
|
||||
return totalDownload;
|
||||
}
|
||||
|
||||
/**
|
||||
* The total number of bytes uploaded to this peer.
|
||||
* These numbers do not include the protocol chatter, but only the
|
||||
* payload data.
|
||||
*
|
||||
* @return number of bytes uploaded
|
||||
*/
|
||||
public long totalUpload() {
|
||||
return totalUpload;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tells you in which state the peer is in. It is set to
|
||||
* any combination of the peer_flags_t flags.
|
||||
*
|
||||
* @return the flags as an integer
|
||||
*/
|
||||
public int flags() {
|
||||
return flags;
|
||||
}
|
||||
|
||||
/**
|
||||
* A combination of flags describing from which sources this peer
|
||||
* was received. A combination of the peer_source_flags_t flags.
|
||||
*
|
||||
* @return the flags as a byte
|
||||
*/
|
||||
public byte source() {
|
||||
return source;
|
||||
}
|
||||
|
||||
/**
|
||||
* The current upload speed we have to and from this peer
|
||||
* (including any protocol messages). Updated about once per second
|
||||
*
|
||||
* @return current upload speed we have to and from this peer
|
||||
*/
|
||||
public int upSpeed() {
|
||||
return upSpeed;
|
||||
}
|
||||
|
||||
/**
|
||||
* The current download speed we have to and from this peer
|
||||
* (including any protocol messages). Updated about once per second
|
||||
*
|
||||
* @return current download speed we have to and from this peer
|
||||
*/
|
||||
public int downSpeed() {
|
||||
return downSpeed;
|
||||
}
|
||||
|
||||
/**
|
||||
* The kind of connection this peer uses.
|
||||
*
|
||||
* @return the connection type
|
||||
*/
|
||||
public ConnectionType connectionType() {
|
||||
return connectionType;
|
||||
}
|
||||
|
||||
/**
|
||||
* The progress of the peer in the range [0, 1]. This is always 0 when
|
||||
* floating point operations are disabled, instead use ``progress_ppm``.
|
||||
*
|
||||
* @return the progress of the peer in the range [0, 1]
|
||||
*/
|
||||
public float progress() {
|
||||
return progress;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates the download progress of the peer in the range [0, 1000000]
|
||||
* (parts per million).
|
||||
*
|
||||
* @return the download progress of the peer in the range [0, 1000000]
|
||||
*/
|
||||
public int progressPpm() {
|
||||
return progressPpm;
|
||||
}
|
||||
|
||||
/**
|
||||
* The IP-address to this peer.
|
||||
*
|
||||
* @return a string representing the endpoint.
|
||||
*/
|
||||
public String ip() {
|
||||
return ip;
|
||||
}
|
||||
|
||||
/**
|
||||
* NOTE: use this with care and only if necessary.
|
||||
*
|
||||
* @param p the native object
|
||||
*/
|
||||
protected void init(peer_info p) {
|
||||
client = Vectors.byte_vector2utf8(p.get_client());
|
||||
totalDownload = p.getTotal_download();
|
||||
totalUpload = p.getTotal_upload();
|
||||
flags = p.get_flags();
|
||||
source = p.get_source();
|
||||
upSpeed = p.getUp_speed();
|
||||
downSpeed = p.getDown_speed();
|
||||
connectionType = ConnectionType.fromSwig(p.getConnection_type());
|
||||
progress = p.getProgress();
|
||||
progressPpm = p.getProgress_ppm();
|
||||
ip = new TcpEndpoint(p.getIp()).toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* The kind of connection this is. Used for the connectionType field.
|
||||
*/
|
||||
public enum ConnectionType {
|
||||
|
||||
/**
|
||||
* Regular bittorrent connection.
|
||||
*/
|
||||
STANDARD_BITTORRENT(peer_info.connection_type_t.standard_bittorrent.swigValue()),
|
||||
|
||||
/**
|
||||
* HTTP connection using the `BEP 19`_ protocol
|
||||
*/
|
||||
WEB_SEED(peer_info.connection_type_t.web_seed.swigValue()),
|
||||
|
||||
/**
|
||||
* HTTP connection using the `BEP 17`_ protocol.
|
||||
*/
|
||||
HTTP_SEED(peer_info.connection_type_t.http_seed.swigValue()),
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
UNKNOWN(-1);
|
||||
|
||||
private final int swigValue;
|
||||
|
||||
ConnectionType(int swigValue) {
|
||||
this.swigValue = swigValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param swigValue the swig value
|
||||
* @return the enum value
|
||||
*/
|
||||
public static ConnectionType fromSwig(int swigValue) {
|
||||
ConnectionType[] enumValues = ConnectionType.class.getEnumConstants();
|
||||
for (ConnectionType ev : enumValues) {
|
||||
if (ev.swig() == swigValue) {
|
||||
return ev;
|
||||
}
|
||||
}
|
||||
return UNKNOWN;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the native value
|
||||
*/
|
||||
public int swig() {
|
||||
return swigValue;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,62 @@
|
||||
package com.frostwire.jlibtorrent;
|
||||
|
||||
import com.frostwire.jlibtorrent.swig.peer_request;
|
||||
|
||||
/**
|
||||
* Represents a byte range within a piece. Internally this is
|
||||
* is used for incoming piece requests.
|
||||
*
|
||||
* @author gubatron
|
||||
* @author aldenml
|
||||
*/
|
||||
public final class PeerRequest {
|
||||
|
||||
private final peer_request r;
|
||||
|
||||
// internal
|
||||
public PeerRequest(peer_request r) {
|
||||
this.r = r;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return native object
|
||||
*/
|
||||
public peer_request swig() {
|
||||
return r;
|
||||
}
|
||||
|
||||
/**
|
||||
* The index of the piece in which the range starts.
|
||||
*
|
||||
* @return the piece index
|
||||
*/
|
||||
public int piece() {
|
||||
return r.getPiece();
|
||||
}
|
||||
|
||||
/**
|
||||
* The offset within that piece where the range starts.
|
||||
*
|
||||
* @return the start offset
|
||||
*/
|
||||
public int start() {
|
||||
return r.getStart();
|
||||
}
|
||||
|
||||
/**
|
||||
* The size of the range, in bytes.
|
||||
*
|
||||
* @return the range length
|
||||
*/
|
||||
public int length() {
|
||||
return r.getLength();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string representation
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return "PeerRequest(piece: " + piece() + ", start: " + start() + ", length: " + length() + ")";
|
||||
}
|
||||
}
|
@ -0,0 +1,177 @@
|
||||
package com.frostwire.jlibtorrent;
|
||||
|
||||
import com.frostwire.jlibtorrent.swig.piece_index_bitfield;
|
||||
import com.frostwire.jlibtorrent.swig.torrent_status;
|
||||
|
||||
/**
|
||||
* The bitfield type stores any number of bits as a bitfield
|
||||
* in a heap allocated array.
|
||||
*
|
||||
* @author gubatron
|
||||
* @author aldenml
|
||||
*/
|
||||
public final class PieceIndexBitfield {
|
||||
|
||||
private final piece_index_bitfield f;
|
||||
private final torrent_status ts;
|
||||
|
||||
/**
|
||||
* @param f the native object
|
||||
*/
|
||||
public PieceIndexBitfield(piece_index_bitfield f) {
|
||||
this(f, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to keep the torrent status reference around.
|
||||
*
|
||||
* @param f the native object
|
||||
* @param ts the torrent status to pin
|
||||
*/
|
||||
PieceIndexBitfield(piece_index_bitfield f, torrent_status ts) {
|
||||
this.f = f;
|
||||
this.ts = ts;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the native object
|
||||
*/
|
||||
public piece_index_bitfield swig() {
|
||||
return f;
|
||||
}
|
||||
|
||||
/**
|
||||
* This methods returns the internal torrent status or null
|
||||
* if it was constructed without one.
|
||||
* <p>
|
||||
* This also prevent premature garbage collection in case
|
||||
* the storage was created from a torrent status.
|
||||
*
|
||||
* @return the pinned torrent info
|
||||
*/
|
||||
public torrent_status ts() {
|
||||
return ts;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param index the bit index
|
||||
* @return the bit value
|
||||
*/
|
||||
public boolean getBit(int index) {
|
||||
return f.get_bit(index);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param index the bit index
|
||||
*/
|
||||
public void clearBit(int index) {
|
||||
f.clear_bit(index);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param index the bit index
|
||||
*/
|
||||
public void setBit(int index) {
|
||||
f.set_bit(index);
|
||||
}
|
||||
|
||||
public int endIndex() {
|
||||
return f.end_index();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if all bits in the bitfield are set.
|
||||
*
|
||||
* @return true if all bits are set
|
||||
*/
|
||||
public boolean isAllSet() {
|
||||
return f.all_set();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if no bit is set
|
||||
*/
|
||||
public boolean isNoneSet() {
|
||||
return f.none_set();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the size of the bitfield in bits.
|
||||
*
|
||||
* @return the size
|
||||
*/
|
||||
public int size() {
|
||||
return f.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the bitfield has zero size.
|
||||
*
|
||||
* @return true if empty
|
||||
*/
|
||||
public boolean isEmpty() {
|
||||
return f.empty();
|
||||
}
|
||||
|
||||
/**
|
||||
* Counts the number of bits in the bitfield that are set to 1.
|
||||
*
|
||||
* @return the number of bits set
|
||||
*/
|
||||
public int count() {
|
||||
return f.count();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the bit index
|
||||
*/
|
||||
public int findFirstSet() {
|
||||
return f.find_first_set();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the bit index
|
||||
*/
|
||||
public int findLastClear() {
|
||||
return f.find_last_clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the size of the bitfield to ``bits`` length. If the bitfield is extended,
|
||||
* the new bits are initialized to ``val``.
|
||||
*
|
||||
* @param bits the number of bits
|
||||
* @param val the bits value
|
||||
*/
|
||||
public void resize(int bits, boolean val) {
|
||||
f.resize(bits, val);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bits the number of bits
|
||||
*/
|
||||
public void resize(int bits) {
|
||||
f.resize(bits);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set all bits in the bitfield to 1 (set_all) or 0 (clear_all).
|
||||
*/
|
||||
public void setAll() {
|
||||
f.set_all();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set all bits in the bitfield to 1 (set_all) or 0 (clear_all).
|
||||
*/
|
||||
public void clearAll() {
|
||||
f.clear_all();
|
||||
}
|
||||
|
||||
/**
|
||||
* Make the bitfield empty, of zero size.
|
||||
*/
|
||||
public void clear() {
|
||||
f.clear();
|
||||
}
|
||||
}
|
@ -0,0 +1,103 @@
|
||||
package com.frostwire.jlibtorrent;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
/**
|
||||
* @author gubatron
|
||||
* @author aldenml
|
||||
*/
|
||||
public final class PiecesTracker {
|
||||
|
||||
private final int numFiles;
|
||||
private final int numPieces;
|
||||
|
||||
private final int[][] files;
|
||||
private final long[][] sizes;
|
||||
private final boolean[] complete;
|
||||
|
||||
public PiecesTracker(TorrentInfo ti) {
|
||||
this.numFiles = ti.numFiles();
|
||||
this.numPieces = ti.numPieces();
|
||||
|
||||
this.files = new int[numFiles][];
|
||||
this.sizes = new long[numFiles][];
|
||||
this.complete = new boolean[numPieces];
|
||||
|
||||
FileStorage fs = ti.files();
|
||||
|
||||
for (int fileIndex = 0; fileIndex < numFiles; fileIndex++) {
|
||||
long size = fs.fileSize(fileIndex);
|
||||
int firstPiece = ti.mapFile(fileIndex, 0, 1).piece();
|
||||
int lastPiece = ti.mapFile(fileIndex, size - 1, 1).piece();
|
||||
|
||||
int numSlices = lastPiece - firstPiece + 1;
|
||||
files[fileIndex] = new int[numSlices];
|
||||
sizes[fileIndex] = new long[numSlices];
|
||||
|
||||
for (int pieceIndex = firstPiece; pieceIndex <= lastPiece; pieceIndex++) {
|
||||
int index = pieceIndex - firstPiece;
|
||||
|
||||
files[fileIndex][index] = pieceIndex;
|
||||
|
||||
ArrayList<FileSlice> slices = ti.mapBlock(pieceIndex, 0, ti.pieceSize(pieceIndex));
|
||||
for (FileSlice slice : slices) {
|
||||
if (slice.fileIndex() == fileIndex) {
|
||||
sizes[fileIndex][index] = slice.size();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public int numFiles() {
|
||||
return numFiles;
|
||||
}
|
||||
|
||||
public int numPieces() {
|
||||
return numPieces;
|
||||
}
|
||||
|
||||
public boolean isComplete(int pieceIndex) {
|
||||
return complete[pieceIndex];
|
||||
}
|
||||
|
||||
public void setComplete(int pieceIndex, boolean complete) {
|
||||
this.complete[pieceIndex] = complete;
|
||||
}
|
||||
|
||||
public long getSequentialDownloadedBytes(int fileIndex) {
|
||||
int[] pieces = files[fileIndex];
|
||||
|
||||
long downloaded = 0;
|
||||
|
||||
for (int i = 0; i < pieces.length; i++) {
|
||||
int pieceIndex = pieces[i];
|
||||
|
||||
if (complete[pieceIndex]) {
|
||||
downloaded += sizes[fileIndex][i];
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return downloaded;
|
||||
}
|
||||
|
||||
public int getSequentialDownloadedPieces(int fileIndex) {
|
||||
int[] pieces = files[fileIndex];
|
||||
|
||||
int count = 0;
|
||||
|
||||
for (int i = 0; i < pieces.length; i++) {
|
||||
int pieceIndex = pieces[i];
|
||||
|
||||
if (complete[pieceIndex]) {
|
||||
count++;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
}
|
@ -0,0 +1,10 @@
|
||||
package com.frostwire.jlibtorrent;
|
||||
|
||||
/**
|
||||
* @author gubatron
|
||||
* @author aldenml
|
||||
*/
|
||||
public interface Plugin {
|
||||
|
||||
boolean onDhtRequest(String query, UdpEndpoint source, BDecodeNode message, Entry response);
|
||||
}
|
@ -0,0 +1,36 @@
|
||||
package com.frostwire.jlibtorrent;
|
||||
|
||||
import com.frostwire.jlibtorrent.swig.portmap_protocol;
|
||||
|
||||
/**
|
||||
* @author gubatron
|
||||
* @author aldenml
|
||||
*/
|
||||
public enum PortmapProtocol {
|
||||
|
||||
NONE(portmap_protocol.none.swigValue()),
|
||||
|
||||
TCP(portmap_protocol.tcp.swigValue()),
|
||||
|
||||
UDP(portmap_protocol.udp.swigValue());
|
||||
|
||||
private final int swigValue;
|
||||
|
||||
PortmapProtocol(int swigValue) {
|
||||
this.swigValue = swigValue;
|
||||
}
|
||||
|
||||
public static PortmapProtocol fromSwig(int swigValue) {
|
||||
PortmapProtocol[] enumValues = PortmapProtocol.class.getEnumConstants();
|
||||
for (PortmapProtocol ev : enumValues) {
|
||||
if (ev.swig() == swigValue) {
|
||||
return ev;
|
||||
}
|
||||
}
|
||||
throw new IllegalArgumentException("No enum " + PortmapProtocol.class + " with value " + swigValue);
|
||||
}
|
||||
|
||||
public int swig() {
|
||||
return swigValue;
|
||||
}
|
||||
}
|
@ -0,0 +1,34 @@
|
||||
package com.frostwire.jlibtorrent;
|
||||
|
||||
import com.frostwire.jlibtorrent.swig.portmap_transport;
|
||||
|
||||
/**
|
||||
* @author gubatron
|
||||
* @author aldenml
|
||||
*/
|
||||
public enum PortmapTransport {
|
||||
|
||||
NAT_PMP(portmap_transport.natpmp.swigValue()),
|
||||
|
||||
UPNP(portmap_transport.upnp.swigValue());
|
||||
|
||||
private final int swigValue;
|
||||
|
||||
PortmapTransport(int swigValue) {
|
||||
this.swigValue = swigValue;
|
||||
}
|
||||
|
||||
public static PortmapTransport fromSwig(int swigValue) {
|
||||
PortmapTransport[] enumValues = PortmapTransport.class.getEnumConstants();
|
||||
for (PortmapTransport ev : enumValues) {
|
||||
if (ev.swig() == swigValue) {
|
||||
return ev;
|
||||
}
|
||||
}
|
||||
throw new IllegalArgumentException("No enum " + PortmapTransport.class + " with value " + swigValue);
|
||||
}
|
||||
|
||||
public int swig() {
|
||||
return swigValue;
|
||||
}
|
||||
}
|
@ -0,0 +1,113 @@
|
||||
package com.frostwire.jlibtorrent;
|
||||
|
||||
import com.frostwire.jlibtorrent.swig.byte_vector;
|
||||
import com.frostwire.jlibtorrent.swig.int_vector;
|
||||
|
||||
/**
|
||||
* @author gubatron
|
||||
* @author aldenml
|
||||
*/
|
||||
public enum Priority {
|
||||
|
||||
/**
|
||||
* piece or file is not downloaded at all
|
||||
*/
|
||||
IGNORE(0),
|
||||
|
||||
/**
|
||||
* normal priority. Download order is dependent on availability
|
||||
*/
|
||||
NORMAL(1),
|
||||
|
||||
/**
|
||||
* higher than normal priority. Pieces are preferred over pieces with
|
||||
* the same availability, but not over pieces with lower availability
|
||||
*/
|
||||
TWO(2),
|
||||
|
||||
/**
|
||||
* pieces are as likely to be picked as partial pieces.
|
||||
*/
|
||||
THREE(3),
|
||||
|
||||
/**
|
||||
* pieces are preferred over partial pieces, but not over pieces with
|
||||
* lower availability
|
||||
*/
|
||||
FOUR(4),
|
||||
|
||||
/**
|
||||
* *currently the same as 4*
|
||||
*/
|
||||
FIVE(5),
|
||||
|
||||
/**
|
||||
* piece is as likely to be picked as any piece with availability 1
|
||||
*/
|
||||
SIX(6),
|
||||
|
||||
/**
|
||||
* maximum priority, availability is disregarded, the piece is
|
||||
* preferred over any other piece with lower priority
|
||||
*/
|
||||
SEVEN(7);
|
||||
|
||||
private final int swigValue;
|
||||
|
||||
Priority(int swigValue) {
|
||||
this.swigValue = swigValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param swigValue the native value
|
||||
* @return the enum corresponding value
|
||||
*/
|
||||
public static Priority fromSwig(int swigValue) {
|
||||
Priority[] enumValues = Priority.class.getEnumConstants();
|
||||
for (Priority ev : enumValues) {
|
||||
if (ev.swig() == swigValue) {
|
||||
return ev;
|
||||
}
|
||||
}
|
||||
throw new IllegalArgumentException("Invalid native value");
|
||||
}
|
||||
|
||||
public static Priority[] array(Priority value, int size) {
|
||||
Priority[] arr = new Priority[size];
|
||||
|
||||
for (int i = 0; i < size; i++) {
|
||||
arr[i] = value;
|
||||
}
|
||||
|
||||
return arr;
|
||||
}
|
||||
|
||||
static int_vector array2vector(Priority[] arr) {
|
||||
int_vector v = new int_vector();
|
||||
|
||||
for (int i = 0; i < arr.length; i++) {
|
||||
Priority p = arr[i];
|
||||
v.push_back(p.swig());
|
||||
}
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
static byte_vector array2byte_vector(Priority[] arr) {
|
||||
byte_vector v = new byte_vector();
|
||||
|
||||
for (int i = 0; i < arr.length; i++) {
|
||||
Priority p = arr[i];
|
||||
v.push_back((byte) p.swig());
|
||||
}
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the native value
|
||||
*/
|
||||
public int swig() {
|
||||
return swigValue;
|
||||
}
|
||||
}
|
@ -0,0 +1,634 @@
|
||||
package com.frostwire.jlibtorrent;
|
||||
|
||||
import com.frostwire.jlibtorrent.alerts.DhtImmutableItemAlert;
|
||||
import com.frostwire.jlibtorrent.alerts.DhtMutableItemAlert;
|
||||
import com.frostwire.jlibtorrent.swig.bdecode_node;
|
||||
import com.frostwire.jlibtorrent.swig.byte_vector;
|
||||
import com.frostwire.jlibtorrent.swig.entry;
|
||||
import com.frostwire.jlibtorrent.swig.error_code;
|
||||
import com.frostwire.jlibtorrent.swig.libtorrent_errors;
|
||||
import com.frostwire.jlibtorrent.swig.port_mapping_t_vector;
|
||||
import com.frostwire.jlibtorrent.swig.portmap_protocol;
|
||||
import com.frostwire.jlibtorrent.swig.remove_flags_t;
|
||||
import com.frostwire.jlibtorrent.swig.reopen_network_flags_t;
|
||||
import com.frostwire.jlibtorrent.swig.save_state_flags_t;
|
||||
import com.frostwire.jlibtorrent.swig.session_flags_t;
|
||||
import com.frostwire.jlibtorrent.swig.session_handle;
|
||||
import com.frostwire.jlibtorrent.swig.status_flags_t;
|
||||
import com.frostwire.jlibtorrent.swig.torrent_handle;
|
||||
import com.frostwire.jlibtorrent.swig.torrent_handle_vector;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* The session holds all state that spans multiple torrents. Among other
|
||||
* things it runs the network loop and manages all torrents. Once it's
|
||||
* created, the session object will spawn the main thread that will do all
|
||||
* the work. The main thread will be idle as long it doesn't have any
|
||||
* torrents to participate in.
|
||||
* <p>
|
||||
* This class belongs to a middle logical layer of abstraction. It's a wrapper
|
||||
* of the underlying swig session object (from libtorrent), but it does not
|
||||
* expose all the raw features.
|
||||
*
|
||||
* @author gubatron
|
||||
* @author aldenml
|
||||
*/
|
||||
public class SessionHandle {
|
||||
|
||||
/**
|
||||
* When set, the session will start paused. Call SessionHandle::resume() to start
|
||||
*/
|
||||
public static final session_flags_t PAUSED = session_handle.paused;
|
||||
/**
|
||||
* Saves settings (i.e. the {@link SettingsPack}).
|
||||
*/
|
||||
public static final save_state_flags_t SAVE_SETTINGS = session_handle.save_settings;
|
||||
/**
|
||||
* Saves {@link DhtSettings}.
|
||||
*/
|
||||
public static final save_state_flags_t SAVE_DHT_SETTINGS = session_handle.save_dht_settings;
|
||||
/**
|
||||
* Saves dht state such as nodes and node-id, possibly accelerating
|
||||
* joining the DHT if provided at next session startup.
|
||||
*/
|
||||
public static final save_state_flags_t SAVE_DHT_STATE = session_handle.save_dht_state;
|
||||
/**
|
||||
* Delete the files belonging to the torrent from disk,
|
||||
* including the part-file, if there is one.
|
||||
*/
|
||||
public static final remove_flags_t DELETE_FILES = session_handle.delete_files;
|
||||
/**
|
||||
* Delete just the part-file associated with this torrent.
|
||||
*/
|
||||
public static final remove_flags_t DELETE_PARTFILE = session_handle.delete_partfile;
|
||||
/**
|
||||
* This option indicates if the ports are mapped using natpmp
|
||||
* and UPnP. If mapping was already made, they are deleted and added
|
||||
* again. This only works if natpmp and/or upnp are configured to be
|
||||
* enable.
|
||||
*/
|
||||
public static final reopen_network_flags_t REOPEN_MAP_PORTS = session_handle.reopen_map_ports;
|
||||
public static final int DHT_ANNOUNCE_SEED = 1;
|
||||
public static final int DHT_ANNOUNCE_IMPLIED_PORT = 1 << 1;
|
||||
public static final int DHT_ANNOUNCE_SSL_TORRENT = 1 << 2;
|
||||
private static final Logger LOG = Logger.getLogger(SessionHandle.class);
|
||||
protected final session_handle s;
|
||||
|
||||
/**
|
||||
* @param s the native object
|
||||
*/
|
||||
public SessionHandle(session_handle s) {
|
||||
this.s = s;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the native object
|
||||
*/
|
||||
public session_handle swig() {
|
||||
return s;
|
||||
}
|
||||
|
||||
public boolean isValid() {
|
||||
return s.is_valid();
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads and saves all session settings, including dht settings,
|
||||
* encryption settings and proxy settings. This method
|
||||
* internally writes all keys to an {@link entry} that is returned
|
||||
* as a bencoded byte array.
|
||||
* <p>
|
||||
* The {@code flags} argument passed in to this method can be used to
|
||||
* filter which parts of the session state to save. By default, all state
|
||||
* is saved (except for the individual torrents).
|
||||
*
|
||||
* @return the bencoded byte array
|
||||
*/
|
||||
public byte[] saveState(save_state_flags_t flags) {
|
||||
entry e = new entry();
|
||||
s.save_state(e, flags);
|
||||
return Vectors.byte_vector2bytes(e.bencode());
|
||||
}
|
||||
|
||||
/**
|
||||
* Same as calling {@link #saveState(save_state_flags_t)} with all save state flags.
|
||||
*
|
||||
* @return the bencoded byte array
|
||||
*/
|
||||
public byte[] saveState() {
|
||||
entry e = new entry();
|
||||
s.save_state(e);
|
||||
return Vectors.byte_vector2bytes(e.bencode());
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads all session settings, including DHT settings,
|
||||
* encryption settings and proxy settings.
|
||||
* <p>
|
||||
* This method expects a byte array that it is a
|
||||
* bencoded buffer.
|
||||
* <p>
|
||||
* The {@code flags} argument passed in to this method can be used to
|
||||
* filter which parts of the session state to load. By default, all state
|
||||
* is restored (except for the individual torrents).
|
||||
*
|
||||
* @param data the bencoded byte array
|
||||
*/
|
||||
public void loadState(byte[] data, save_state_flags_t flags) {
|
||||
byte_vector buffer = Vectors.bytes2byte_vector(data);
|
||||
bdecode_node n = new bdecode_node();
|
||||
error_code ec = new error_code();
|
||||
int ret = bdecode_node.bdecode(buffer, n, ec);
|
||||
|
||||
if (ret == 0) {
|
||||
s.load_state(n, flags);
|
||||
buffer.clear(); // prevents GC
|
||||
} else {
|
||||
LOG.error("failed to decode bencoded data: " + ec.message());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Same as calling {@link #loadState(byte[], save_state_flags_t)} with all
|
||||
* save state flags.
|
||||
*/
|
||||
public void loadState(byte[] data) {
|
||||
byte_vector buffer = Vectors.bytes2byte_vector(data);
|
||||
bdecode_node n = new bdecode_node();
|
||||
error_code ec = new error_code();
|
||||
int ret = bdecode_node.bdecode(buffer, n, ec);
|
||||
|
||||
if (ret == 0) {
|
||||
s.load_state(n);
|
||||
buffer.clear(); // prevents GC
|
||||
} else {
|
||||
LOG.error("failed to decode bencoded data: " + ec.message());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This functions instructs the session to post the
|
||||
* {@link com.frostwire.jlibtorrent.alerts.StateUpdateAlert},
|
||||
* containing the status of all torrents whose state changed since the
|
||||
* last time this function was called.
|
||||
* <p>
|
||||
* Only torrents who has the state subscription flag set will be
|
||||
* included. This flag is on by default. See {@link AddTorrentParams}.
|
||||
* the {@code flags} argument is the same as for torrent_handle::status().
|
||||
*
|
||||
* @param flags or-combination of native values
|
||||
*/
|
||||
public void postTorrentUpdates(status_flags_t flags) {
|
||||
s.post_torrent_updates(flags);
|
||||
}
|
||||
|
||||
/**
|
||||
* This functions instructs the session to post the
|
||||
* {@link com.frostwire.jlibtorrent.alerts.StateUpdateAlert},
|
||||
* containing the status of all torrents whose state changed since the
|
||||
* last time this function was called.
|
||||
* <p>
|
||||
* Only torrents who has the state subscription flag set will be
|
||||
* included.
|
||||
*/
|
||||
public void postTorrentUpdates() {
|
||||
s.post_torrent_updates();
|
||||
}
|
||||
|
||||
/**
|
||||
* This function will post a {@link com.frostwire.jlibtorrent.alerts.SessionStatsAlert} object, containing a
|
||||
* snapshot of the performance counters from the internals of libtorrent.
|
||||
* To interpret these counters, query the session via
|
||||
* session_stats_metrics().
|
||||
*/
|
||||
public void postSessionStats() {
|
||||
s.post_session_stats();
|
||||
}
|
||||
|
||||
/**
|
||||
* This will cause a dht_stats_alert to be posted.
|
||||
*/
|
||||
public void postDhtStats() {
|
||||
s.post_dht_stats();
|
||||
}
|
||||
|
||||
/**
|
||||
* Looks for a torrent with the given info-hash. In case there is such
|
||||
* a torrent in the session, a {@link TorrentHandle} to that torrent
|
||||
* is returned.
|
||||
* <p>
|
||||
* In case the torrent cannot be found, a null is returned.
|
||||
*
|
||||
* @param infoHash
|
||||
* @return
|
||||
*/
|
||||
public TorrentHandle findTorrent(Sha1Hash infoHash) {
|
||||
torrent_handle th = s.find_torrent(infoHash.swig());
|
||||
|
||||
return th != null && th.is_valid() ? new TorrentHandle(th) : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of torrent handles to all the
|
||||
* torrents currently in the session.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public List<TorrentHandle> torrents() {
|
||||
torrent_handle_vector v = s.get_torrents();
|
||||
int size = (int) v.size();
|
||||
|
||||
ArrayList<TorrentHandle> l = new ArrayList<>(size);
|
||||
|
||||
for (int i = 0; i < size; i++) {
|
||||
l.add(new TorrentHandle(v.get(i)));
|
||||
}
|
||||
|
||||
return l;
|
||||
}
|
||||
|
||||
/**
|
||||
* You add torrents through the {@link #addTorrent(AddTorrentParams, ErrorCode)}
|
||||
* function where you give an object with all the parameters.
|
||||
* The {@code addTorrent} overloads will block
|
||||
* until the torrent has been added (or failed to be added) and returns
|
||||
* an error code and a {@link TorrentHandle}. In order to add torrents more
|
||||
* efficiently, consider using {@link #asyncAddTorrent(AddTorrentParams)}
|
||||
* which returns immediately, without waiting for the torrent to add.
|
||||
* Notification of the torrent being added is sent as
|
||||
* {@link com.frostwire.jlibtorrent.alerts.AddTorrentAlert}.
|
||||
* <p>
|
||||
* The {@link TorrentHandle} returned by this method can be used to retrieve
|
||||
* information about the torrent's progress, its peers etc. It is also
|
||||
* used to abort a torrent.
|
||||
* <p>
|
||||
* If the torrent you are trying to add already exists in the session (is
|
||||
* either queued for checking, being checked or downloading)
|
||||
* the error code will be set to {@link libtorrent_errors#duplicate_torrent}
|
||||
* unless {@code flag_duplicate_is_error}
|
||||
* is set to false. In that case, {@code addTorrent} will return the handle
|
||||
* to the existing torrent.
|
||||
* <p>
|
||||
* All torrent handles must be destructed before the session is destructed!
|
||||
*
|
||||
* @param params the parameters to create the torrent download
|
||||
* @param ec the error code if no torrent handle was created
|
||||
* @return the torrent handle, could be invalid
|
||||
*/
|
||||
public TorrentHandle addTorrent(AddTorrentParams params, ErrorCode ec) {
|
||||
error_code e = new error_code();
|
||||
TorrentHandle th = new TorrentHandle(s.add_torrent(params.swig(), e));
|
||||
ec.assign(e);
|
||||
return th;
|
||||
}
|
||||
|
||||
public void asyncAddTorrent(AddTorrentParams params) {
|
||||
s.async_add_torrent(params.swig());
|
||||
}
|
||||
|
||||
/**
|
||||
* This method will close all peer connections associated with the torrent and tell the
|
||||
* tracker that we've stopped participating in the swarm. This operation cannot fail.
|
||||
* When it completes, you will receive a torrent_removed_alert.
|
||||
* <p>
|
||||
* The optional second argument options can be used to delete all the files downloaded
|
||||
* by this torrent. To do so, pass in the value session::delete_files. The removal of
|
||||
* the torrent is asynchronous, there is no guarantee that adding the same torrent immediately
|
||||
* after it was removed will not throw a libtorrent_exception exception. Once the torrent
|
||||
* is deleted, a torrent_deleted_alert is posted.
|
||||
*
|
||||
* @param th the handle
|
||||
*/
|
||||
public void removeTorrent(TorrentHandle th, remove_flags_t options) {
|
||||
if (th.isValid()) {
|
||||
s.remove_torrent(th.swig(), options);
|
||||
}
|
||||
}
|
||||
|
||||
// starts/stops UPnP, NATPMP or LSD port mappers they are stopped by
|
||||
// default These functions are not available in case
|
||||
// ``TORRENT_DISABLE_DHT`` is defined. ``start_dht`` starts the dht node
|
||||
// and makes the trackerless service available to torrents. The startup
|
||||
// state is optional and can contain nodes and the node id from the
|
||||
// previous session. The dht node state is a bencoded dictionary with the
|
||||
// following entries:
|
||||
//
|
||||
// nodes
|
||||
// A list of strings, where each string is a node endpoint encoded in
|
||||
// binary. If the string is 6 bytes long, it is an IPv4 address of 4
|
||||
// bytes, encoded in network byte order (big endian), followed by a 2
|
||||
// byte port number (also network byte order). If the string is 18
|
||||
// bytes long, it is 16 bytes of IPv6 address followed by a 2 bytes
|
||||
// port number (also network byte order).
|
||||
//
|
||||
// node-id
|
||||
// The node id written as a readable string as a hexadecimal number.
|
||||
//
|
||||
// ``dht_state`` will return the current state of the dht node, this can
|
||||
// be used to start up the node again, passing this entry to
|
||||
// ``start_dht``. It is a good idea to save this to disk when the session
|
||||
// is closed, and read it up again when starting.
|
||||
//
|
||||
// If the port the DHT is supposed to listen on is already in use, and
|
||||
// exception is thrown, ``asio::error``.
|
||||
//
|
||||
// ``stop_dht`` stops the dht node.
|
||||
//
|
||||
// ``add_dht_node`` adds a node to the routing table. This can be used if
|
||||
// your client has its own source of bootstrapping nodes.
|
||||
//
|
||||
// ``set_dht_settings`` sets some parameters available to the dht node.
|
||||
// See dht_settings for more information.
|
||||
//
|
||||
// ``is_dht_running()`` returns true if the DHT support has been started
|
||||
// and false
|
||||
// otherwise.
|
||||
|
||||
/**
|
||||
* This method will close all peer connections associated with the torrent and tell the
|
||||
* tracker that we've stopped participating in the swarm. This operation cannot fail.
|
||||
* When it completes, you will receive a torrent_removed_alert.
|
||||
*
|
||||
* @param th
|
||||
*/
|
||||
public void removeTorrent(TorrentHandle th) {
|
||||
if (th.isValid()) {
|
||||
s.remove_torrent(th.swig());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Pausing the session has the same effect as pausing every torrent in
|
||||
* it, except that torrents will not be resumed by the auto-manage
|
||||
* mechanism.
|
||||
*/
|
||||
public void pause() {
|
||||
s.pause();
|
||||
}
|
||||
|
||||
/**
|
||||
* Resuming will restore the torrents to their previous paused
|
||||
* state. i.e. the session pause state is separate from the torrent pause
|
||||
* state. A torrent is inactive if it is paused or if the session is
|
||||
* paused.
|
||||
*/
|
||||
public void resume() {
|
||||
s.resume();
|
||||
}
|
||||
|
||||
public boolean isPaused() {
|
||||
return s.is_paused();
|
||||
}
|
||||
|
||||
void setDhtSettings(DhtSettings settings) {
|
||||
s.set_dht_settings(settings.swig());
|
||||
}
|
||||
|
||||
public boolean isDhtRunning() {
|
||||
return s.is_dht_running();
|
||||
}
|
||||
|
||||
/**
|
||||
* takes a host name and port pair. That endpoint will be
|
||||
* pinged, and if a valid DHT reply is received, the node will be added to
|
||||
* the routing table.
|
||||
*
|
||||
* @param node
|
||||
*/
|
||||
public void addDhtNode(Pair<String, Integer> node) {
|
||||
s.add_dht_node(node.to_string_int_pair());
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies the settings specified by the settings pack {@code sp}. This is an
|
||||
* asynchronous operation that will return immediately and actually apply
|
||||
* the settings to the main thread of libtorrent some time later.
|
||||
*
|
||||
* @param sp the settings
|
||||
*/
|
||||
public void applySettings(SettingsPack sp) {
|
||||
s.apply_settings(sp.swig());
|
||||
}
|
||||
|
||||
/**
|
||||
* @return a copy of the internal settings
|
||||
*/
|
||||
public SettingsPack settings() {
|
||||
return new SettingsPack(s.get_settings());
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a port forwarding on UPnP and/or NAT-PMP, using PCP if supported,
|
||||
* whichever is enabled. The return value is a handle referring to the
|
||||
* port mapping that was just created. Pass it to {@link #deletePortMapping}
|
||||
* to remove it.
|
||||
*
|
||||
* @param t the mapping protocol
|
||||
* @param externalPort the external port
|
||||
* @param localPort the local port
|
||||
* @return the array of port mapping ids
|
||||
*/
|
||||
public int[] addPortMapping(PortmapProtocol t, int externalPort, int localPort) {
|
||||
port_mapping_t_vector v = s.add_port_mapping(portmap_protocol.swigToEnum(t.swig()), externalPort, localPort);
|
||||
|
||||
int size = (int) v.size();
|
||||
int[] arr = new int[size];
|
||||
|
||||
for (int i = 0; i < size; i++) {
|
||||
arr[i] = v.get(i);
|
||||
}
|
||||
|
||||
return arr;
|
||||
}
|
||||
|
||||
public void deletePortMapping(int handle) {
|
||||
s.delete_port_mapping(handle);
|
||||
}
|
||||
|
||||
/**
|
||||
* Instructs the session to reopen all listen and outgoing sockets.
|
||||
* <p>
|
||||
* It's useful in the case your platform doesn't support the built in
|
||||
* IP notifier mechanism, or if you have a better more reliable way to
|
||||
* detect changes in the IP routing table.
|
||||
*
|
||||
* @param options the options
|
||||
*/
|
||||
public void reopenNetworkSockets(reopen_network_flags_t options) {
|
||||
s.reopen_network_sockets(options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Instructs the session to reopen all listen and outgoing sockets.
|
||||
* <p>
|
||||
* It's useful in the case your platform doesn't support the built in
|
||||
* IP notifier mechanism, or if you have a better more reliable way to
|
||||
* detect changes in the IP routing table.
|
||||
*/
|
||||
public void reopenNetworkSockets() {
|
||||
s.reopen_network_sockets();
|
||||
}
|
||||
|
||||
/**
|
||||
* Query the DHT for an immutable item at the target hash.
|
||||
* the result is posted as a {@link DhtImmutableItemAlert}.
|
||||
*
|
||||
* @param target
|
||||
*/
|
||||
public void dhtGetItem(Sha1Hash target) {
|
||||
s.dht_get_item(target.swig());
|
||||
}
|
||||
|
||||
/**
|
||||
* Query the DHT for a mutable item under the public key {@code key}.
|
||||
* this is an ed25519 key. The {@code salt} argument is optional and may be left
|
||||
* as an empty string if no salt is to be used.
|
||||
* <p>
|
||||
* if the item is found in the DHT, a {@link DhtMutableItemAlert} is
|
||||
* posted.
|
||||
*
|
||||
* @param key
|
||||
* @param salt
|
||||
*/
|
||||
public void dhtGetItem(byte[] key, byte[] salt) {
|
||||
s.dht_get_item(Vectors.bytes2byte_vector(key), Vectors.bytes2byte_vector(salt));
|
||||
}
|
||||
|
||||
/**
|
||||
* Store the given bencoded data as an immutable item in the DHT.
|
||||
* the returned hash is the key that is to be used to look the item
|
||||
* up again. It's just the sha-1 hash of the bencoded form of the
|
||||
* structure.
|
||||
*
|
||||
* @param entry
|
||||
* @return
|
||||
*/
|
||||
public Sha1Hash dhtPutItem(Entry entry) {
|
||||
return new Sha1Hash(s.dht_put_item(entry.swig()));
|
||||
}
|
||||
|
||||
// store an immutable item. The ``key`` is the public key the blob is
|
||||
// to be stored under. The optional ``salt`` argument is a string that
|
||||
// is to be mixed in with the key when determining where in the DHT
|
||||
// the value is to be stored. The callback function is called from within
|
||||
// the libtorrent network thread once we've found where to store the blob,
|
||||
// possibly with the current value stored under the key.
|
||||
// The values passed to the callback functions are:
|
||||
//
|
||||
// entry& value
|
||||
// the current value stored under the key (may be empty). Also expected
|
||||
// to be set to the value to be stored by the function.
|
||||
//
|
||||
// boost::array<char,64>& signature
|
||||
// the signature authenticating the current value. This may be zeroes
|
||||
// if there is currently no value stored. The function is expected to
|
||||
// fill in this buffer with the signature of the new value to store.
|
||||
// To generate the signature, you may want to use the
|
||||
// ``sign_mutable_item`` function.
|
||||
//
|
||||
// boost::uint64_t& seq
|
||||
// current sequence number. May be zero if there is no current value.
|
||||
// The function is expected to set this to the new sequence number of
|
||||
// the value that is to be stored. Sequence numbers must be monotonically
|
||||
// increasing. Attempting to overwrite a value with a lower or equal
|
||||
// sequence number will fail, even if the signature is correct.
|
||||
//
|
||||
// std::string const& salt
|
||||
// this is the salt that was used for this put call.
|
||||
//
|
||||
// Since the callback function ``cb`` is called from within libtorrent,
|
||||
// it is critical to not perform any blocking operations. Ideally not
|
||||
// even locking a mutex. Pass any data required for this function along
|
||||
// with the function object's context and make the function entirely
|
||||
// self-contained. The only reason data blobs' values are computed
|
||||
// via a function instead of just passing in the new value is to avoid
|
||||
// race conditions. If you want to *update* the value in the DHT, you
|
||||
// must first retrieve it, then modify it, then write it back. The way
|
||||
// the DHT works, it is natural to always do a lookup before storing and
|
||||
// calling the callback in between is convenient.
|
||||
public void dhtPutItem(byte[] publicKey, byte[] privateKey, Entry entry, byte[] salt) {
|
||||
s.dht_put_item(Vectors.bytes2byte_vector(publicKey),
|
||||
Vectors.bytes2byte_vector(privateKey),
|
||||
entry.swig(),
|
||||
Vectors.bytes2byte_vector(salt));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param infoHash
|
||||
*/
|
||||
public void dhtGetPeers(Sha1Hash infoHash) {
|
||||
s.dht_get_peers(infoHash.swig());
|
||||
}
|
||||
|
||||
/**
|
||||
* @param infoHash
|
||||
* @param port
|
||||
* @param flags
|
||||
*/
|
||||
public void dhtAnnounce(Sha1Hash infoHash, int port, int flags) {
|
||||
s.dht_announce(infoHash.swig(), port, flags);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param infoHash
|
||||
*/
|
||||
public void dhtAnnounce(Sha1Hash infoHash) {
|
||||
s.dht_announce(infoHash.swig());
|
||||
}
|
||||
|
||||
/**
|
||||
* @param endp
|
||||
* @param entry
|
||||
* @param userdata
|
||||
*/
|
||||
public void dhtDirectRequest(UdpEndpoint endp, Entry entry, long userdata) {
|
||||
s.dht_direct_request(endp.swig(), entry.swig(), userdata);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param endp
|
||||
* @param entry
|
||||
*/
|
||||
public void dhtDirectRequest(UdpEndpoint endp, Entry entry) {
|
||||
s.dht_direct_request(endp.swig(), entry.swig());
|
||||
}
|
||||
|
||||
/**
|
||||
* returns the port we ended up listening on. Since you
|
||||
* just pass a port-range to the constructor and to ``listen_on()``, to
|
||||
* know which port it ended up using, you have to ask the session using
|
||||
* this function.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public int getListenPort() {
|
||||
return s.listen_port();
|
||||
}
|
||||
|
||||
public int getSslListenPort() {
|
||||
return s.ssl_listen_port();
|
||||
}
|
||||
|
||||
/**
|
||||
* will tell you whether or not the session has
|
||||
* successfully opened a listening port. If it hasn't, this function will
|
||||
* return false, and then you can use ``listen_on()`` to make another
|
||||
* attempt.
|
||||
*
|
||||
* @return {@code true} if listening
|
||||
*/
|
||||
public boolean isListening() {
|
||||
return s.is_listening();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public void addExtension(Plugin plugin) {
|
||||
SwigPlugin p = new SwigPlugin(plugin);
|
||||
s.add_extension(p);
|
||||
p.swigReleaseOwnership();
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,58 @@
|
||||
package com.frostwire.jlibtorrent;
|
||||
|
||||
import com.frostwire.jlibtorrent.swig.session_params;
|
||||
|
||||
/**
|
||||
* This is a parameters pack for configuring the session
|
||||
* before it's started.
|
||||
*
|
||||
* @author gubatron
|
||||
* @author aldenml
|
||||
*/
|
||||
public class SessionParams {
|
||||
|
||||
private final session_params p;
|
||||
|
||||
/**
|
||||
* @param p the native object
|
||||
*/
|
||||
public SessionParams(session_params p) {
|
||||
this.p = p;
|
||||
}
|
||||
|
||||
/**
|
||||
* This constructor can be used to start with the default plugins
|
||||
* (ut_metadata, ut_pex and smart_ban). The default values in the
|
||||
* settings is to start the default features like upnp, nat-pmp,
|
||||
* and dht for example.
|
||||
*/
|
||||
public SessionParams() {
|
||||
this(new session_params());
|
||||
}
|
||||
|
||||
/**
|
||||
* This constructor can be used to start with the default plugins
|
||||
* (ut_metadata, ut_pex and smart_ban). The default values in the
|
||||
* settings is to start the default features like upnp, nat-pmp,
|
||||
* and dht for example.
|
||||
*
|
||||
* @param settings the initial settings pack
|
||||
*/
|
||||
public SessionParams(SettingsPack settings) {
|
||||
this(new session_params(settings.swig()));
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the native object
|
||||
*/
|
||||
public session_params swig() {
|
||||
return p;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the settings pack
|
||||
*/
|
||||
public SettingsPack settings() {
|
||||
return new SettingsPack(p.getSettings());
|
||||
}
|
||||
}
|
@ -0,0 +1,149 @@
|
||||
package com.frostwire.jlibtorrent;
|
||||
|
||||
import com.frostwire.jlibtorrent.alerts.SessionStatsAlert;
|
||||
|
||||
/**
|
||||
* @author gubatron
|
||||
* @author aldenml
|
||||
*/
|
||||
public final class SessionStats {
|
||||
|
||||
// these are the channels we keep stats for
|
||||
private static final int UPLOAD_PAYLOAD = 0;
|
||||
private static final int UPLOAD_PROTOCOL = 1;
|
||||
private static final int UPLOAD_IP_PROTOCOL = 2;
|
||||
private static final int DOWNLOAD_PAYLOAD = 3;
|
||||
private static final int DOWNLOAD_PROTOCOL = 4;
|
||||
private static final int DOWNLOAD_IP_PROTOCOL = 5;
|
||||
private static final int NUM_AVERAGES = 6;
|
||||
|
||||
private final Average[] stat;
|
||||
|
||||
private long lastTickTime;
|
||||
private long dhtNodes;
|
||||
|
||||
SessionStats() {
|
||||
this.stat = new Average[NUM_AVERAGES];
|
||||
for (int i = 0; i < this.stat.length; i++) {
|
||||
this.stat[i] = new Average();
|
||||
}
|
||||
}
|
||||
|
||||
public long totalDownload() {
|
||||
return stat[DOWNLOAD_PAYLOAD].total() +
|
||||
stat[DOWNLOAD_PROTOCOL].total() +
|
||||
stat[DOWNLOAD_IP_PROTOCOL].total();
|
||||
}
|
||||
|
||||
public long totalUpload() {
|
||||
return stat[UPLOAD_PAYLOAD].total() +
|
||||
stat[UPLOAD_PROTOCOL].total() +
|
||||
stat[UPLOAD_IP_PROTOCOL].total();
|
||||
}
|
||||
|
||||
public long downloadRate() {
|
||||
return stat[DOWNLOAD_PAYLOAD].rate() +
|
||||
stat[DOWNLOAD_PROTOCOL].rate() +
|
||||
stat[DOWNLOAD_IP_PROTOCOL].rate();
|
||||
}
|
||||
|
||||
public long uploadRate() {
|
||||
return stat[UPLOAD_PAYLOAD].rate() +
|
||||
stat[UPLOAD_PROTOCOL].rate() +
|
||||
stat[UPLOAD_IP_PROTOCOL].rate();
|
||||
}
|
||||
|
||||
public long dhtNodes() {
|
||||
return dhtNodes;
|
||||
}
|
||||
|
||||
void update(SessionStatsAlert alert) {
|
||||
long now = System.currentTimeMillis();
|
||||
long tickIntervalMs = now - lastTickTime;
|
||||
lastTickTime = now;
|
||||
|
||||
long received = alert.value(StatsMetric.NET_RECV_BYTES_COUNTER_INDEX);
|
||||
long payload = alert.value(StatsMetric.NET_RECV_PAYLOAD_BYTES_COUNTER_INDEX);
|
||||
long protocol = received - payload;
|
||||
long ip = alert.value(StatsMetric.NET_RECV_IP_OVERHEAD_BYTES_COUNTER_INDEX);
|
||||
|
||||
payload -= stat[DOWNLOAD_PAYLOAD].total();
|
||||
protocol -= stat[DOWNLOAD_PROTOCOL].total();
|
||||
ip -= stat[DOWNLOAD_IP_PROTOCOL].total();
|
||||
stat[DOWNLOAD_PAYLOAD].add(payload);
|
||||
stat[DOWNLOAD_PROTOCOL].add(protocol);
|
||||
stat[DOWNLOAD_IP_PROTOCOL].add(ip);
|
||||
|
||||
long sent = alert.value(StatsMetric.NET_SENT_BYTES_COUNTER_INDEX);
|
||||
payload = alert.value(StatsMetric.NET_SENT_PAYLOAD_BYTES_COUNTER_INDEX);
|
||||
protocol = sent - payload;
|
||||
ip = alert.value(StatsMetric.NET_SENT_IP_OVERHEAD_BYTES_COUNTER_INDEX);
|
||||
|
||||
payload -= stat[UPLOAD_PAYLOAD].total();
|
||||
protocol -= stat[UPLOAD_PROTOCOL].total();
|
||||
ip -= stat[UPLOAD_IP_PROTOCOL].total();
|
||||
stat[UPLOAD_PAYLOAD].add(payload);
|
||||
stat[UPLOAD_PROTOCOL].add(protocol);
|
||||
stat[UPLOAD_IP_PROTOCOL].add(ip);
|
||||
|
||||
tick(tickIntervalMs);
|
||||
dhtNodes = alert.value(StatsMetric.DHT_NODES_GAUGE_INDEX);
|
||||
}
|
||||
|
||||
void clear() {
|
||||
for (int i = 0; i < NUM_AVERAGES; ++i) {
|
||||
stat[i].clear();
|
||||
}
|
||||
dhtNodes = 0;
|
||||
}
|
||||
|
||||
// should be called once every second
|
||||
private void tick(long tickIntervalMs) {
|
||||
for (int i = 0; i < NUM_AVERAGES; ++i) {
|
||||
stat[i].tick(tickIntervalMs);
|
||||
}
|
||||
}
|
||||
|
||||
private static final class Average {
|
||||
|
||||
// total counters
|
||||
private long totalCounter;
|
||||
|
||||
// the accumulator for this second.
|
||||
private long counter;
|
||||
|
||||
// sliding average
|
||||
private long averageSec5;
|
||||
|
||||
public Average() {
|
||||
}
|
||||
|
||||
public void add(long count) {
|
||||
counter += count;
|
||||
totalCounter += count;
|
||||
}
|
||||
|
||||
// should be called once every second
|
||||
public void tick(long tickIntervalMs) {
|
||||
if (tickIntervalMs >= 1) {
|
||||
long sample = (counter * 1000) / tickIntervalMs;
|
||||
averageSec5 = (averageSec5 * 4) / 5 + sample / 5;
|
||||
counter = 0;
|
||||
}
|
||||
}
|
||||
|
||||
public long rate() {
|
||||
return averageSec5;
|
||||
}
|
||||
|
||||
public long total() {
|
||||
return totalCounter;
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
counter = 0;
|
||||
averageSec5 = 0;
|
||||
totalCounter = 0;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,609 @@
|
||||
package com.frostwire.jlibtorrent;
|
||||
|
||||
import com.frostwire.jlibtorrent.swig.settings_pack;
|
||||
|
||||
/**
|
||||
* The ``settings_pack`` struct, contains the names of all settings as
|
||||
* enum values. These values are passed in to the ``set_str()``,
|
||||
* ``set_int()``, ``set_bool()`` functions, to specify the setting to
|
||||
* change.
|
||||
*
|
||||
* @author gubatron
|
||||
* @author aldenml
|
||||
*/
|
||||
public final class SettingsPack {
|
||||
|
||||
private final settings_pack sp;
|
||||
|
||||
public SettingsPack(settings_pack sp) {
|
||||
this.sp = sp;
|
||||
}
|
||||
|
||||
/**
|
||||
* Example, how to turn on the DHT using SettingsPack.
|
||||
* <pre>{@code
|
||||
* SettingsPack pack = new SettingsPack();
|
||||
* pack.setBoolean(settings_pack.bool_types.enable_dht.swigValue(), on);
|
||||
* s.applySettings(pack);
|
||||
* }</pre>
|
||||
*/
|
||||
public SettingsPack() {
|
||||
this(new settings_pack());
|
||||
}
|
||||
|
||||
/**
|
||||
* @return
|
||||
*/
|
||||
public settings_pack swig() {
|
||||
return sp;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param name
|
||||
* @return
|
||||
*/
|
||||
public boolean getBoolean(int name) {
|
||||
return sp.get_bool(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param name
|
||||
* @param value
|
||||
*/
|
||||
public SettingsPack setBoolean(int name, boolean value) {
|
||||
sp.set_bool(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param name
|
||||
* @return
|
||||
*/
|
||||
public int getInteger(int name) {
|
||||
return sp.get_int(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param name
|
||||
* @param value
|
||||
*/
|
||||
public SettingsPack setInteger(int name, int value) {
|
||||
sp.set_int(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param name
|
||||
* @return
|
||||
*/
|
||||
public String getString(int name) {
|
||||
return sp.get_str(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param name
|
||||
* @param value
|
||||
*/
|
||||
public SettingsPack setString(int name, String value) {
|
||||
sp.set_str(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
sp.clear();
|
||||
}
|
||||
|
||||
public void clear(int name) {
|
||||
sp.clear(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the session-global download rate limit in bytes per second. (0 for unlimited)
|
||||
*/
|
||||
public int downloadRateLimit() {
|
||||
return sp.get_int(settings_pack.int_types.download_rate_limit.swigValue());
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the session-global limits of download rate limit, in
|
||||
* bytes per second.
|
||||
* <p>
|
||||
* A value of 0 means unlimited.
|
||||
*
|
||||
* @param value
|
||||
*/
|
||||
public SettingsPack downloadRateLimit(int value) {
|
||||
sp.set_int(settings_pack.int_types.download_rate_limit.swigValue(), value);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the session-global upload rate limit in bytes per second. (0 for unlimited)
|
||||
*/
|
||||
public int uploadRateLimit() {
|
||||
return sp.get_int(settings_pack.int_types.upload_rate_limit.swigValue());
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the session-global limits of upload rate limit, in
|
||||
* bytes per second.
|
||||
* <p>
|
||||
* A value of 0 means unlimited.
|
||||
*
|
||||
* @param value
|
||||
*/
|
||||
public SettingsPack uploadRateLimit(int value) {
|
||||
sp.set_int(settings_pack.int_types.upload_rate_limit.swigValue(), value);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@code active_downloads} controls how many active
|
||||
* downloading torrents the queuing mechanism allows.
|
||||
* <p>
|
||||
* The target number of active torrents is {@code min(active_downloads +
|
||||
* active_seeds, active_limit)}. {@code active_downloads} and
|
||||
* {@code active_seeds} are upper limits on the number of downloading
|
||||
* torrents and seeding torrents respectively. Setting the value to -1
|
||||
* means unlimited.
|
||||
* <p>
|
||||
* For auto managed torrents, these are the limits they are subject to.
|
||||
* If there are too many torrents some of the auto managed ones will be
|
||||
* paused until some slots free up.
|
||||
* <p>
|
||||
* You can have more torrents *active*, even though they are not
|
||||
* announced to the DHT, lsd or their tracker. If some peer knows about
|
||||
* you for any reason and tries to connect, it will still be accepted,
|
||||
* unless the torrent is paused, which means it won't accept any
|
||||
* connections.
|
||||
* <p>
|
||||
* For example if there are 10 seeding torrents and 10 downloading
|
||||
* torrents, and ``active_downloads`` is 4 and ``active_seeds`` is 4,
|
||||
* there will be 4 seeds active and 4 downloading torrents. If the
|
||||
* settings are ``active_downloads`` = 2 and ``active_seeds`` = 4, then
|
||||
* there will be 2 downloading torrents and 4 seeding torrents active.
|
||||
* Torrents that are not auto managed are also counted against these
|
||||
* limits. If there are non-auto managed torrents that use up all the
|
||||
* slots, no auto managed torrent will be activated.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public int activeDownloads() {
|
||||
return sp.get_int(settings_pack.int_types.active_downloads.swigValue());
|
||||
}
|
||||
|
||||
/**
|
||||
* @param value
|
||||
* @see #activeDownloads()
|
||||
*/
|
||||
public SettingsPack activeDownloads(int value) {
|
||||
sp.set_int(settings_pack.int_types.active_downloads.swigValue(), value);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@code active_seeds} controls how many active seeding
|
||||
* torrents the queuing mechanism allows.
|
||||
*
|
||||
* @return
|
||||
* @see #activeDownloads()
|
||||
*/
|
||||
public int activeSeeds() {
|
||||
return sp.get_int(settings_pack.int_types.active_seeds.swigValue());
|
||||
}
|
||||
|
||||
/**
|
||||
* @param value
|
||||
* @see #activeSeeds()
|
||||
*/
|
||||
public SettingsPack activeSeeds(int value) {
|
||||
sp.set_int(settings_pack.int_types.active_seeds.swigValue(), value);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@code active_checking} is the limit of number of simultaneous checking
|
||||
* torrents.
|
||||
*
|
||||
* @return
|
||||
* @see #activeDownloads()
|
||||
*/
|
||||
public int activeChecking() {
|
||||
return sp.get_int(settings_pack.int_types.active_checking.swigValue());
|
||||
}
|
||||
|
||||
/**
|
||||
* @param value
|
||||
* @see #activeChecking()
|
||||
*/
|
||||
public SettingsPack activeChecking(int value) {
|
||||
sp.set_int(settings_pack.int_types.active_checking.swigValue(), value);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@code active_dht_limit} is the max number of torrents to announce to
|
||||
* the DHT. By default this is set to 88, which is no more than one
|
||||
* DHT announce every 10 seconds.
|
||||
*
|
||||
* @return
|
||||
* @see #activeDownloads()
|
||||
*/
|
||||
public int activeDhtLimit() {
|
||||
return sp.get_int(settings_pack.int_types.active_dht_limit.swigValue());
|
||||
}
|
||||
|
||||
/**
|
||||
* @param value
|
||||
* @see #activeDhtLimit()
|
||||
*/
|
||||
public SettingsPack activeDhtLimit(int value) {
|
||||
sp.set_int(settings_pack.int_types.active_dht_limit.swigValue(), value);
|
||||
return this;
|
||||
}
|
||||
|
||||
public int dhtUploadRate() {
|
||||
return sp.get_int(settings_pack.int_types.dht_upload_rate_limit.swigValue());
|
||||
}
|
||||
|
||||
public SettingsPack dhtUploadRate(int value) {
|
||||
sp.set_int(settings_pack.int_types.dht_upload_rate_limit.swigValue(), value);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@code active_tracker_limit} is the max number of torrents to announce
|
||||
* to their trackers. By default this is 360, which is no more than
|
||||
* one announce every 5 seconds.
|
||||
*
|
||||
* @return
|
||||
* @see #activeDownloads()
|
||||
*/
|
||||
public int activeTrackerLimit() {
|
||||
return sp.get_int(settings_pack.int_types.active_tracker_limit.swigValue());
|
||||
}
|
||||
|
||||
/**
|
||||
* @param value
|
||||
* @see #activeTrackerLimit()
|
||||
*/
|
||||
public SettingsPack activeTrackerLimit(int value) {
|
||||
sp.set_int(settings_pack.int_types.active_tracker_limit.swigValue(), value);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@code active_lsd_limit} is the max number of torrents to announce to
|
||||
* the local network over the local service discovery protocol. By
|
||||
* default this is 80, which is no more than one announce every 5
|
||||
* seconds (assuming the default announce interval of 5 minutes).
|
||||
*
|
||||
* @return
|
||||
* @see #activeDownloads()
|
||||
*/
|
||||
public int activeLsdLimit() {
|
||||
return sp.get_int(settings_pack.int_types.active_lsd_limit.swigValue());
|
||||
}
|
||||
|
||||
/**
|
||||
* @param value
|
||||
* @see #activeLsdLimit()
|
||||
*/
|
||||
public SettingsPack activeLsdLimit(int value) {
|
||||
sp.set_int(settings_pack.int_types.active_lsd_limit.swigValue(), value);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@code active_limit} is a hard limit on the number of active (auto
|
||||
* managed) torrents. This limit also applies to slow torrents.
|
||||
*
|
||||
* @return the value
|
||||
* @see #activeDownloads()
|
||||
*/
|
||||
public int activeLimit() {
|
||||
return sp.get_int(settings_pack.int_types.active_limit.swigValue());
|
||||
}
|
||||
|
||||
/**
|
||||
* {@code active_limit} is a hard limit on the number of active (auto
|
||||
* managed) torrents. This limit also applies to slow torrents.
|
||||
*
|
||||
* @param value the value
|
||||
* @see #activeLimit()
|
||||
*/
|
||||
public SettingsPack activeLimit(int value) {
|
||||
sp.set_int(settings_pack.int_types.active_limit.swigValue(), value);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return global limit on the number of connections opened.
|
||||
*/
|
||||
public int connectionsLimit() {
|
||||
return sp.get_int(settings_pack.int_types.connections_limit.swigValue());
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a global limit on the number of connections opened. The number of
|
||||
* connections is set to a hard minimum of at least two per torrent, so
|
||||
* if you set a too low connections limit, and open too many torrents,
|
||||
* the limit will not be met.
|
||||
*
|
||||
* @param value
|
||||
*/
|
||||
public SettingsPack connectionsLimit(int value) {
|
||||
sp.set_int(settings_pack.int_types.connections_limit.swigValue(), value);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the maximum number of peers in the list of known peers. (0 for unlimited)
|
||||
*/
|
||||
public int maxPeerlistSize() {
|
||||
return sp.get_int(settings_pack.int_types.max_peerlist_size.swigValue());
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the maximum number of peers in the list of known peers. These peers
|
||||
* are not necessarily connected, so this number should be much greater
|
||||
* than the maximum number of connected peers. Peers are evicted from the
|
||||
* cache when the list grows passed 90% of this limit, and once the size
|
||||
* hits the limit, peers are no longer added to the list. If this limit
|
||||
* is set to 0, there is no limit on how many peers we'll keep in the
|
||||
* peer list.
|
||||
*
|
||||
* @param value
|
||||
*/
|
||||
public SettingsPack maxPeerlistSize(int value) {
|
||||
sp.set_int(settings_pack.int_types.max_peerlist_size.swigValue(), value);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the maximum number of bytes a connection may have pending in the disk
|
||||
* write queue before its download rate is being throttled.
|
||||
*/
|
||||
public int maxQueuedDiskBytes() {
|
||||
return sp.get_int(settings_pack.int_types.max_queued_disk_bytes.swigValue());
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the maximum number of bytes a connection may have pending in the disk
|
||||
* write queue before its download rate is being throttled. This prevents
|
||||
* fast downloads to slow medias to allocate more memory indefinitely.
|
||||
* This should be set to at least 16 kB to not completely disrupt normal
|
||||
* downloads. If it's set to 0, you will be starving the disk thread and
|
||||
* nothing will be written to disk. this is a per session setting.
|
||||
* <p>
|
||||
* When this limit is reached, the peer connections will stop reading
|
||||
* data from their sockets, until the disk thread catches up. Setting
|
||||
* this too low will severely limit your download rate.
|
||||
*
|
||||
* @param value
|
||||
*/
|
||||
public SettingsPack maxQueuedDiskBytes(int value) {
|
||||
sp.set_int(settings_pack.int_types.max_queued_disk_bytes.swigValue(), value);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the upper limit of the send buffer low-watermark.
|
||||
*/
|
||||
public int sendBufferWatermark() {
|
||||
return sp.get_int(settings_pack.int_types.send_buffer_watermark.swigValue());
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the upper limit of the send buffer low-watermark.
|
||||
* <p>
|
||||
* if the send buffer has fewer bytes than this, we'll read another 16kB
|
||||
* block onto it. If set too small, upload rate capacity will suffer. If
|
||||
* set too high, memory will be wasted. The actual watermark may be lower
|
||||
* than this in case the upload rate is low, this is the upper limit.
|
||||
*
|
||||
* @param value
|
||||
*/
|
||||
public SettingsPack sendBufferWatermark(int value) {
|
||||
sp.set_int(settings_pack.int_types.send_buffer_watermark.swigValue(), value);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the disk write and read cache. It is specified in units of 16 KiB
|
||||
* blocks. Buffers that are part of a peer's send or receive buffer also
|
||||
* count against this limit. Send and receive buffers will never be
|
||||
* denied to be allocated, but they will cause the actual cached blocks
|
||||
* to be flushed or evicted. If this is set to -1, the cache size is
|
||||
* automatically set to the amount of physical RAM available in the
|
||||
* machine divided by 8. If the amount of physical RAM cannot be
|
||||
* determined, it's set to 1024 (= 16 MiB).
|
||||
*
|
||||
* @return the current value
|
||||
*/
|
||||
public int cacheSize() {
|
||||
return sp.get_int(settings_pack.int_types.cache_size.swigValue());
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the disk write and read cache. It is specified in units of 16 KiB
|
||||
* blocks. Buffers that are part of a peer's send or receive buffer also
|
||||
* count against this limit. Send and receive buffers will never be
|
||||
* denied to be allocated, but they will cause the actual cached blocks
|
||||
* to be flushed or evicted. If this is set to -1, the cache size is
|
||||
* automatically set to the amount of physical RAM available in the
|
||||
* machine divided by 8. If the amount of physical RAM cannot be
|
||||
* determined, it's set to 1024 (= 16 MiB).
|
||||
*
|
||||
* @param value the new value
|
||||
* @return this
|
||||
*/
|
||||
public SettingsPack cacheSize(int value) {
|
||||
sp.set_int(settings_pack.int_types.cache_size.swigValue(), value);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return
|
||||
*/
|
||||
public int tickInterval() {
|
||||
return sp.get_int(settings_pack.int_types.tick_interval.swigValue());
|
||||
}
|
||||
|
||||
/**
|
||||
* Specifies the number of milliseconds between internal ticks. This is
|
||||
* the frequency with which bandwidth quota is distributed to peers. It
|
||||
* should not be more than one second (i.e. 1000 ms). Setting this to a
|
||||
* low value (around 100) means higher resolution bandwidth quota
|
||||
* distribution, setting it to a higher value saves CPU cycles.
|
||||
*
|
||||
* @param value
|
||||
*/
|
||||
public SettingsPack tickInterval(int value) {
|
||||
sp.set_int(settings_pack.int_types.tick_interval.swigValue(), value);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return
|
||||
*/
|
||||
public int inactivityTimeout() {
|
||||
return sp.get_int(settings_pack.int_types.inactivity_timeout.swigValue());
|
||||
}
|
||||
|
||||
/**
|
||||
* if a peer is uninteresting and uninterested for longer than this
|
||||
* number of seconds, it will be disconnected. default is 10 minutes
|
||||
*
|
||||
* @param value
|
||||
*/
|
||||
public SettingsPack inactivityTimeout(int value) {
|
||||
sp.set_int(settings_pack.int_types.inactivity_timeout.swigValue(), value);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return
|
||||
*/
|
||||
public boolean seedingOutgoingConnections() {
|
||||
return sp.get_bool(settings_pack.bool_types.seeding_outgoing_connections.swigValue());
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if seeding (and finished) torrents should attempt to make
|
||||
* outgoing connections or not. By default this is true. It may be set to
|
||||
* false in very specific applications where the cost of making outgoing
|
||||
* connections is high, and there are no or small benefits of doing so.
|
||||
* For instance, if no nodes are behind a firewall or a NAT, seeds don't
|
||||
* need to make outgoing connections.
|
||||
*
|
||||
* @param value
|
||||
*/
|
||||
public SettingsPack seedingOutgoingConnections(boolean value) {
|
||||
sp.set_bool(settings_pack.bool_types.seeding_outgoing_connections.swigValue(), value);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return
|
||||
*/
|
||||
public boolean anonymousMode() {
|
||||
return sp.get_bool(settings_pack.bool_types.anonymous_mode.swigValue());
|
||||
}
|
||||
|
||||
/**
|
||||
* defaults to false. When set to true, the client tries to hide its
|
||||
* identity to a certain degree. The peer-ID will no longer include the
|
||||
* client's fingerprint. The user-agent will be reset to an empty string.
|
||||
* It will also try to not leak other identifying information, such as
|
||||
* your local listen port, your IP etc.
|
||||
* <p>
|
||||
* If you're using I2P, a VPN or a proxy, it might make sense to enable
|
||||
* anonymous mode.
|
||||
*
|
||||
* @param value
|
||||
*/
|
||||
public SettingsPack anonymousMode(boolean value) {
|
||||
sp.set_bool(settings_pack.bool_types.anonymous_mode.swigValue(), value);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return
|
||||
*/
|
||||
public boolean enableDht() {
|
||||
return sp.get_bool(settings_pack.bool_types.enable_dht.swigValue());
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts the dht node and makes the trackerless service available to
|
||||
* torrents.
|
||||
*
|
||||
* @param value
|
||||
* @return this
|
||||
*/
|
||||
public SettingsPack enableDht(boolean value) {
|
||||
sp.set_bool(settings_pack.bool_types.enable_dht.swigValue(), value);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return
|
||||
*/
|
||||
public String listenInterfaces() {
|
||||
return sp.get_str(settings_pack.string_types.listen_interfaces.swigValue());
|
||||
}
|
||||
|
||||
/**
|
||||
* @param value
|
||||
* @return this
|
||||
*/
|
||||
public SettingsPack listenInterfaces(String value) {
|
||||
sp.set_str(settings_pack.string_types.listen_interfaces.swigValue(), value);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the current value
|
||||
* @see #stopTrackerTimeout(int)
|
||||
*/
|
||||
public int stopTrackerTimeout() {
|
||||
return sp.get_int(settings_pack.int_types.stop_tracker_timeout.swigValue());
|
||||
}
|
||||
|
||||
/**
|
||||
* {@code stop_tracker_timeout} is the number of seconds to wait when
|
||||
* sending a stopped message before considering a tracker to have
|
||||
* timed out. This is usually shorter, to make the client quit faster.
|
||||
* If the value is set to 0, the connections to trackers with the
|
||||
* stopped event are suppressed.
|
||||
*
|
||||
* @param value the new value
|
||||
* @return this
|
||||
*/
|
||||
public SettingsPack stopTrackerTimeout(int value) {
|
||||
sp.set_int(settings_pack.int_types.stop_tracker_timeout.swigValue(), value);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the current value
|
||||
* @see #alertQueueSize(int)
|
||||
*/
|
||||
public int alertQueueSize() {
|
||||
return sp.get_int(settings_pack.int_types.alert_queue_size.swigValue());
|
||||
}
|
||||
|
||||
/**
|
||||
* {@code alert_queue_size} is the maximum number of alerts queued up
|
||||
* internally. If alerts are not popped, the queue will eventually
|
||||
* fill up to this level.
|
||||
*
|
||||
* @param value the new value
|
||||
* @return this
|
||||
*/
|
||||
public SettingsPack alertQueueSize(int value) {
|
||||
sp.set_int(settings_pack.int_types.alert_queue_size.swigValue(), value);
|
||||
return this;
|
||||
}
|
||||
}
|
@ -0,0 +1,174 @@
|
||||
package com.frostwire.jlibtorrent;
|
||||
|
||||
import com.frostwire.jlibtorrent.swig.sha1_hash;
|
||||
import com.frostwire.jlibtorrent.swig.sha1_hash_vector;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
/**
|
||||
* This type holds a SHA-1 digest or any other kind of 20 byte
|
||||
* sequence. It implements a number of convenience functions, such
|
||||
* as bit operations, comparison operators etc.
|
||||
* <p>
|
||||
* In libtorrent it is primarily used to hold info-hashes, piece-hashes,
|
||||
* peer IDs, node IDs etc.
|
||||
*
|
||||
* @author gubatron
|
||||
* @author aldenml
|
||||
*/
|
||||
public final class Sha1Hash implements Comparable<Sha1Hash>, Cloneable {
|
||||
|
||||
private final sha1_hash h;
|
||||
|
||||
/**
|
||||
* @param h native object
|
||||
*/
|
||||
public Sha1Hash(sha1_hash h) {
|
||||
this.h = h;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bytes hash as an array of bytes
|
||||
*/
|
||||
public Sha1Hash(byte[] bytes) {
|
||||
if (bytes.length != 20) {
|
||||
throw new IllegalArgumentException("bytes array must be of length 20");
|
||||
}
|
||||
|
||||
this.h = new sha1_hash(Vectors.bytes2byte_vector(bytes));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param hex hex coded representation of the hash
|
||||
*/
|
||||
public Sha1Hash(String hex) {
|
||||
this(Hex.decode(hex));
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs an all-zero sha1-hash
|
||||
*/
|
||||
public Sha1Hash() {
|
||||
this(new sha1_hash());
|
||||
}
|
||||
|
||||
/**
|
||||
* returns an all-F sha1-hash. i.e. the maximum value
|
||||
* representable by a 160 bit number (20 bytes). This is
|
||||
* a static member function.
|
||||
*
|
||||
* @return the maximum number
|
||||
*/
|
||||
public static Sha1Hash max() {
|
||||
return new Sha1Hash(sha1_hash.max());
|
||||
}
|
||||
|
||||
/**
|
||||
* returns an all-zero sha1-hash. i.e. the minimum value
|
||||
* representable by a 160 bit number (20 bytes). This is
|
||||
* a static member function.
|
||||
*
|
||||
* @return the minimum number (zero)
|
||||
*/
|
||||
public static Sha1Hash min() {
|
||||
return new Sha1Hash(sha1_hash.min());
|
||||
}
|
||||
|
||||
static ArrayList<Sha1Hash> convert(sha1_hash_vector v) {
|
||||
int size = (int) v.size();
|
||||
ArrayList<Sha1Hash> l = new ArrayList<>(size);
|
||||
|
||||
for (int i = 0; i < size; i++) {
|
||||
l.add(new Sha1Hash(v.get(i)));
|
||||
}
|
||||
|
||||
return l;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the native object
|
||||
*/
|
||||
public sha1_hash swig() {
|
||||
return h;
|
||||
}
|
||||
|
||||
/**
|
||||
* set the sha1-hash to all zeroes.
|
||||
*/
|
||||
public void clear() {
|
||||
h.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* return true if the sha1-hash is all zero.
|
||||
*
|
||||
* @return true if zero
|
||||
*/
|
||||
public boolean isAllZeros() {
|
||||
return h.is_all_zeros();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the number of leading zeroes
|
||||
*/
|
||||
public int countLeadingZeroes() {
|
||||
return h.count_leading_zeroes();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the hex representation of this has.
|
||||
* <p>
|
||||
* This method uses internally the libtorrent to_hex function.
|
||||
*
|
||||
* @return the hex representation
|
||||
*/
|
||||
public String toHex() {
|
||||
return h.to_hex();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param o {@inheritDoc}
|
||||
* @return {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public int compareTo(Sha1Hash o) {
|
||||
return sha1_hash.compare(this.h, o.h);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an hex representation of this hash. Internally it
|
||||
* calls {@link #toHex()}.
|
||||
*
|
||||
* @return {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return toHex();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param obj {@inheritDoc}
|
||||
* @return {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (!(obj instanceof Sha1Hash)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return h.op_eq(((Sha1Hash) obj).h);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return h.hash_code();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Sha1Hash clone() {
|
||||
return new Sha1Hash(new sha1_hash(h));
|
||||
}
|
||||
}
|
@ -0,0 +1,59 @@
|
||||
package com.frostwire.jlibtorrent;
|
||||
|
||||
import com.frostwire.jlibtorrent.swig.metric_type_t;
|
||||
import com.frostwire.jlibtorrent.swig.stats_metric;
|
||||
|
||||
/**
|
||||
* Describes one statistics metric from the session.
|
||||
*
|
||||
* @author gubatron
|
||||
* @author aldenml
|
||||
*/
|
||||
public final class StatsMetric {
|
||||
|
||||
public static final String NET_SENT_PAYLOAD_BYTES_COUNTER_NAME = "net.sent_payload_bytes";
|
||||
public static final String NET_SENT_BYTES_COUNTER_NAME = "net.sent_bytes";
|
||||
public static final String NET_SENT_IP_OVERHEAD_BYTES_COUNTER_NAME = "net.sent_ip_overhead_bytes";
|
||||
public static final String NET_RECV_PAYLOAD_BYTES_COUNTER_NAME = "net.recv_payload_bytes";
|
||||
public static final String NET_RECV_BYTES_COUNTER_NAME = "net.recv_bytes";
|
||||
public static final String NET_RECV_IP_OVERHEAD_BYTES_COUNTER_NAME = "net.recv_ip_overhead_bytes";
|
||||
|
||||
public static final int NET_SENT_PAYLOAD_BYTES_COUNTER_INDEX = LibTorrent.findMetricIdx(NET_SENT_PAYLOAD_BYTES_COUNTER_NAME);
|
||||
public static final int NET_SENT_BYTES_COUNTER_INDEX = LibTorrent.findMetricIdx(NET_SENT_BYTES_COUNTER_NAME);
|
||||
public static final int NET_SENT_IP_OVERHEAD_BYTES_COUNTER_INDEX = LibTorrent.findMetricIdx(NET_SENT_IP_OVERHEAD_BYTES_COUNTER_NAME);
|
||||
public static final int NET_RECV_PAYLOAD_BYTES_COUNTER_INDEX = LibTorrent.findMetricIdx(NET_RECV_PAYLOAD_BYTES_COUNTER_NAME);
|
||||
public static final int NET_RECV_BYTES_COUNTER_INDEX = LibTorrent.findMetricIdx(NET_RECV_BYTES_COUNTER_NAME);
|
||||
public static final int NET_RECV_IP_OVERHEAD_BYTES_COUNTER_INDEX = LibTorrent.findMetricIdx(NET_RECV_IP_OVERHEAD_BYTES_COUNTER_NAME);
|
||||
|
||||
public static final String DHT_NODES_GAUGE_NAME = "dht.dht_nodes";
|
||||
public static final int DHT_NODES_GAUGE_INDEX = LibTorrent.findMetricIdx(DHT_NODES_GAUGE_NAME);
|
||||
|
||||
public static final int TYPE_COUNTER = metric_type_t.counter.swigValue();
|
||||
public static final int TYPE_GAUGE = metric_type_t.gauge.swigValue();
|
||||
public final String name;
|
||||
public final int valueIndex;
|
||||
public final int type;
|
||||
|
||||
StatsMetric(stats_metric sm) {
|
||||
this.name = sm.get_name();
|
||||
this.valueIndex = sm.getValue_index();
|
||||
this.type = sm.getType().swigValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return name + ":" + valueIndex + ":" + typeStr();
|
||||
}
|
||||
|
||||
private String typeStr() {
|
||||
String str = "unknown";
|
||||
|
||||
if (type == TYPE_COUNTER) {
|
||||
str = "counter";
|
||||
} else if (type == TYPE_GAUGE) {
|
||||
str = "gauge";
|
||||
}
|
||||
|
||||
return str;
|
||||
}
|
||||
}
|
@ -0,0 +1,57 @@
|
||||
package com.frostwire.jlibtorrent;
|
||||
|
||||
import com.frostwire.jlibtorrent.swig.storage_mode_t;
|
||||
|
||||
/**
|
||||
* Types of storage allocation used for {@link AddTorrentParams#storageMode(StorageMode)}.
|
||||
*
|
||||
* @author gubatron
|
||||
* @author aldenml
|
||||
*/
|
||||
public enum StorageMode {
|
||||
|
||||
/**
|
||||
* All pieces will be written to their final position, all files will be
|
||||
* allocated in full when the torrent is first started. This is done with
|
||||
* {@code fallocate()} and similar calls. This mode minimizes fragmentation.
|
||||
*/
|
||||
STORAGE_MODE_ALLOCATE(storage_mode_t.storage_mode_allocate.swigValue()),
|
||||
|
||||
/**
|
||||
* All pieces will be written to the place where they belong and sparse files
|
||||
* will be used. This is the recommended, and default mode.
|
||||
*/
|
||||
STORAGE_MODE_SPARSE(storage_mode_t.storage_mode_sparse.swigValue()),
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
UNKNOWN(-1);
|
||||
|
||||
private final int swigValue;
|
||||
|
||||
StorageMode(int swigValue) {
|
||||
this.swigValue = swigValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param swigValue the native value
|
||||
* @return the java enum
|
||||
*/
|
||||
public static StorageMode fromSwig(int swigValue) {
|
||||
StorageMode[] enumValues = StorageMode.class.getEnumConstants();
|
||||
for (StorageMode ev : enumValues) {
|
||||
if (ev.swig() == swigValue) {
|
||||
return ev;
|
||||
}
|
||||
}
|
||||
return UNKNOWN;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the native value
|
||||
*/
|
||||
public int swig() {
|
||||
return swigValue;
|
||||
}
|
||||
}
|
@ -0,0 +1,30 @@
|
||||
package com.frostwire.jlibtorrent;
|
||||
|
||||
import com.frostwire.jlibtorrent.swig.bdecode_node;
|
||||
import com.frostwire.jlibtorrent.swig.byte_vector;
|
||||
import com.frostwire.jlibtorrent.swig.entry;
|
||||
import com.frostwire.jlibtorrent.swig.string_view;
|
||||
import com.frostwire.jlibtorrent.swig.swig_plugin;
|
||||
import com.frostwire.jlibtorrent.swig.udp_endpoint;
|
||||
|
||||
/**
|
||||
* @author gubatron
|
||||
* @author aldenml
|
||||
*/
|
||||
class SwigPlugin extends swig_plugin {
|
||||
|
||||
private final Plugin p;
|
||||
|
||||
public SwigPlugin(Plugin p) {
|
||||
this.p = p;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean on_dht_request(string_view query, udp_endpoint source,
|
||||
bdecode_node message, entry response) {
|
||||
byte_vector v = query.to_bytes();
|
||||
String s = Vectors.byte_vector2ascii(v);
|
||||
return p.onDhtRequest(s, new UdpEndpoint(source),
|
||||
new BDecodeNode(message), new Entry(response));
|
||||
}
|
||||
}
|
@ -0,0 +1,85 @@
|
||||
package com.frostwire.jlibtorrent;
|
||||
|
||||
import com.frostwire.jlibtorrent.swig.address;
|
||||
import com.frostwire.jlibtorrent.swig.error_code;
|
||||
import com.frostwire.jlibtorrent.swig.tcp_endpoint;
|
||||
|
||||
/**
|
||||
* @author gubatron
|
||||
* @author aldenml
|
||||
*/
|
||||
public final class TcpEndpoint implements Cloneable {
|
||||
|
||||
private final tcp_endpoint endp;
|
||||
|
||||
/**
|
||||
* @param endp the native object
|
||||
*/
|
||||
public TcpEndpoint(tcp_endpoint endp) {
|
||||
this.endp = endp;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public TcpEndpoint() {
|
||||
this(new tcp_endpoint());
|
||||
}
|
||||
|
||||
/**
|
||||
* @param address the address
|
||||
* @param port the port
|
||||
*/
|
||||
public TcpEndpoint(Address address, int port) {
|
||||
this(new tcp_endpoint(address.swig(), port));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ip the address as an IP
|
||||
* @param port the port
|
||||
*/
|
||||
public TcpEndpoint(String ip, int port) {
|
||||
error_code ec = new error_code();
|
||||
address addr = address.from_string(ip, ec);
|
||||
if (ec.value() != 0) {
|
||||
throw new IllegalArgumentException(ec.message());
|
||||
}
|
||||
this.endp = new tcp_endpoint(addr, port);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the native object
|
||||
*/
|
||||
public tcp_endpoint swig() {
|
||||
return endp;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the address
|
||||
*/
|
||||
public Address address() {
|
||||
return new Address(endp.address());
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the port
|
||||
*/
|
||||
public int port() {
|
||||
return endp.port();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the string representation
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
address addr = endp.address();
|
||||
String s = Address.toString(addr);
|
||||
return (addr.is_v4() ? s : "[" + s + "]") + ":" + endp.port();
|
||||
}
|
||||
|
||||
@Override
|
||||
public TcpEndpoint clone() {
|
||||
return new TcpEndpoint(new tcp_endpoint(endp));
|
||||
}
|
||||
}
|
@ -0,0 +1,665 @@
|
||||
package com.frostwire.jlibtorrent;
|
||||
|
||||
import com.frostwire.jlibtorrent.swig.add_files_listener;
|
||||
import com.frostwire.jlibtorrent.swig.create_flags_t;
|
||||
import com.frostwire.jlibtorrent.swig.create_torrent;
|
||||
import com.frostwire.jlibtorrent.swig.error_code;
|
||||
import com.frostwire.jlibtorrent.swig.file_storage;
|
||||
import com.frostwire.jlibtorrent.swig.set_piece_hashes_listener;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
import static com.frostwire.jlibtorrent.swig.libtorrent.add_files_ex;
|
||||
import static com.frostwire.jlibtorrent.swig.libtorrent.set_piece_hashes_ex;
|
||||
|
||||
/**
|
||||
* @author gubatron
|
||||
* @author aldenml
|
||||
*/
|
||||
public final class TorrentBuilder {
|
||||
|
||||
/**
|
||||
* This will insert pad files to align the files to piece boundaries, for
|
||||
* optimized disk-I/O. This will minimize the number of bytes of pad-
|
||||
* files, to keep the impact down for clients that don't support
|
||||
* them.
|
||||
*/
|
||||
public static final create_flags_t OPTIMIZE_ALIGNMENT = create_torrent.optimize_alignment;
|
||||
/**
|
||||
* This will create a merkle hash tree torrent. A merkle torrent cannot
|
||||
* be opened in clients that don't specifically support merkle torrents.
|
||||
* The benefit is that the resulting torrent file will be much smaller and
|
||||
* not grow with more pieces. When this option is specified, it is
|
||||
* recommended to have a fairly small piece size, say 64 kiB.
|
||||
* When creating merkle torrents, the full hash tree is also generated
|
||||
* and should be saved off separately.
|
||||
*/
|
||||
public static final create_flags_t MERKLE = create_torrent.merkle;
|
||||
/**
|
||||
* This will include the file modification time as part of the torrent.
|
||||
* This is not enabled by default, as it might cause problems when you
|
||||
* create a torrent from separate files with the same content, hoping to
|
||||
* yield the same info-hash. If the files have different modification times,
|
||||
* with this option enabled, you would get different info-hashes for the
|
||||
* files.
|
||||
*/
|
||||
public static final create_flags_t MODIFICATION_TIME = create_torrent.modification_time;
|
||||
/**
|
||||
* If this flag is set, files that are symlinks get a symlink attribute
|
||||
* set on them and their data will not be included in the torrent. This
|
||||
* is useful if you need to reconstruct a file hierarchy which contains
|
||||
* symlinks.
|
||||
*/
|
||||
public static final create_flags_t SYMLINKS = create_torrent.symlinks;
|
||||
/**
|
||||
* To create a torrent that can be updated via a *mutable torrent*
|
||||
* (see BEP38_). This also needs to be enabled for torrents that update
|
||||
* another torrent.
|
||||
* <p>
|
||||
* BEP38: http://www.bittorrent.org/beps/bep_0038.html
|
||||
*/
|
||||
public static final create_flags_t MUTABLE_TORRENT_SUPPORT = create_torrent.mutable_torrent_support;
|
||||
private final List<String> urlSeeds;
|
||||
private final List<String> httpSeeds;
|
||||
private final List<Pair<String, Integer>> nodes;
|
||||
private final List<Pair<String, Integer>> trackers;
|
||||
private final List<Sha1Hash> similarTorrents;
|
||||
private final List<String> collections;
|
||||
private File path;
|
||||
private int pieceSize;
|
||||
private int padFileLimit;
|
||||
private create_flags_t flags;
|
||||
private int alignment;
|
||||
private String comment;
|
||||
private String creator;
|
||||
private boolean priv;
|
||||
private Listener listener;
|
||||
|
||||
public TorrentBuilder() {
|
||||
this.pieceSize = 0;
|
||||
this.padFileLimit = -1;
|
||||
this.flags = OPTIMIZE_ALIGNMENT;
|
||||
this.alignment = -1;
|
||||
|
||||
this.urlSeeds = new LinkedList<>();
|
||||
this.httpSeeds = new LinkedList<>();
|
||||
this.nodes = new LinkedList<>();
|
||||
this.trackers = new LinkedList<>();
|
||||
|
||||
this.similarTorrents = new LinkedList<>();
|
||||
this.collections = new LinkedList<>();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return
|
||||
*/
|
||||
public File path() {
|
||||
return path;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the file specified by {@code value}
|
||||
*
|
||||
* @param value
|
||||
* @return
|
||||
*/
|
||||
public TorrentBuilder path(File value) {
|
||||
this.path = value;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return
|
||||
*/
|
||||
public int pieceSize() {
|
||||
return pieceSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* The size of each piece in bytes. It must
|
||||
* be a multiple of 16 kiB. If a piece size of 0 is specified, a
|
||||
* {@code pieceSize} will be calculated such that the torrent file is roughly 40 kB.
|
||||
*
|
||||
* @param value
|
||||
* @return
|
||||
*/
|
||||
public TorrentBuilder pieceSize(int value) {
|
||||
this.pieceSize = value;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return
|
||||
*/
|
||||
public int padFileLimit() {
|
||||
return padFileLimit;
|
||||
}
|
||||
|
||||
/**
|
||||
* If a ``pad_size_limit`` is specified (other than -1), any file larger than
|
||||
* the specified number of bytes will be preceded by a pad file to align it
|
||||
* with the start of a piece. The pad_file_limit is ignored unless the
|
||||
* {@link OPTIMIZE_ALIGNMENT} flag is passed. Typically it doesn't make sense
|
||||
* to set this any lower than 4kiB.
|
||||
*
|
||||
* @param value
|
||||
* @return
|
||||
*/
|
||||
public TorrentBuilder padFileLimit(int value) {
|
||||
this.padFileLimit = value;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return
|
||||
*/
|
||||
public create_flags_t flags() {
|
||||
return flags;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specifies options for the torrent creation. It can
|
||||
* be any combination of the flags defined by {@link create_flags_t}
|
||||
*
|
||||
* @param value
|
||||
* @return
|
||||
*/
|
||||
public TorrentBuilder flags(create_flags_t value) {
|
||||
this.flags = value;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return
|
||||
*/
|
||||
public int alignment() {
|
||||
return alignment;
|
||||
}
|
||||
|
||||
/**
|
||||
* Used when pad files are enabled. This is the size
|
||||
* eligible files are aligned to. The default is -1, which means the
|
||||
* piece size of the torrent.
|
||||
*
|
||||
* @param value
|
||||
* @return
|
||||
*/
|
||||
public TorrentBuilder alignment(int value) {
|
||||
this.alignment = value;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* The comment for the torrent. The comment in a torrent file is optional.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public String comment() {
|
||||
return comment;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the comment for the torrent. The comment in a torrent file is optional.
|
||||
*
|
||||
* @param value
|
||||
* @return
|
||||
*/
|
||||
public TorrentBuilder comment(String value) {
|
||||
this.comment = value;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* The creator of the torrent. This is optional.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public String creator() {
|
||||
return creator;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the creator of the torrent. This is optional.
|
||||
*
|
||||
* @param value
|
||||
* @return
|
||||
*/
|
||||
public TorrentBuilder creator(String value) {
|
||||
this.creator = value;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return
|
||||
*/
|
||||
public List<String> urlSeeds() {
|
||||
return urlSeeds;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param value
|
||||
* @return
|
||||
*/
|
||||
public TorrentBuilder addUrlSeeds(List<String> value) {
|
||||
if (value != null) {
|
||||
this.urlSeeds.addAll(value);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* This adds a url seed to the torrent. You can have any number of url seeds. For a
|
||||
* single file torrent, this should be an HTTP url, pointing to a file with identical
|
||||
* content as the file of the torrent. For a multi-file torrent, it should point to
|
||||
* a directory containing a directory with the same name as this torrent, and all the
|
||||
* files of the torrent in it.
|
||||
*
|
||||
* @param value
|
||||
* @return
|
||||
*/
|
||||
public TorrentBuilder addUrlSeed(String value) {
|
||||
if (value != null) {
|
||||
this.urlSeeds.add(value);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return
|
||||
*/
|
||||
public List<String> httpSeeds() {
|
||||
return httpSeeds;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param value
|
||||
* @return
|
||||
*/
|
||||
public TorrentBuilder addHttpSeeds(List<String> value) {
|
||||
if (value != null) {
|
||||
this.httpSeeds.addAll(value);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* This adds a HTTP seed to the torrent. You can have any number of url seeds. For a
|
||||
* single file torrent, this should be an HTTP url, pointing to a file with identical
|
||||
* content as the file of the torrent. For a multi-file torrent, it should point to
|
||||
* a directory containing a directory with the same name as this torrent, and all the
|
||||
* files of the torrent in it.
|
||||
*
|
||||
* @param value
|
||||
* @return
|
||||
*/
|
||||
public TorrentBuilder addHttpSeed(String value) {
|
||||
if (value != null) {
|
||||
this.httpSeeds.add(value);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return
|
||||
*/
|
||||
public List<Pair<String, Integer>> nodes() {
|
||||
return nodes;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param value
|
||||
* @return
|
||||
*/
|
||||
public TorrentBuilder addNodes(List<Pair<String, Integer>> value) {
|
||||
if (value != null) {
|
||||
this.nodes.addAll(value);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* This adds a DHT node to the torrent. This especially useful if you're creating a
|
||||
* tracker less torrent. It can be used by clients to bootstrap their DHT node from.
|
||||
* The node is a hostname and a port number where there is a DHT node running.
|
||||
* You can have any number of DHT nodes in a torrent.
|
||||
*
|
||||
* @param value
|
||||
* @return
|
||||
*/
|
||||
public TorrentBuilder addNode(Pair<String, Integer> value) {
|
||||
if (value != null) {
|
||||
this.nodes.add(value);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return
|
||||
*/
|
||||
public List<Pair<String, Integer>> trackers() {
|
||||
return trackers;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param value
|
||||
* @return
|
||||
*/
|
||||
public TorrentBuilder addTrackers(List<Pair<String, Integer>> value) {
|
||||
if (value != null) {
|
||||
this.trackers.addAll(value);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param value
|
||||
* @return
|
||||
*/
|
||||
public TorrentBuilder addTracker(Pair<String, Integer> value) {
|
||||
if (value != null) {
|
||||
this.trackers.add(value);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a tracker to the torrent. This is not strictly required, but most torrents
|
||||
* use a tracker as their main source of peers. The url should be an http:// or udp://
|
||||
* url to a machine running a bittorrent tracker that accepts announces for this torrent's
|
||||
* info-hash. The tier is the fallback priority of the tracker. All trackers with tier 0 are
|
||||
* tried first (in any order). If all fail, trackers with tier 1 are tried. If all of those
|
||||
* fail, trackers with tier 2 are tried, and so on.
|
||||
*
|
||||
* @param url
|
||||
* @param tier
|
||||
* @return
|
||||
*/
|
||||
public TorrentBuilder addTracker(String url, int tier) {
|
||||
return addTracker(new Pair<>(url, tier));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param url
|
||||
* @return
|
||||
*/
|
||||
public TorrentBuilder addTracker(String url) {
|
||||
return addTracker(url, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return
|
||||
*/
|
||||
public boolean isPrivate() {
|
||||
return priv;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the private flag of the torrent.
|
||||
* <p>
|
||||
* Torrents with the private flag set ask clients to not use any other
|
||||
* sources than the tracker for peers, and to not advertise itself publicly,
|
||||
* apart from the tracker.
|
||||
*
|
||||
* @param value
|
||||
* @return
|
||||
*/
|
||||
public TorrentBuilder setPrivate(boolean value) {
|
||||
this.priv = value;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return
|
||||
*/
|
||||
public List<Sha1Hash> similarTorrents() {
|
||||
return similarTorrents;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param value
|
||||
* @return
|
||||
*/
|
||||
public TorrentBuilder addSimilarTorrents(List<Sha1Hash> value) {
|
||||
if (value != null) {
|
||||
this.similarTorrents.addAll(value);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add similar torrents (by info-hash).
|
||||
* <p>
|
||||
* Similar torrents are expected to share some files with this torrent.
|
||||
* Torrents sharing a collection name with this torrent are also expected
|
||||
* to share files with this torrent. A torrent may have more than one
|
||||
* collection and more than one similar torrents. For more information,
|
||||
* see BEP 38.
|
||||
* <p>
|
||||
* BEP 38: http://www.bittorrent.org/beps/bep_0038.html
|
||||
*
|
||||
* @param value
|
||||
* @return
|
||||
*/
|
||||
public TorrentBuilder addSimilarTorrent(Sha1Hash value) {
|
||||
if (value != null) {
|
||||
this.similarTorrents.add(value);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return
|
||||
*/
|
||||
public List<String> collections() {
|
||||
return collections;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param value
|
||||
* @return
|
||||
*/
|
||||
public TorrentBuilder addCollections(List<String> value) {
|
||||
if (value != null) {
|
||||
this.collections.addAll(value);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add collections of similar torrents.
|
||||
* <p>
|
||||
* Similar torrents are expected to share some files with this torrent.
|
||||
* Torrents sharing a collection name with this torrent are also expected
|
||||
* to share files with this torrent. A torrent may have more than one
|
||||
* collection and more than one similar torrents. For more information,
|
||||
* see BEP 38.
|
||||
* <p>
|
||||
* BEP 38: http://www.bittorrent.org/beps/bep_0038.html
|
||||
*
|
||||
* @param value
|
||||
* @return
|
||||
*/
|
||||
public TorrentBuilder addCollection(String value) {
|
||||
if (value != null) {
|
||||
this.collections.add(value);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return
|
||||
*/
|
||||
public Listener listener() {
|
||||
return listener;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param value
|
||||
* @return
|
||||
*/
|
||||
public TorrentBuilder listener(Listener value) {
|
||||
this.listener = value;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function will generate a result withe the .torrent file as a bencode tree.
|
||||
*
|
||||
* @return
|
||||
* @throws IOException
|
||||
*/
|
||||
public Result generate() throws IOException {
|
||||
if (path == null) {
|
||||
throw new IOException("path can't be null");
|
||||
}
|
||||
|
||||
File absPath = path.getAbsoluteFile();
|
||||
|
||||
file_storage fs = new file_storage();
|
||||
add_files_listener l1 = new add_files_listener() {
|
||||
@Override
|
||||
public boolean pred(String p) {
|
||||
return listener == null || listener.accept(p);
|
||||
}
|
||||
};
|
||||
add_files_ex(fs, absPath.getPath(), l1, flags);
|
||||
if (fs.total_size() == 0) {
|
||||
throw new IOException("content total size can't be 0");
|
||||
}
|
||||
create_torrent t = new create_torrent(fs, pieceSize, padFileLimit, flags, alignment);
|
||||
final int numPieces = t.num_pieces();
|
||||
set_piece_hashes_listener l2 = new set_piece_hashes_listener() {
|
||||
@Override
|
||||
public void progress(int i) {
|
||||
if (listener != null) {
|
||||
listener.progress(i, numPieces);
|
||||
}
|
||||
}
|
||||
};
|
||||
File parent = absPath.getParentFile();
|
||||
if (parent == null) {
|
||||
throw new IOException("path's parent can't be null");
|
||||
}
|
||||
error_code ec = new error_code();
|
||||
set_piece_hashes_ex(t, parent.getAbsolutePath(), l2, ec);
|
||||
if (ec.value() != 0) {
|
||||
throw new IOException(ec.message());
|
||||
}
|
||||
|
||||
if (comment != null) {
|
||||
t.set_comment(comment);
|
||||
}
|
||||
if (creator != null) {
|
||||
t.set_creator(creator);
|
||||
}
|
||||
for (String s : urlSeeds) {
|
||||
t.add_url_seed(s);
|
||||
}
|
||||
for (String s : httpSeeds) {
|
||||
t.add_http_seed(s);
|
||||
}
|
||||
for (Pair<String, Integer> n : nodes) {
|
||||
t.add_node(n.to_string_int_pair());
|
||||
}
|
||||
for (Pair<String, Integer> tr : trackers) {
|
||||
t.add_tracker(tr.first, tr.second);
|
||||
}
|
||||
if (priv) {
|
||||
t.set_priv(priv);
|
||||
}
|
||||
|
||||
if (!similarTorrents.isEmpty()) {
|
||||
for (Sha1Hash h : similarTorrents) {
|
||||
t.add_similar_torrent(h.swig());
|
||||
}
|
||||
}
|
||||
if (!collections.isEmpty()) {
|
||||
for (String s : collections) {
|
||||
t.add_collection(s);
|
||||
}
|
||||
}
|
||||
|
||||
return new Result(t);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public interface Listener {
|
||||
|
||||
/**
|
||||
* @param filename
|
||||
* @return
|
||||
*/
|
||||
boolean accept(String filename);
|
||||
|
||||
/**
|
||||
* @param pieceIndex
|
||||
* @param numPieces
|
||||
*/
|
||||
void progress(int pieceIndex, int numPieces);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public static final class Result {
|
||||
|
||||
private final create_torrent t;
|
||||
private final Entry entry;
|
||||
|
||||
private Result(create_torrent t) {
|
||||
this.t = t;
|
||||
this.entry = new Entry(t.generate());
|
||||
}
|
||||
|
||||
/**
|
||||
* @return
|
||||
*/
|
||||
public Entry entry() {
|
||||
return entry;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return
|
||||
*/
|
||||
public int numPieces() {
|
||||
return t.num_pieces();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return
|
||||
*/
|
||||
public int pieceLength() {
|
||||
return t.piece_length();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param index
|
||||
* @return
|
||||
*/
|
||||
public int pieceSize(int index) {
|
||||
return t.piece_size(index);
|
||||
}
|
||||
|
||||
/**
|
||||
* This function returns the merkle hash tree, if the torrent was created
|
||||
* as a merkle torrent. The tree is created by {@link #generate()} and won't
|
||||
* be valid until that function has been called.
|
||||
* <p>
|
||||
* When creating a merkle tree torrent, the actual tree itself has to
|
||||
* be saved off separately and fed into libtorrent the first time you start
|
||||
* seeding it, through the {@link TorrentInfo#merkleTree(List)} function.
|
||||
* From that point onwards, the tree will be saved in the resume data.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public ArrayList<Sha1Hash> merkleTree() {
|
||||
return Sha1Hash.convert(t.merkle_tree());
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,169 @@
|
||||
package com.frostwire.jlibtorrent;
|
||||
|
||||
import com.frostwire.jlibtorrent.swig.libtorrent;
|
||||
import com.frostwire.jlibtorrent.swig.torrent_flags_t;
|
||||
|
||||
/**
|
||||
* @author gubatron
|
||||
* @author aldenml
|
||||
*/
|
||||
public final class TorrentFlags {
|
||||
|
||||
// If ``seed_mode`` is set, libtorrent will assume that all files
|
||||
// are present for this torrent and that they all match the hashes in
|
||||
// the torrent file. Each time a peer requests to download a block,
|
||||
// the piece is verified against the hash, unless it has been verified
|
||||
// already. If a hash fails, the torrent will automatically leave the
|
||||
// seed mode and recheck all the files. The use case for this mode is
|
||||
// if a torrent is created and seeded, or if the user already know
|
||||
// that the files are complete, this is a way to avoid the initial
|
||||
// file checks, and significantly reduce the startup time.
|
||||
//
|
||||
// Setting ``seed_mode`` on a torrent without metadata (a
|
||||
// .torrent file) is a no-op and will be ignored.
|
||||
//
|
||||
// If resume data is passed in with this torrent, the seed mode saved
|
||||
// in there will override the seed mode you set here.
|
||||
public static final torrent_flags_t SEED_MODE = libtorrent.getSeed_mode();
|
||||
// If ``upload_mode`` is set, the torrent will be initialized in
|
||||
// upload-mode, which means it will not make any piece requests. This
|
||||
// state is typically entered on disk I/O errors, and if the torrent
|
||||
// is also auto managed, it will be taken out of this state
|
||||
// periodically (see ``settings_pack::optimistic_disk_retry``).
|
||||
//
|
||||
// This mode can be used to avoid race conditions when
|
||||
// adjusting priorities of pieces before allowing the torrent to start
|
||||
// downloading.
|
||||
//
|
||||
// If the torrent is auto-managed (``auto_managed``), the torrent
|
||||
// will eventually be taken out of upload-mode, regardless of how it
|
||||
// got there. If it's important to manually control when the torrent
|
||||
// leaves upload mode, don't make it auto managed.
|
||||
public static final torrent_flags_t UPLOAD_MODE = libtorrent.getUpload_mode();
|
||||
// determines if the torrent should be added in *share mode* or not.
|
||||
// Share mode indicates that we are not interested in downloading the
|
||||
// torrent, but merely want to improve our share ratio (i.e. increase
|
||||
// it). A torrent started in share mode will do its best to never
|
||||
// download more than it uploads to the swarm. If the swarm does not
|
||||
// have enough demand for upload capacity, the torrent will not
|
||||
// download anything. This mode is intended to be safe to add any
|
||||
// number of torrents to, without manual screening, without the risk
|
||||
// of downloading more than is uploaded.
|
||||
//
|
||||
// A torrent in share mode sets the priority to all pieces to 0,
|
||||
// except for the pieces that are downloaded, when pieces are decided
|
||||
// to be downloaded. This affects the progress bar, which might be set
|
||||
// to "100% finished" most of the time. Do not change file or piece
|
||||
// priorities for torrents in share mode, it will make it not work.
|
||||
//
|
||||
// The share mode has one setting, the share ratio target, see
|
||||
// ``settings_pack::share_mode_target`` for more info.
|
||||
public static final torrent_flags_t SHARE_MODE = libtorrent.getShare_mode();
|
||||
// determines if the IP filter should apply to this torrent or not. By
|
||||
// default all torrents are subject to filtering by the IP filter
|
||||
// (i.e. this flag is set by default). This is useful if certain
|
||||
// torrents needs to be exempt for some reason, being an auto-update
|
||||
// torrent for instance.
|
||||
public static final torrent_flags_t APPLY_IP_FILTER = libtorrent.getApply_ip_filter();
|
||||
// specifies whether or not the torrent is to be started in a paused
|
||||
// state. I.e. it won't connect to the tracker or any of the peers
|
||||
// until it's resumed. This is typically a good way of avoiding race
|
||||
// conditions when setting configuration options on torrents before
|
||||
// starting them.
|
||||
public static final torrent_flags_t PAUSED = libtorrent.getPaused();
|
||||
// If the torrent is auto-managed (``auto_managed``), the torrent
|
||||
// may be resumed at any point, regardless of how it paused. If it's
|
||||
// important to manually control when the torrent is paused and
|
||||
// resumed, don't make it auto managed.
|
||||
//
|
||||
// If ``auto_managed`` is set, the torrent will be queued,
|
||||
// started and seeded automatically by libtorrent. When this is set,
|
||||
// the torrent should also be started as paused. The default queue
|
||||
// order is the order the torrents were added. They are all downloaded
|
||||
// in that order. For more details, see queuing_.
|
||||
//
|
||||
// If you pass in resume data, the auto_managed state of the torrent
|
||||
// when the resume data was saved will override the auto_managed state
|
||||
// you pass in here. You can override this by setting
|
||||
// ``override_resume_data``.
|
||||
public static final torrent_flags_t AUTO_MANAGED = libtorrent.getAuto_managed();
|
||||
public static final torrent_flags_t DUPLICATE_IS_ERROR = libtorrent.getDuplicate_is_error();
|
||||
// on by default and means that this torrent will be part of state
|
||||
// updates when calling post_torrent_updates().
|
||||
public static final torrent_flags_t UPDATE_SUBSCRIBE = libtorrent.getUpdate_subscribe();
|
||||
// sets the torrent into super seeding mode. If the torrent is not a
|
||||
// seed, this flag has no effect. It has the same effect as calling
|
||||
// ``torrent_handle::super_seeding(true)`` on the torrent handle
|
||||
// immediately after adding it.
|
||||
public static final torrent_flags_t SUPER_SEEDING = libtorrent.getSuper_seeding();
|
||||
// sets the sequential download state for the torrent. It has the same
|
||||
// effect as calling ``torrent_handle::sequential_download(true)`` on
|
||||
// the torrent handle immediately after adding it.
|
||||
public static final torrent_flags_t SEQUENTIAL_DOWNLOAD = libtorrent.getSequential_download();
|
||||
// When this flag is set, the
|
||||
// torrent will *force stop* whenever it transitions from a
|
||||
// non-data-transferring state into a data-transferring state (referred to
|
||||
// as being ready to download or seed). This is useful for torrents that
|
||||
// should not start downloading or seeding yet, but want to be made ready
|
||||
// to do so. A torrent may need to have its files checked for instance, so
|
||||
// it needs to be started and possibly queued for checking (auto-managed
|
||||
// and started) but as soon as it's done, it should be stopped.
|
||||
//
|
||||
// *Force stopped* means auto-managed is set to false and it's paused. As
|
||||
// if auto_manage(false) and pause() were called on the torrent.
|
||||
//
|
||||
// Note that the torrent may transition into a downloading state while
|
||||
// calling this function, and since the logic is edge triggered you may
|
||||
// miss the edge. To avoid this race, if the torrent already is in a
|
||||
// downloading state when this call is made, it will trigger the
|
||||
// stop-when-ready immediately.
|
||||
//
|
||||
// When the stop-when-ready logic fires, the flag is cleared. Any
|
||||
// subsequent transitions between downloading and non-downloading states
|
||||
// will not be affected, until this function is used to set it again.
|
||||
//
|
||||
// The behavior is more robust when setting this flag as part of adding
|
||||
// the torrent. See add_torrent_params.
|
||||
//
|
||||
// The stop-when-ready flag fixes the inherent race condition of waiting
|
||||
// for the state_changed_alert and then call pause(). The download/seeding
|
||||
// will most likely start in between posting the alert and receiving the
|
||||
// call to pause.
|
||||
public static final torrent_flags_t STOP_WHEN_READY = libtorrent.getStop_when_ready();
|
||||
// when this flag is set, the tracker list in the add_torrent_params
|
||||
// object override any trackers from the torrent file. If the flag is
|
||||
// not set, the trackers from the add_torrent_params object will be
|
||||
// added to the list of trackers used by the torrent.
|
||||
public static final torrent_flags_t OVERRIDE_TRACKERS = libtorrent.getOverride_trackers();
|
||||
// If this flag is set, the web seeds from the add_torrent_params
|
||||
// object will override any web seeds in the torrent file. If it's not
|
||||
// set, web seeds in the add_torrent_params object will be added to the
|
||||
// list of web seeds used by the torrent.
|
||||
public static final torrent_flags_t OVERRIDE_WEB_SEEDS = libtorrent.getOverride_web_seeds();
|
||||
/**
|
||||
* If this flag is set (which it is by default) the torrent will be
|
||||
* considered needing to save its resume data immediately as it's
|
||||
* added. New torrents that don't have any resume data should do that.
|
||||
* This flag is cleared by a successful call to save_resume_data()
|
||||
*/
|
||||
public static final torrent_flags_t NEED_SAVE_RESUME = libtorrent.getNeed_save_resume();
|
||||
/**
|
||||
* Set this flag to disable DHT for this torrent. This lets you have the DHT
|
||||
* enabled for the whole client, and still have specific torrents not
|
||||
* participating in it. i.e. not announcing to the DHT nor picking up peers
|
||||
* from it.
|
||||
*/
|
||||
public static final torrent_flags_t DISABLE_DHT = libtorrent.getDisable_dht();
|
||||
/**
|
||||
* Set this flag to disable local service discovery for this torrent.
|
||||
*/
|
||||
public static final torrent_flags_t DISABLE_LSD = libtorrent.getDisable_lsd();
|
||||
/**
|
||||
* Set this flag to disable peer exchange for this torrent.
|
||||
*/
|
||||
public static final torrent_flags_t DISABLE_PEX = libtorrent.getDisable_pex();
|
||||
public static final torrent_flags_t ALL = libtorrent.getAll();
|
||||
|
||||
private TorrentFlags() {
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,709 @@
|
||||
package com.frostwire.jlibtorrent;
|
||||
|
||||
import com.frostwire.jlibtorrent.swig.announce_entry_vector;
|
||||
import com.frostwire.jlibtorrent.swig.bdecode_node;
|
||||
import com.frostwire.jlibtorrent.swig.byte_vector;
|
||||
import com.frostwire.jlibtorrent.swig.create_torrent;
|
||||
import com.frostwire.jlibtorrent.swig.error_code;
|
||||
import com.frostwire.jlibtorrent.swig.libtorrent;
|
||||
import com.frostwire.jlibtorrent.swig.libtorrent_jni;
|
||||
import com.frostwire.jlibtorrent.swig.sha1_hash_vector;
|
||||
import com.frostwire.jlibtorrent.swig.string_int_pair;
|
||||
import com.frostwire.jlibtorrent.swig.string_int_pair_vector;
|
||||
import com.frostwire.jlibtorrent.swig.string_string_pair_vector;
|
||||
import com.frostwire.jlibtorrent.swig.string_vector;
|
||||
import com.frostwire.jlibtorrent.swig.torrent_info;
|
||||
import com.frostwire.jlibtorrent.swig.web_seed_entry_vector;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.MappedByteBuffer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* This class represents the information stored in a .torrent file
|
||||
*
|
||||
* @author gubatron
|
||||
* @author aldenml
|
||||
*/
|
||||
public final class TorrentInfo {
|
||||
|
||||
private final torrent_info ti;
|
||||
|
||||
public TorrentInfo(torrent_info ti) {
|
||||
this.ti = ti;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load the torrent file and decode it inside the constructor, for convenience.
|
||||
* <p>
|
||||
* This might not be the most suitable for applications that
|
||||
* want to be able to report detailed errors on what might go wrong.
|
||||
*
|
||||
* @param torrent the torrent file
|
||||
*/
|
||||
public TorrentInfo(File torrent) {
|
||||
this(bdecode0(torrent));
|
||||
}
|
||||
|
||||
/**
|
||||
* Load the torrent data and decode it inside the constructor, for convenience.
|
||||
* <p>
|
||||
* This might not be the most suitable for applications that
|
||||
* want to be able to report detailed errors on what might go wrong.
|
||||
*
|
||||
* @param data the torrent data
|
||||
*/
|
||||
public TorrentInfo(byte[] data) {
|
||||
this(bdecode0(data));
|
||||
}
|
||||
|
||||
public TorrentInfo(MappedByteBuffer buffer) {
|
||||
try {
|
||||
long ptr = libtorrent_jni.directBufferAddress(buffer);
|
||||
long size = libtorrent_jni.directBufferCapacity(buffer);
|
||||
|
||||
error_code ec = new error_code();
|
||||
this.ti = new torrent_info(ptr, (int) size, ec);
|
||||
|
||||
if (ec.value() != 0) {
|
||||
throw new IllegalArgumentException("Can't decode data: " + ec.message());
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
throw new IllegalArgumentException("Can't decode data mapped buffer: " + e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
public static TorrentInfo bdecode(byte[] data) {
|
||||
return new TorrentInfo(bdecode0(data));
|
||||
}
|
||||
|
||||
// helper function
|
||||
static ArrayList<AnnounceEntry> trackers(announce_entry_vector v) {
|
||||
int size = (int) v.size();
|
||||
ArrayList<AnnounceEntry> l = new ArrayList<>(size);
|
||||
|
||||
for (int i = 0; i < size; i++) {
|
||||
l.add(new AnnounceEntry(v.get(i)));
|
||||
}
|
||||
|
||||
return l;
|
||||
}
|
||||
|
||||
private static torrent_info bdecode0(File file) {
|
||||
try {
|
||||
byte[] data = Files.bytes(file);
|
||||
return bdecode0(data);
|
||||
} catch (IOException e) {
|
||||
throw new IllegalArgumentException("Can't decode data from file: " + file, e);
|
||||
}
|
||||
}
|
||||
|
||||
private static torrent_info bdecode0(byte[] data) {
|
||||
byte_vector buffer = Vectors.bytes2byte_vector(data);
|
||||
bdecode_node n = new bdecode_node();
|
||||
error_code ec = new error_code();
|
||||
int ret = bdecode_node.bdecode(buffer, n, ec);
|
||||
|
||||
if (ret == 0) {
|
||||
ec.clear();
|
||||
torrent_info ti = new torrent_info(n, ec);
|
||||
buffer.clear(); // prevents GC
|
||||
if (ec.value() != 0) {
|
||||
throw new IllegalArgumentException("Can't decode data: " + ec.message());
|
||||
}
|
||||
return ti;
|
||||
} else {
|
||||
throw new IllegalArgumentException("Can't decode data: " + ec.message());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the native object
|
||||
*/
|
||||
public torrent_info swig() {
|
||||
return this.ti;
|
||||
}
|
||||
|
||||
/**
|
||||
* The {@link FileStorage} object contains the information on
|
||||
* how to map the pieces to files.
|
||||
* <p>
|
||||
* It is separated from the {@link TorrentInfo} object because when creating torrents
|
||||
* a storage object needs to be created without having a torrent file. When renaming files
|
||||
* in a storage, the storage needs to make its own copy of the {@link FileStorage} in order
|
||||
* to make its mapping differ from the one in the torrent file.
|
||||
*
|
||||
* @return the files storage
|
||||
*/
|
||||
public FileStorage files() {
|
||||
return new FileStorage(ti.files(), ti);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the original (unmodified) file storage for this torrent. This
|
||||
* is used by the web server connection, which needs to request files with the original
|
||||
* names. Filename may be changed using {@link #renameFile(int, String)}.
|
||||
*
|
||||
* @return the original file storage
|
||||
*/
|
||||
public FileStorage origFiles() {
|
||||
return new FileStorage(ti.orig_files(), ti);
|
||||
}
|
||||
|
||||
/**
|
||||
* Renames a the file with the specified index to the new name. The new
|
||||
* filename is reflected by the {@link FileStorage} returned by {@link #files()}
|
||||
* but not by the one returned by {@link #origFiles()}.
|
||||
* <p>
|
||||
* If you want to rename the base name of the torrent (for a multifile
|
||||
* torrent), you can copy the {@code FileStorage} (see {@link #files()} and
|
||||
* {@link #origFiles()} ), change the name, and then use
|
||||
* {@link #remapFiles(FileStorage)}.
|
||||
* <p>
|
||||
* The {@code newFilename} can both be a relative path, in which case the
|
||||
* file name is relative to the {@code savePath} of the torrent. If the
|
||||
* {@code newFilename} is an absolute path then the file is detached from
|
||||
* the {@code savePath} of the torrent. In this case the file is not moved when
|
||||
* {@link TorrentHandle#moveStorage(String, MoveFlags)} is invoked.
|
||||
*
|
||||
* @param index the file index to rename
|
||||
* @param newFilename the new file name
|
||||
*/
|
||||
public void renameFile(int index, String newFilename) {
|
||||
ti.rename_file(index, newFilename);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remaps the file storage to a new file layout. This can be used to, for
|
||||
* instance, download all data in a torrent to a single file, or to a
|
||||
* number of fixed size sector aligned files, regardless of the number
|
||||
* and sizes of the files in the torrent.
|
||||
* <p>
|
||||
* The new specified {@link FileStorage} must have the exact same size as
|
||||
* the current one.
|
||||
*
|
||||
* @param f the file storage
|
||||
*/
|
||||
public void remapFiles(FileStorage f) {
|
||||
ti.remap_files(f.swig());
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a tracker to the announce-list.
|
||||
*
|
||||
* @param url the tracker url
|
||||
*/
|
||||
public void addTracker(String url) {
|
||||
ti.add_tracker(url);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a tracker to the announce-list. The {@code tier} determines the order in
|
||||
* which the trackers are to be tried.
|
||||
*
|
||||
* @param url the tracker url
|
||||
* @param tier the tracker tier
|
||||
*/
|
||||
public void addTracker(String url, int tier) {
|
||||
ti.add_tracker(url, tier);
|
||||
}
|
||||
|
||||
/**
|
||||
* Will return a sorted list with the trackers of this torrent info.
|
||||
* <p>
|
||||
* Each announce entry contains a string, which is the tracker url, and a tier index. The
|
||||
* tier index is the high-level priority. No matter which trackers that works or not, the
|
||||
* ones with lower tier will always be tried before the one with higher tier number.
|
||||
*
|
||||
* @return the list of trackers
|
||||
*/
|
||||
public ArrayList<AnnounceEntry> trackers() {
|
||||
return trackers(ti.trackers());
|
||||
}
|
||||
|
||||
/**
|
||||
* This function is related to BEP38_ (mutable torrents). The
|
||||
* vector returned from this correspond to the "similar" in the
|
||||
* .torrent file. The info-hashes from within the info-dict
|
||||
* and from outside of it are included.
|
||||
* <p>
|
||||
* BEP38: http://www.bittorrent.org/beps/bep_0038.html
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public ArrayList<Sha1Hash> similarTorrents() {
|
||||
return Sha1Hash.convert(ti.similar_torrents());
|
||||
}
|
||||
|
||||
/**
|
||||
* This function is related to BEP38_ (mutable torrents). The
|
||||
* vector returned from this correspond to the "collections" keys
|
||||
* in the .torrent file. The collections from within the info-dict
|
||||
* and from outside of it are included.
|
||||
* <p>
|
||||
* BEP38: http://www.bittorrent.org/beps/bep_0038.html
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public ArrayList<String> collections() {
|
||||
string_vector v = ti.collections();
|
||||
int size = (int) v.size();
|
||||
|
||||
ArrayList<String> l = new ArrayList<>(size);
|
||||
for (int i = 0; i < size; i++) {
|
||||
l.add(v.get(i));
|
||||
}
|
||||
|
||||
return l;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear the internal list of trackers.
|
||||
*/
|
||||
public void clearTrackers() {
|
||||
ti.trackers().clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds one url to the list of url seeds. Currently, the only transport protocol
|
||||
* supported for the url is http.
|
||||
*
|
||||
* @param url
|
||||
* @see #addHttpSeed(String, String)
|
||||
*/
|
||||
public void addUrlSeed(String url) {
|
||||
ti.add_url_seed(url);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds one url to the list of url seeds. Currently, the only transport protocol
|
||||
* supported for the url is http.
|
||||
* <p>
|
||||
* The {@code externAuth} argument can be used for other authorization schemes than
|
||||
* basic HTTP authorization. If set, it will override any username and password
|
||||
* found in the URL itself. The string will be sent as the HTTP authorization header's
|
||||
* value (without specifying "Basic").
|
||||
* <p>
|
||||
* This is the same as calling {@link #addUrlSeed(String, String, List)} with an
|
||||
* empty list.
|
||||
*
|
||||
* @param url
|
||||
* @param externAuth
|
||||
*/
|
||||
public void addUrlSeed(String url, String externAuth) {
|
||||
ti.add_url_seed(url, externAuth);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds one url to the list of url seeds. Currently, the only transport protocol
|
||||
* supported for the url is http.
|
||||
* <p>
|
||||
* The {@code externAuth} argument can be used for other authorization schemes than
|
||||
* basic HTTP authorization. If set, it will override any username and password
|
||||
* found in the URL itself. The string will be sent as the HTTP authorization header's
|
||||
* value (without specifying "Basic").
|
||||
* <p>
|
||||
* The {@code extraHeaders} argument can be used to insert custom HTTP headers
|
||||
* in the requests to a specific web seed.
|
||||
*
|
||||
* @param url
|
||||
* @param externAuth
|
||||
* @param extraHeaders
|
||||
*/
|
||||
public void addUrlSeed(String url, String externAuth, List<Pair<String, String>> extraHeaders) {
|
||||
string_string_pair_vector v = new string_string_pair_vector();
|
||||
|
||||
for (Pair<String, String> p : extraHeaders) {
|
||||
v.push_back(p.to_string_string_pair());
|
||||
}
|
||||
|
||||
ti.add_url_seed(url, externAuth, v);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds one url to the list of http seeds. Currently, the only transport protocol supported for the url
|
||||
* is http.
|
||||
*
|
||||
* @param url
|
||||
*/
|
||||
public void addHttpSeed(String url) {
|
||||
ti.add_url_seed(url);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds one url to the list of http seeds. Currently, the only transport protocol supported for the url
|
||||
* is http.
|
||||
* <p>
|
||||
* The {@code externAuth} argument can be used for other authorization schemes than
|
||||
* basic HTTP authorization. If set, it will override any username and password
|
||||
* found in the URL itself. The string will be sent as the HTTP authorization header's
|
||||
* value (without specifying "Basic").
|
||||
*
|
||||
* @param url
|
||||
* @param externAuth
|
||||
*/
|
||||
public void addHttpSeed(String url, String externAuth) {
|
||||
ti.add_url_seed(url, externAuth);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds one url to the list of http seeds. Currently, the only transport protocol supported
|
||||
* for the url is http.
|
||||
* <p>
|
||||
* The {@code externAuth} argument can be used for other authorization schemes than
|
||||
* basic HTTP authorization. If set, it will override any username and password
|
||||
* found in the URL itself. The string will be sent as the HTTP authorization header's
|
||||
* value (without specifying "Basic").
|
||||
* <p>
|
||||
* The {@code extraHeaders} argument defaults to an empty list, but can be used to
|
||||
* insert custom HTTP headers in the requests to a specific web seed.
|
||||
*
|
||||
* @param url
|
||||
* @param externAuth
|
||||
* @param extraHeaders
|
||||
*/
|
||||
public void addHttpSeed(String url, String externAuth, List<Pair<String, String>> extraHeaders) {
|
||||
string_string_pair_vector v = new string_string_pair_vector();
|
||||
|
||||
for (Pair<String, String> p : extraHeaders) {
|
||||
v.push_back(p.to_string_string_pair());
|
||||
}
|
||||
|
||||
ti.add_url_seed(url, externAuth, v);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all url seeds and http seeds in the torrent. Each entry
|
||||
* is a {@link WebSeedEntry} and may refer to either a url seed or http seed.
|
||||
*
|
||||
* @return the list of web seeds
|
||||
*/
|
||||
public ArrayList<WebSeedEntry> webSeeds() {
|
||||
web_seed_entry_vector v = ti.web_seeds();
|
||||
int size = (int) v.size();
|
||||
|
||||
ArrayList<WebSeedEntry> l = new ArrayList<>(size);
|
||||
for (int i = 0; i < size; i++) {
|
||||
l.add(new WebSeedEntry(v.get(i)));
|
||||
}
|
||||
|
||||
return l;
|
||||
}
|
||||
|
||||
/**
|
||||
* Replaces all web seeds with the ones specified in the
|
||||
* {@code seeds} list.
|
||||
*
|
||||
* @param seeds the list of web seeds
|
||||
*/
|
||||
public void setWebSeeds(List<WebSeedEntry> seeds) {
|
||||
web_seed_entry_vector v = new web_seed_entry_vector();
|
||||
|
||||
for (WebSeedEntry e : seeds) {
|
||||
v.push_back(e.swig());
|
||||
}
|
||||
|
||||
ti.set_web_seeds(v);
|
||||
}
|
||||
|
||||
/**
|
||||
* The total number of bytes the torrent-file represents (all the files in it).
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public long totalSize() {
|
||||
return ti.total_size();
|
||||
}
|
||||
|
||||
/**
|
||||
* The number of byte for each piece.
|
||||
* <p>
|
||||
* The difference between {@link #pieceSize(int)} and {@link #pieceLength()} is that
|
||||
* {@link #pieceSize(int)} takes the piece index as argument and gives you the exact size
|
||||
* of that piece. It will always be the same as {@link #pieceLength()} except in the case
|
||||
* of the last piece, which may be smaller.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public int pieceLength() {
|
||||
return ti.piece_length();
|
||||
}
|
||||
|
||||
/**
|
||||
* The total number of pieces.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public int numPieces() {
|
||||
return ti.num_pieces();
|
||||
}
|
||||
|
||||
/**
|
||||
* returns the info-hash of the torrent.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public Sha1Hash infoHash() {
|
||||
return new Sha1Hash(ti.info_hash());
|
||||
}
|
||||
|
||||
/**
|
||||
* If you need index-access to files you can use this method
|
||||
* to access files using indices.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public int numFiles() {
|
||||
return ti.num_files();
|
||||
}
|
||||
|
||||
/**
|
||||
* This function will map a piece index, a byte offset within that piece and
|
||||
* a size (in bytes) into the corresponding files with offsets where that data
|
||||
* for that piece is supposed to be stored.
|
||||
*
|
||||
* @param piece
|
||||
* @param offset
|
||||
* @param size
|
||||
* @return
|
||||
* @see com.frostwire.jlibtorrent.FileSlice
|
||||
*/
|
||||
public ArrayList<FileSlice> mapBlock(int piece, long offset, int size) {
|
||||
return FileStorage.mapBlock(ti.map_block(piece, offset, size));
|
||||
}
|
||||
|
||||
/**
|
||||
* This function will map a range in a specific file into a range in the torrent.
|
||||
* The {@code offset} parameter is the offset in the file, given in bytes, where
|
||||
* 0 is the start of the file.
|
||||
* <p>
|
||||
* The input range is assumed to be valid within the torrent. {@code offset + size}
|
||||
* is not allowed to be greater than the file size. {@code index}
|
||||
* must refer to a valid file, i.e. it cannot be {@code >= numFiles()}.
|
||||
*
|
||||
* @param file
|
||||
* @param offset
|
||||
* @param size
|
||||
* @return
|
||||
* @see com.frostwire.jlibtorrent.PeerRequest
|
||||
*/
|
||||
public PeerRequest mapFile(int file, long offset, int size) {
|
||||
return new PeerRequest(ti.map_file(file, offset, size));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the SSL root certificate for the torrent, if it is an SSL
|
||||
* torrent. Otherwise returns an empty string. The certificate is
|
||||
* the the public certificate in x509 format.
|
||||
*
|
||||
* @return the cert as a byte array
|
||||
*/
|
||||
byte[] sslCert() {
|
||||
byte_vector v = ti.ssl_cert().to_bytes();
|
||||
return Vectors.byte_vector2bytes(v);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if this torrent_info object has a torrent loaded.
|
||||
* <p>
|
||||
* This is primarily used to determine if a magnet link has had its
|
||||
* metadata resolved yet or not.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public boolean isValid() {
|
||||
return ti.is_valid();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if this torrent is private. i.e., it should not be
|
||||
* distributed on the trackerless network (the kademlia DHT).
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public boolean isPrivate() {
|
||||
return ti.priv();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if this is an i2p torrent. This is determined by whether
|
||||
* or not it has a tracker whose URL domain name ends with ".i2p". i2p
|
||||
* torrents disable the DHT and local peer discovery as well as talking
|
||||
* to peers over anything other than the i2p network.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public boolean isI2p() {
|
||||
return ti.is_i2p();
|
||||
}
|
||||
|
||||
public int pieceSize(int index) {
|
||||
return ti.piece_size(index);
|
||||
}
|
||||
|
||||
/**
|
||||
* takes a piece-index and returns the 20-bytes sha1-hash for that
|
||||
* piece and ``info_hash()`` returns the 20-bytes sha1-hash for the info-section of the
|
||||
* torrent file.
|
||||
*
|
||||
* @param index
|
||||
* @return
|
||||
*/
|
||||
public Sha1Hash hashForPiece(int index) {
|
||||
return new Sha1Hash(ti.hash_for_piece(index));
|
||||
}
|
||||
|
||||
public boolean isLoaded() {
|
||||
return ti.is_loaded();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a copy to the merkle tree for this
|
||||
* torrent, if any.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public ArrayList<Sha1Hash> merkleTree() {
|
||||
return Sha1Hash.convert(ti.merkle_tree());
|
||||
}
|
||||
|
||||
/**
|
||||
* Copies the passed in merkle tree into the torrent info object.
|
||||
* <p>
|
||||
* You need to set the merkle tree for a torrent that you've just created
|
||||
* (as a merkle torrent). The merkle tree is retrieved from the
|
||||
* {@link #merkleTree()} function, and need to be saved
|
||||
* separately from the torrent file itself. Once it's added to
|
||||
* libtorrent, the merkle tree will be persisted in the resume data.
|
||||
*
|
||||
* @param tree
|
||||
*/
|
||||
public void merkleTree(List<Sha1Hash> tree) {
|
||||
sha1_hash_vector v = new sha1_hash_vector();
|
||||
|
||||
for (Sha1Hash h : tree) {
|
||||
v.push_back(h.swig());
|
||||
}
|
||||
|
||||
ti.set_merkle_tree(v);
|
||||
}
|
||||
|
||||
/**
|
||||
* returns the name of the torrent.
|
||||
* <p>
|
||||
* the name is an UTF-8 encoded strings.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public String name() {
|
||||
return ti.name();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the creation date of he torrent as time_t (`posix time`_).
|
||||
* If there's no time stamp in the torrent file,
|
||||
* a value of zero is returned.
|
||||
*
|
||||
* @return the time
|
||||
*/
|
||||
public long creationDate() {
|
||||
return ti.creation_date();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the creator string in the torrent. If there is no creator string
|
||||
* it will return an empty string.
|
||||
*
|
||||
* @return the creator
|
||||
*/
|
||||
public String creator() {
|
||||
return ti.creator();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the comment associated with the torrent. If there's no comment,
|
||||
* it will return an empty string.
|
||||
* <p>
|
||||
* The comment is an UTF-8 encoded strings.
|
||||
*
|
||||
* @return the comment
|
||||
*/
|
||||
public String comment() {
|
||||
return ti.comment();
|
||||
}
|
||||
|
||||
/**
|
||||
* If this torrent contains any DHT nodes, they are returned in
|
||||
* their original form (host name and port number).
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public ArrayList<Pair<String, Integer>> nodes() {
|
||||
string_int_pair_vector v = ti.nodes();
|
||||
int size = (int) v.size();
|
||||
|
||||
ArrayList<Pair<String, Integer>> l = new ArrayList<>(size);
|
||||
|
||||
for (int i = 0; i < size; i++) {
|
||||
string_int_pair p = v.get(i);
|
||||
l.add(new Pair<>(p.getFirst(), p.getSecond()));
|
||||
}
|
||||
|
||||
return l;
|
||||
}
|
||||
|
||||
/**
|
||||
* This is used when creating torrent. Use this to add a known DHT node.
|
||||
* It may be used, by the client, to bootstrap into the DHT network.
|
||||
*
|
||||
* @param host
|
||||
* @param port
|
||||
*/
|
||||
public void addNode(String host, int port) {
|
||||
ti.add_node(new string_int_pair(host, port));
|
||||
}
|
||||
|
||||
/**
|
||||
* This function looks up keys from the info-dictionary of the loaded
|
||||
* torrent file. It can be used to access extension values put in the
|
||||
* .torrent file. If the specified key cannot be found, it returns NULL.
|
||||
*
|
||||
* @param key
|
||||
* @return
|
||||
*/
|
||||
public bdecode_node info(String key) {
|
||||
return ti.info(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether or not this is a merkle torrent.
|
||||
* See BEP30: http://bittorrent.org/beps/bep_0030.html
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public boolean isMerkleTorrent() {
|
||||
return ti.is_merkle_torrent();
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a magnet URI from the specified torrent. If the torrent
|
||||
* is invalid, null is returned.
|
||||
* <p>
|
||||
* For more information about magnet links, see magnet-links_.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public String makeMagnetUri() {
|
||||
return ti.is_valid() ? libtorrent.make_magnet_uri(ti) : null;
|
||||
}
|
||||
|
||||
public Entry toEntry() {
|
||||
return new Entry(new create_torrent(ti).generate());
|
||||
}
|
||||
|
||||
public byte[] bencode() {
|
||||
return toEntry().bencode();
|
||||
}
|
||||
}
|
@ -0,0 +1,400 @@
|
||||
package com.frostwire.jlibtorrent;
|
||||
|
||||
import com.frostwire.jlibtorrent.swig.torrent_status;
|
||||
|
||||
/**
|
||||
* To be used in concert with {@link SessionManager}.
|
||||
* <p>
|
||||
* The call to {@code SessionManager#postTorrentUpdates()} is done approximately
|
||||
* every second. This class holds a time series per metric and a time series for
|
||||
* the sampling time.
|
||||
*
|
||||
* @author gubatron
|
||||
* @author aldenml
|
||||
* @author haperlot
|
||||
*/
|
||||
public final class TorrentStats {
|
||||
|
||||
private final Sha1Hash ih;
|
||||
|
||||
private final int maxSamples;
|
||||
|
||||
private final IntSeries time;
|
||||
private final IntSeries downloadRateSeries;
|
||||
private final IntSeries uploadRateSeries;
|
||||
|
||||
private long totalDownload;
|
||||
private long totalUpload;
|
||||
private long totalPayloadDownload;
|
||||
private long totalPayloadUpload;
|
||||
private long totalDone;
|
||||
private long totalWantedDone;
|
||||
private long totalWanted;
|
||||
private long allTimeUpload;
|
||||
private long allTimeDownload;
|
||||
private float progress;
|
||||
private int progressPpm;
|
||||
private int downloadRate;
|
||||
private int uploadRate;
|
||||
private int downloadPayloadRate;
|
||||
private int uploadPayloadRate;
|
||||
private int numSeeds;
|
||||
private int numPeers;
|
||||
private int listSeeds;
|
||||
private int listPeers;
|
||||
private int numPieces;
|
||||
private int numConnections;
|
||||
private TorrentStatus.State state;
|
||||
private boolean needSaveResume;
|
||||
private boolean isPaused;
|
||||
private boolean isSequentialDownload;
|
||||
private boolean isSeeding;
|
||||
private boolean isFinished;
|
||||
|
||||
public TorrentStats(Sha1Hash infoHash, int maxSamples) {
|
||||
this.ih = infoHash.clone();
|
||||
|
||||
this.maxSamples = maxSamples;
|
||||
|
||||
this.time = new IntSeries(maxSamples);
|
||||
this.downloadRateSeries = new IntSeries(maxSamples);
|
||||
this.uploadRateSeries = new IntSeries(maxSamples);
|
||||
}
|
||||
|
||||
public int maxSamples() {
|
||||
return maxSamples;
|
||||
}
|
||||
|
||||
public IntSeries series(SeriesMetric metric) {
|
||||
switch (metric) {
|
||||
case TIME:
|
||||
return time;
|
||||
case DOWNLOAD_RATE:
|
||||
return downloadRateSeries;
|
||||
case UPLOAD_RATE:
|
||||
return uploadRateSeries;
|
||||
default:
|
||||
throw new UnsupportedOperationException("metric type not supported");
|
||||
}
|
||||
}
|
||||
|
||||
public long last(SeriesMetric metric) {
|
||||
return series(metric).last();
|
||||
}
|
||||
|
||||
/**
|
||||
* The number of bytes downloaded and uploaded to all peers, accumulated, this session
|
||||
* only. The session is considered to restart when a torrent is paused and restarted
|
||||
* again. When a torrent is paused, these counters are reset to 0. If you want complete,
|
||||
* persistent, stats, see allTimeUpload and allTimeDownload.
|
||||
*/
|
||||
public long totalDownload() {
|
||||
return totalDownload;
|
||||
}
|
||||
|
||||
/**
|
||||
* The number of bytes downloaded and uploaded to all peers, accumulated, this session
|
||||
* only. The session is considered to restart when a torrent is paused and restarted
|
||||
* again. When a torrent is paused, these counters are reset to 0. If you want complete,
|
||||
* persistent, stats, see allTimeUpload and allTimeDownload.
|
||||
*/
|
||||
public long totalUpload() {
|
||||
return totalUpload;
|
||||
}
|
||||
|
||||
/**
|
||||
* Counts the amount of bytes received this session, but only
|
||||
* the actual payload data (i.e the interesting data), these counters
|
||||
* ignore any protocol overhead.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public long totalPayloadDownload() {
|
||||
return totalPayloadDownload;
|
||||
}
|
||||
|
||||
/**
|
||||
* Counts the amount of bytes send this session, but only
|
||||
* the actual payload data (i.e the interesting data), these counters
|
||||
* ignore any protocol overhead.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public long totalPayloadUpload() {
|
||||
return totalPayloadUpload;
|
||||
}
|
||||
|
||||
/**
|
||||
* The total number of bytes of the file(s) that we have. All this does not necessarily
|
||||
* has to be downloaded during this session (that's total_payload_download).
|
||||
*
|
||||
* @return the value
|
||||
*/
|
||||
public long totalDone() {
|
||||
return totalDone;
|
||||
}
|
||||
|
||||
/**
|
||||
* The number of bytes we have downloaded, only counting the pieces that we actually want
|
||||
* to download. i.e. excluding any pieces that we have but have priority 0 (i.e. not wanted).
|
||||
*/
|
||||
public long totalWantedDone() {
|
||||
return totalWantedDone;
|
||||
}
|
||||
|
||||
/**
|
||||
* The total number of bytes we want to download. This may be smaller than the total
|
||||
* torrent size in case any pieces are prioritized to 0, i.e. not wanted.
|
||||
*/
|
||||
public long totalWanted() {
|
||||
return totalWanted;
|
||||
}
|
||||
|
||||
/**
|
||||
* This is the accumulated upload payload byte counter. They are saved in and restored
|
||||
* from resume data to keep totals across sessions.
|
||||
*/
|
||||
public long allTimeUpload() {
|
||||
return allTimeUpload;
|
||||
}
|
||||
|
||||
/**
|
||||
* This is the accumulated download payload byte counters. They are saved in and restored
|
||||
* from resume data to keep totals across sessions.
|
||||
*/
|
||||
public long allTimeDownload() {
|
||||
return allTimeDownload;
|
||||
}
|
||||
|
||||
/**
|
||||
* A value in the range [0, 1], that represents the progress of the torrent's
|
||||
* current task. It may be checking files or downloading.
|
||||
*
|
||||
* @return the progress in [0, 1]
|
||||
*/
|
||||
public float progress() {
|
||||
return progress;
|
||||
}
|
||||
|
||||
/**
|
||||
* progress parts per million (progress * 1000000) when disabling
|
||||
* floating point operations, this is the only option to query progress
|
||||
* <p>
|
||||
* reflects the same value as ``progress``, but instead in a range [0,
|
||||
* 1000000] (ppm = parts per million). When floating point operations are
|
||||
* disabled, this is the only alternative to the floating point value in.
|
||||
*
|
||||
* @return the progress in parts per million (progress * 1000000)
|
||||
*/
|
||||
public int progressPpm() {
|
||||
return progressPpm;
|
||||
}
|
||||
|
||||
/**
|
||||
* The total rates for all peers for this torrent. These will usually have better
|
||||
* precision than summing the rates from all peers. The rates are given as the
|
||||
* number of bytes per second.
|
||||
*/
|
||||
public int downloadRate() {
|
||||
return downloadRate;
|
||||
}
|
||||
|
||||
/**
|
||||
* The total rates for all peers for this torrent. These will usually have better
|
||||
* precision than summing the rates from all peers. The rates are given as the
|
||||
* number of bytes per second.
|
||||
*/
|
||||
public int uploadRate() {
|
||||
return uploadRate;
|
||||
}
|
||||
|
||||
/**
|
||||
* The total transfer rate of payload only, not counting protocol chatter.
|
||||
* This might be slightly smaller than the other rates, but if projected over
|
||||
* a long time (e.g. when calculating ETA:s) the difference may be noticeable.
|
||||
*/
|
||||
public int downloadPayloadRate() {
|
||||
return downloadPayloadRate;
|
||||
}
|
||||
|
||||
/**
|
||||
* The total transfer rate of payload only, not counting protocol chatter.
|
||||
* This might be slightly smaller than the other rates, but if projected over
|
||||
* a long time (e.g. when calculating ETA:s) the difference may be noticeable.
|
||||
*/
|
||||
public int uploadPayloadRate() {
|
||||
return uploadPayloadRate;
|
||||
}
|
||||
|
||||
/**
|
||||
* The number of peers that are seeding that this client is currently connected to.
|
||||
*/
|
||||
public int numSeeds() {
|
||||
return numSeeds;
|
||||
}
|
||||
|
||||
/**
|
||||
* The number of peers this torrent currently is connected to. Peer connections that
|
||||
* are in the half-open state (is attempting to connect) or are queued for later
|
||||
* connection attempt do not count. Although they are visible in the peer list when
|
||||
* you call get_peer_info().
|
||||
*/
|
||||
public int numPeers() {
|
||||
return numPeers;
|
||||
}
|
||||
|
||||
/**
|
||||
* The number of seeds in our peer list and the total number of peers (including seeds).
|
||||
* We are not necessarily connected to all the peers in our peer list. This is the number
|
||||
* of peers we know of in total, including banned peers and peers that we have failed to
|
||||
* connect to.
|
||||
*/
|
||||
public int listSeeds() {
|
||||
return listSeeds;
|
||||
}
|
||||
|
||||
/**
|
||||
* The number of seeds in our peer list and the total number of peers (including seeds).
|
||||
* We are not necessarily connected to all the peers in our peer list. This is the number
|
||||
* of peers we know of in total, including banned peers and peers that we have failed to
|
||||
* connect to.
|
||||
*/
|
||||
public int listPeers() {
|
||||
return listPeers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of pieces that has been downloaded so you don't have
|
||||
* to count yourself. This can be used to see if anything has updated
|
||||
* since last time if you want to keep a graph of the pieces up to date.
|
||||
*
|
||||
* @return the number of pieces that has been downloaded
|
||||
*/
|
||||
public int numPieces() {
|
||||
return numPieces;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of peer connections this torrent has,
|
||||
* including half-open connections that hasn't completed the
|
||||
* bittorrent handshake yet.
|
||||
* <p>
|
||||
* This is always {@code >= num_peers}.
|
||||
*
|
||||
* @return the number of peer connections
|
||||
*/
|
||||
public int numConnections() {
|
||||
return numConnections;
|
||||
}
|
||||
|
||||
/**
|
||||
* The main state the torrent is in. See torrent_status::state_t.
|
||||
*
|
||||
* @return the state
|
||||
*/
|
||||
public TorrentStatus.State state() {
|
||||
return state;
|
||||
}
|
||||
|
||||
/**
|
||||
* true if this torrent has unsaved changes
|
||||
* to its download state and statistics since the last resume data
|
||||
* was saved.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public boolean needSaveResume() {
|
||||
return needSaveResume;
|
||||
}
|
||||
|
||||
/**
|
||||
* set to true if the torrent is paused and false otherwise. It's only
|
||||
* true if the torrent itself is paused. If the torrent is not running
|
||||
* because the session is paused, this is still false. To know if a
|
||||
* torrent is active or not, you need to inspect both
|
||||
* ``torrent_status::paused`` and ``session::is_paused()``.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public boolean isPaused() {
|
||||
return isPaused;
|
||||
}
|
||||
|
||||
/**
|
||||
* true when the torrent is in sequential download mode. In this mode
|
||||
* pieces are downloaded in order rather than rarest first.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public boolean isSequentialDownload() {
|
||||
return isSequentialDownload;
|
||||
}
|
||||
|
||||
/**
|
||||
* true if all pieces have been downloaded.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public boolean isSeeding() {
|
||||
return isSeeding;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@code true} if all pieces that have a
|
||||
* {@code priority > 0} are downloaded. There is
|
||||
* only a distinction between finished and seeding if some pieces or
|
||||
* files have been set to priority 0, i.e. are not downloaded.
|
||||
*
|
||||
* @return {@code true} if all pieces that have a {@code priority > 0} are downloaded.
|
||||
*/
|
||||
public boolean isFinished() {
|
||||
return isFinished;
|
||||
}
|
||||
|
||||
public void update(TorrentStatus status) {
|
||||
if (!ih.equals(status.infoHash())) {
|
||||
return; // not for us
|
||||
}
|
||||
|
||||
time.add(System.currentTimeMillis());
|
||||
|
||||
torrent_status st = status.swig();
|
||||
|
||||
downloadRateSeries.add(st.getDownload_rate());
|
||||
uploadRateSeries.add(st.getUpload_rate());
|
||||
|
||||
totalDownload = st.getTotal_download();
|
||||
totalUpload = st.getTotal_upload();
|
||||
totalPayloadDownload = st.getTotal_payload_download();
|
||||
totalPayloadUpload = st.getTotal_payload_upload();
|
||||
totalDone = st.getTotal_done();
|
||||
totalWantedDone = st.getTotal_wanted_done();
|
||||
totalWanted = st.getTotal_wanted();
|
||||
allTimeUpload = st.getAll_time_upload();
|
||||
allTimeDownload = st.getAll_time_download();
|
||||
progress = st.getProgress();
|
||||
progressPpm = st.getProgress_ppm();
|
||||
downloadRate = st.getDownload_rate();
|
||||
uploadRate = st.getUpload_rate();
|
||||
downloadPayloadRate = st.getDownload_payload_rate();
|
||||
uploadPayloadRate = st.getUpload_payload_rate();
|
||||
numSeeds = st.getNum_seeds();
|
||||
numPeers = st.getNum_peers();
|
||||
listSeeds = st.getList_seeds();
|
||||
listPeers = st.getList_peers();
|
||||
numPieces = st.getNum_pieces();
|
||||
numConnections = st.getNum_connections();
|
||||
state = status.state();
|
||||
needSaveResume = st.getNeed_save_resume();
|
||||
isPaused = st.getFlags().and_(TorrentFlags.PAUSED).nonZero();
|
||||
isSequentialDownload = st.getFlags().and_(TorrentFlags.SEQUENTIAL_DOWNLOAD).nonZero();
|
||||
isSeeding = st.getIs_seeding();
|
||||
isFinished = st.getIs_finished();
|
||||
}
|
||||
|
||||
public enum SeriesMetric {
|
||||
TIME,
|
||||
DOWNLOAD_RATE,
|
||||
UPLOAD_RATE
|
||||
}
|
||||
}
|
@ -0,0 +1,780 @@
|
||||
package com.frostwire.jlibtorrent;
|
||||
|
||||
import com.frostwire.jlibtorrent.swig.torrent_flags_t;
|
||||
import com.frostwire.jlibtorrent.swig.torrent_status;
|
||||
|
||||
/**
|
||||
* Holds a snapshot of the status of a torrent, as queried by
|
||||
* {@link TorrentHandle#status()}
|
||||
*
|
||||
* @author gubatron
|
||||
* @author aldenml
|
||||
*/
|
||||
public final class TorrentStatus implements Cloneable {
|
||||
|
||||
private final torrent_status ts;
|
||||
|
||||
/**
|
||||
* Internal, don't use it in your code.
|
||||
*
|
||||
* @param ts
|
||||
*/
|
||||
// this is public to make it available to StateUpdateAlert
|
||||
public TorrentStatus(torrent_status ts) {
|
||||
this.ts = ts;
|
||||
}
|
||||
|
||||
private static long time2millis(long time) {
|
||||
return time * 1000;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the native object
|
||||
*/
|
||||
public torrent_status swig() {
|
||||
return ts;
|
||||
}
|
||||
|
||||
/**
|
||||
* May be set to an error message describing why the torrent
|
||||
* was paused, in case it was paused by an error. If the torrent
|
||||
* is not paused or if it's paused but not because of an error,
|
||||
* this string is empty.
|
||||
*
|
||||
* @return the error code
|
||||
*/
|
||||
public ErrorCode errorCode() {
|
||||
return new ErrorCode(ts.getErrc());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns 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. See ``session::add_torrent``.
|
||||
* This field is only included if the torrent status is queried
|
||||
* with ``torrent_handle::query_name``.
|
||||
*
|
||||
* @return the name
|
||||
*/
|
||||
public String name() {
|
||||
return ts.getName();
|
||||
}
|
||||
|
||||
/**
|
||||
* The time until the torrent will announce itself to the tracker (in milliseconds).
|
||||
*
|
||||
* @return the next announce time
|
||||
*/
|
||||
public long nextAnnounce() {
|
||||
return ts.get_next_announce();
|
||||
}
|
||||
|
||||
/**
|
||||
* the URL of the last working tracker. If no tracker request has
|
||||
* been successful yet, it's set to an empty string.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public String currentTracker() {
|
||||
return ts.getCurrent_tracker();
|
||||
}
|
||||
|
||||
/**
|
||||
* The number of bytes downloaded and uploaded to all peers, accumulated, this session
|
||||
* only. The session is considered to restart when a torrent is paused and restarted
|
||||
* again. When a torrent is paused, these counters are reset to 0. If you want complete,
|
||||
* persistent, stats, see allTimeUpload and allTimeDownload.
|
||||
*/
|
||||
public long totalDownload() {
|
||||
return ts.getTotal_download();
|
||||
}
|
||||
|
||||
/**
|
||||
* The number of bytes downloaded and uploaded to all peers, accumulated, this session
|
||||
* only. The session is considered to restart when a torrent is paused and restarted
|
||||
* again. When a torrent is paused, these counters are reset to 0. If you want complete,
|
||||
* persistent, stats, see allTimeUpload and allTimeDownload.
|
||||
*/
|
||||
public long totalUpload() {
|
||||
return ts.getTotal_upload();
|
||||
}
|
||||
|
||||
/**
|
||||
* Counts the amount of bytes received this session, but only
|
||||
* the actual payload data (i.e the interesting data), these counters
|
||||
* ignore any protocol overhead.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public long totalPayloadDownload() {
|
||||
return ts.getTotal_payload_download();
|
||||
}
|
||||
|
||||
/**
|
||||
* Counts the amount of bytes send this session, but only
|
||||
* the actual payload data (i.e the interesting data), these counters
|
||||
* ignore any protocol overhead.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public long totalPayloadUpload() {
|
||||
return ts.getTotal_payload_upload();
|
||||
}
|
||||
|
||||
/**
|
||||
* The number of bytes that has been downloaded and that has failed the
|
||||
* piece hash test. In other words, this is just how much crap that has
|
||||
* been downloaded.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public long totalFailedBytes() {
|
||||
return ts.getTotal_failed_bytes();
|
||||
}
|
||||
|
||||
/**
|
||||
* The number of bytes that has been downloaded even though that data
|
||||
* already was downloaded. The reason for this is that in some situations
|
||||
* the same data can be downloaded by mistake. When libtorrent sends
|
||||
* requests to a peer, and the peer doesn't send a response within a
|
||||
* certain timeout, libtorrent will re-request that block. Another
|
||||
* situation when libtorrent may re-request blocks is when the requests
|
||||
* it sends out are not replied in FIFO-order (it will re-request blocks
|
||||
* that are skipped by an out of order block). This is supposed to be as
|
||||
* low as possible.
|
||||
*
|
||||
* @return the value
|
||||
*/
|
||||
public long totalRedundantBytes() {
|
||||
return ts.getTotal_redundant_bytes();
|
||||
}
|
||||
|
||||
/**
|
||||
* IMPORTANT: If you are not getting up to date information about pieces
|
||||
* remember that PieceIndexBitfield data is considered augmented data
|
||||
* for a torrentHandle.status() call, meaning, if you want to get the latest
|
||||
* piece data, you must use the TorrentHandle.QUERY_PIECES flag when invoking
|
||||
* torrentHandle.status(TorrentHandle.QUERY_PIECES). Keep in mind this is
|
||||
* an expensive call, therefore not part of the default flags.
|
||||
* <p>
|
||||
* A bitmask that represents which pieces we have (set to true) and the
|
||||
* pieces we don't have. It's a pointer and may be set to 0 if the
|
||||
* torrent isn't downloading or seeding.
|
||||
*
|
||||
* @return the bitfield of pieces
|
||||
*/
|
||||
public PieceIndexBitfield pieces() {
|
||||
return new PieceIndexBitfield(ts.getPieces(), ts);
|
||||
}
|
||||
|
||||
/**
|
||||
* A bitmask representing which pieces has had their hash checked. This
|
||||
* only applies to torrents in *seed mode*. If the torrent is not in seed
|
||||
* mode, this bitmask may be empty.
|
||||
*
|
||||
* @return the bitfield of verified pieces
|
||||
*/
|
||||
public PieceIndexBitfield verifiedPieces() {
|
||||
return new PieceIndexBitfield(ts.getVerified_pieces(), ts);
|
||||
}
|
||||
|
||||
/**
|
||||
* The total number of bytes of the file(s) that we have. All this does not necessarily
|
||||
* has to be downloaded during this session (that's total_payload_download).
|
||||
*
|
||||
* @return the value
|
||||
*/
|
||||
public long totalDone() {
|
||||
return ts.getTotal_done();
|
||||
}
|
||||
|
||||
/**
|
||||
* The total number of bytes to download for this torrent. This
|
||||
* may be less than the size of the torrent in case there are
|
||||
* pad files. This number only counts bytes that will actually
|
||||
* be requested from peers.
|
||||
*/
|
||||
public long total() {
|
||||
return ts.getTotal();
|
||||
}
|
||||
|
||||
/**
|
||||
* The number of bytes we have downloaded, only counting the pieces that we actually want
|
||||
* to download. i.e. excluding any pieces that we have but have priority 0 (i.e. not wanted).
|
||||
*/
|
||||
public long totalWantedDone() {
|
||||
return ts.getTotal_wanted_done();
|
||||
}
|
||||
|
||||
/**
|
||||
* The total number of bytes we want to download. This may be smaller than the total
|
||||
* torrent size in case any pieces are prioritized to 0, i.e. not wanted.
|
||||
*/
|
||||
public long totalWanted() {
|
||||
return ts.getTotal_wanted();
|
||||
}
|
||||
|
||||
/**
|
||||
* This is the accumulated upload payload byte counter. They are saved in and restored
|
||||
* from resume data to keep totals across sessions.
|
||||
*/
|
||||
public long allTimeUpload() {
|
||||
return ts.getAll_time_upload();
|
||||
}
|
||||
|
||||
/**
|
||||
* This is the accumulated download payload byte counters. They are saved in and restored
|
||||
* from resume data to keep totals across sessions.
|
||||
*/
|
||||
public long allTimeDownload() {
|
||||
return ts.getAll_time_download();
|
||||
}
|
||||
|
||||
/**
|
||||
* The posix-time (in milliseconds) when this torrent was added. i.e. what time(NULL) returned at the time.
|
||||
*/
|
||||
public long addedTime() {
|
||||
return time2millis(ts.getAdded_time());
|
||||
}
|
||||
|
||||
/**
|
||||
* The posix-time (in milliseconds) when this torrent was finished. If the torrent is not yet finished, this is 0.
|
||||
*/
|
||||
public long completedTime() {
|
||||
return time2millis(ts.getCompleted_time());
|
||||
}
|
||||
|
||||
/**
|
||||
* The time (in milliseconds) when we, or one of our peers, last saw a complete copy of this torrent.
|
||||
*/
|
||||
public long lastSeenComplete() {
|
||||
return time2millis(ts.getLast_seen_complete());
|
||||
}
|
||||
|
||||
/**
|
||||
* The allocation mode for the torrent.
|
||||
*
|
||||
* @see StorageMode
|
||||
*/
|
||||
public final StorageMode storageMode() {
|
||||
return StorageMode.fromSwig(ts.getStorage_mode().swigValue());
|
||||
}
|
||||
|
||||
/**
|
||||
* A value in the range [0, 1], that represents the progress of the torrent's
|
||||
* current task. It may be checking files or downloading.
|
||||
*
|
||||
* @return the progress in [0, 1]
|
||||
*/
|
||||
public float progress() {
|
||||
return ts.getProgress();
|
||||
}
|
||||
|
||||
/**
|
||||
* progress parts per million (progress * 1000000) when disabling
|
||||
* floating point operations, this is the only option to query progress
|
||||
* <p>
|
||||
* reflects the same value as ``progress``, but instead in a range [0,
|
||||
* 1000000] (ppm = parts per million). When floating point operations are
|
||||
* disabled, this is the only alternative to the floating point value in.
|
||||
*
|
||||
* @return the progress in parts per million (progress * 1000000)
|
||||
*/
|
||||
public int progressPpm() {
|
||||
return ts.getProgress_ppm();
|
||||
}
|
||||
|
||||
/**
|
||||
* the position this torrent has in the download
|
||||
* queue. If the torrent is a seed or finished, this is -1.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public int queuePosition() {
|
||||
return ts.get_queue_position();
|
||||
}
|
||||
|
||||
/**
|
||||
* The total rates for all peers for this torrent. These will usually have better
|
||||
* precision than summing the rates from all peers. The rates are given as the
|
||||
* number of bytes per second.
|
||||
*/
|
||||
public int downloadRate() {
|
||||
return ts.getDownload_rate();
|
||||
}
|
||||
|
||||
/**
|
||||
* The total rates for all peers for this torrent. These will usually have better
|
||||
* precision than summing the rates from all peers. The rates are given as the
|
||||
* number of bytes per second.
|
||||
*/
|
||||
public int uploadRate() {
|
||||
return ts.getUpload_rate();
|
||||
}
|
||||
|
||||
/**
|
||||
* The total transfer rate of payload only, not counting protocol chatter.
|
||||
* This might be slightly smaller than the other rates, but if projected over
|
||||
* a long time (e.g. when calculating ETA:s) the difference may be noticeable.
|
||||
*/
|
||||
public int downloadPayloadRate() {
|
||||
return ts.getDownload_payload_rate();
|
||||
}
|
||||
|
||||
/**
|
||||
* The total transfer rate of payload only, not counting protocol chatter.
|
||||
* This might be slightly smaller than the other rates, but if projected over
|
||||
* a long time (e.g. when calculating ETA:s) the difference may be noticeable.
|
||||
*/
|
||||
public int uploadPayloadRate() {
|
||||
return ts.getUpload_payload_rate();
|
||||
}
|
||||
|
||||
/**
|
||||
* The number of peers that are seeding that this client is currently connected to.
|
||||
*/
|
||||
public int numSeeds() {
|
||||
return ts.getNum_seeds();
|
||||
}
|
||||
|
||||
/**
|
||||
* The number of peers this torrent currently is connected to. Peer connections that
|
||||
* are in the half-open state (is attempting to connect) or are queued for later
|
||||
* connection attempt do not count. Although they are visible in the peer list when
|
||||
* you call get_peer_info().
|
||||
*/
|
||||
public int numPeers() {
|
||||
return ts.getNum_peers();
|
||||
}
|
||||
|
||||
/**
|
||||
* If the tracker sends scrape info in its announce reply, these fields
|
||||
* will be set to the total number of peers that have the whole file and
|
||||
* the total number of peers that are still downloading. set to -1 if the
|
||||
* tracker did not send any scrape data in its announce reply.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public int numComplete() {
|
||||
return ts.getNum_complete();
|
||||
}
|
||||
|
||||
/**
|
||||
* If the tracker sends scrape info in its announce reply, these fields
|
||||
* will be set to the total number of peers that have the whole file and
|
||||
* the total number of peers that are still downloading. set to -1 if the
|
||||
* tracker did not send any scrape data in its announce reply.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public int numIncomplete() {
|
||||
return ts.getNum_incomplete();
|
||||
}
|
||||
|
||||
/**
|
||||
* The number of seeds in our peer list and the total number of peers (including seeds).
|
||||
* We are not necessarily connected to all the peers in our peer list. This is the number
|
||||
* of peers we know of in total, including banned peers and peers that we have failed to
|
||||
* connect to.
|
||||
*/
|
||||
public int listSeeds() {
|
||||
return ts.getList_seeds();
|
||||
}
|
||||
|
||||
/**
|
||||
* The number of seeds in our peer list and the total number of peers (including seeds).
|
||||
* We are not necessarily connected to all the peers in our peer list. This is the number
|
||||
* of peers we know of in total, including banned peers and peers that we have failed to
|
||||
* connect to.
|
||||
*/
|
||||
public int listPeers() {
|
||||
return ts.getList_peers();
|
||||
}
|
||||
|
||||
/**
|
||||
* the number of peers in this torrent's peer list that is a candidate to
|
||||
* be connected to. i.e. It has fewer connect attempts than the max fail
|
||||
* count, it is not a seed if we are a seed, it is not banned etc. If
|
||||
* this is 0, it means we don't know of any more peers that we can try.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public int connectCandidates() {
|
||||
return ts.getConnect_candidates();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of pieces that has been downloaded so you don't have
|
||||
* to count yourself. This can be used to see if anything has updated
|
||||
* since last time if you want to keep a graph of the pieces up to date.
|
||||
*
|
||||
* @return the number of pieces that has been downloaded
|
||||
*/
|
||||
public int numPieces() {
|
||||
return ts.getNum_pieces();
|
||||
}
|
||||
|
||||
/**
|
||||
* the number of distributed copies of the torrent. Note that one copy
|
||||
* may be spread out among many peers. It tells how many copies there are
|
||||
* currently of the rarest piece(s) among the peers this client is
|
||||
* connected to.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public int distributedFullCopies() {
|
||||
return ts.getDistributed_full_copies();
|
||||
}
|
||||
|
||||
/**
|
||||
* tells the share of pieces that have more copies than the rarest
|
||||
* // piece(s). Divide this number by 1000 to get the fraction.
|
||||
* //
|
||||
* // For example, if ``distributed_full_copies`` is 2 and
|
||||
* // ``distributed_fraction`` is 500, it means that the rarest pieces have
|
||||
* // only 2 copies among the peers this torrent is connected to, and that
|
||||
* // 50% of all the pieces have more than two copies.
|
||||
* //
|
||||
* // If we are a seed, the piece picker is deallocated as an optimization,
|
||||
* // and piece availability is no longer tracked. In this case the
|
||||
* // distributed copies members are set to -1.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public int distributedFraction() {
|
||||
return ts.getDistributed_fraction();
|
||||
}
|
||||
|
||||
/**
|
||||
* the number of distributed copies of the file. note that one copy may
|
||||
* be spread out among many peers. This is a floating point
|
||||
* representation of the distributed copies.
|
||||
* <p>
|
||||
* the integer part tells how many copies
|
||||
* there are of the rarest piece(s)
|
||||
* <p>
|
||||
* the fractional part tells the fraction of pieces that
|
||||
* have more copies than the rarest piece(s).
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public float distributedCopies() {
|
||||
return ts.getDistributed_copies();
|
||||
}
|
||||
|
||||
/**
|
||||
* the size of a block, in bytes. A block is a sub piece, it is the
|
||||
* number of bytes that each piece request asks for and the number of
|
||||
* bytes that each bit in the ``partial_piece_info``'s bitset represents,
|
||||
* see get_download_queue(). This is typically 16 kB, but it may be
|
||||
* larger if the pieces are larger.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public int blockSize() {
|
||||
return ts.getBlock_size();
|
||||
}
|
||||
|
||||
/**
|
||||
* the number of unchoked peers in this torrent.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public int numUploads() {
|
||||
return ts.getNum_uploads();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of peer connections this torrent has,
|
||||
* including half-open connections that hasn't completed the
|
||||
* bittorrent handshake yet.
|
||||
* <p>
|
||||
* This is always {@code >= num_peers}.
|
||||
*
|
||||
* @return the number of peer connections
|
||||
*/
|
||||
public int numConnections() {
|
||||
return ts.getNum_connections();
|
||||
}
|
||||
|
||||
/**
|
||||
* get limit of upload slots (unchoked peers) for this torrent.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public int uploadsLimit() {
|
||||
return ts.getUploads_limit();
|
||||
}
|
||||
|
||||
/**
|
||||
* get limit of number of connections for this torrent.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public int connectionsLimit() {
|
||||
return ts.getConnections_limit();
|
||||
}
|
||||
|
||||
/**
|
||||
* the number of peers in this torrent that are waiting for more bandwidth quota from the torrent rate limiter.
|
||||
* This can determine if the rate you get from this torrent is bound by the torrents limit or not.
|
||||
* If there is no limit set on this torrent, the peers might still be waiting for bandwidth quota from the global limiter,
|
||||
* but then they are counted in the ``session_status`` object.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public int upBandwidthQueue() {
|
||||
return ts.getUp_bandwidth_queue();
|
||||
}
|
||||
|
||||
/**
|
||||
* the number of peers in this torrent that are waiting for more bandwidth quota from the torrent rate limiter.
|
||||
* This can determine if the rate you get from this torrent is bound by the torrents limit or not.
|
||||
* If there is no limit set on this torrent, the peers might still be waiting for bandwidth quota from the global limiter,
|
||||
* but then they are counted in the ``session_status`` object.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public int downBandwidthQueue() {
|
||||
return ts.getDown_bandwidth_queue();
|
||||
}
|
||||
|
||||
/**
|
||||
* A rank of how important it is to seed the torrent, it is used to determine which torrents to seed and which to queue.
|
||||
* It is based on the peer to seed ratio from the tracker scrape. Higher value means more important to seed.
|
||||
*
|
||||
* @return the seed rank
|
||||
*/
|
||||
public int seedRank() {
|
||||
return ts.getSeed_rank();
|
||||
}
|
||||
|
||||
/**
|
||||
* The main state the torrent is in. See torrent_status::state_t.
|
||||
*
|
||||
* @return the state
|
||||
*/
|
||||
public State state() {
|
||||
return State.fromSwig(ts.getState().swigValue());
|
||||
}
|
||||
|
||||
/**
|
||||
* true if this torrent has unsaved changes
|
||||
* to its download state and statistics since the last resume data
|
||||
* was saved.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public boolean needSaveResume() {
|
||||
return ts.getNeed_save_resume();
|
||||
}
|
||||
|
||||
/**
|
||||
* true if all pieces have been downloaded.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public boolean isSeeding() {
|
||||
return ts.getIs_seeding();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@code true} if all pieces that have a
|
||||
* {@code priority > 0} are downloaded. There is
|
||||
* only a distinction between finished and seeding if some pieces or
|
||||
* files have been set to priority 0, i.e. are not downloaded.
|
||||
*
|
||||
* @return {@code true} if all pieces that have a {@code priority > 0} are downloaded.
|
||||
*/
|
||||
public boolean isFinished() {
|
||||
return ts.getIs_finished();
|
||||
}
|
||||
|
||||
/**
|
||||
* true if this torrent has metadata (either it was started from a
|
||||
* .torrent file or the metadata has been downloaded). The only scenario
|
||||
* where this can be false is when the torrent was started torrent-less
|
||||
* (i.e. with just an info-hash and tracker ip, a magnet link for
|
||||
* instance).
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public boolean hasMetadata() {
|
||||
return ts.getHas_metadata();
|
||||
}
|
||||
|
||||
/**
|
||||
* true if there has ever been an incoming connection attempt to this
|
||||
* torrent.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public boolean hasIncoming() {
|
||||
return ts.getHas_incoming();
|
||||
}
|
||||
|
||||
/**
|
||||
* this is true if this torrent's storage is currently being moved from
|
||||
* one location to another. This may potentially be a long operation
|
||||
* if a large file ends up being copied from one drive to another.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public boolean isMovingStorage() {
|
||||
return ts.getMoving_storage();
|
||||
}
|
||||
|
||||
/**
|
||||
* These are set to true if this torrent is allowed to announce to the
|
||||
* respective peer source. Whether they are true or false is determined by
|
||||
* the queue logic/auto manager. Torrents that are not auto managed will
|
||||
* always be allowed to announce to all peer sources.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public boolean announcingToTrackers() {
|
||||
return ts.getAnnouncing_to_trackers();
|
||||
}
|
||||
|
||||
/**
|
||||
* These are set to true if this torrent is allowed to announce to the
|
||||
* respective peer source. Whether they are true or false is determined by
|
||||
* the queue logic/auto manager. Torrents that are not auto managed will
|
||||
* always be allowed to announce to all peer sources.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public boolean announcingToLsd() {
|
||||
return ts.getAnnouncing_to_lsd();
|
||||
}
|
||||
|
||||
/**
|
||||
* These are set to true if this torrent is allowed to announce to the
|
||||
* respective peer source. Whether they are true or false is determined by
|
||||
* the queue logic/auto manager. Torrents that are not auto managed will
|
||||
* always be allowed to announce to all peer sources.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public boolean announcingToDht() {
|
||||
return ts.getAnnouncing_to_dht();
|
||||
}
|
||||
|
||||
/**
|
||||
* the info-hash for this torrent.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public Sha1Hash infoHash() {
|
||||
return new Sha1Hash(ts.getInfo_hash());
|
||||
}
|
||||
|
||||
public long lastUpload() {
|
||||
return ts.get_last_upload();
|
||||
}
|
||||
|
||||
public long lastDownload() {
|
||||
return ts.get_last_download();
|
||||
}
|
||||
|
||||
public long activeDuration() {
|
||||
return ts.get_active_duration();
|
||||
}
|
||||
|
||||
public long finishedDuration() {
|
||||
return ts.get_finished_duration();
|
||||
}
|
||||
|
||||
public long seedingDuration() {
|
||||
return ts.get_seeding_duration();
|
||||
}
|
||||
|
||||
public torrent_flags_t flags() {
|
||||
return ts.getFlags();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected TorrentStatus clone() {
|
||||
return new TorrentStatus(new torrent_status(ts));
|
||||
}
|
||||
|
||||
/**
|
||||
* the different overall states a torrent can be in.
|
||||
*/
|
||||
public enum State {
|
||||
|
||||
/**
|
||||
* The torrent has not started its download yet, and is
|
||||
* currently checking existing files.
|
||||
*/
|
||||
CHECKING_FILES(torrent_status.state_t.checking_files.swigValue()),
|
||||
|
||||
/**
|
||||
* The torrent is trying to download metadata from peers.
|
||||
* This assumes the metadata_transfer extension is in use.
|
||||
*/
|
||||
DOWNLOADING_METADATA(torrent_status.state_t.downloading_metadata.swigValue()),
|
||||
|
||||
/**
|
||||
* The torrent is being downloaded. This is the state
|
||||
* most torrents will be in most of the time. The progress
|
||||
* meter will tell how much of the files that has been
|
||||
* downloaded.
|
||||
*/
|
||||
DOWNLOADING(torrent_status.state_t.downloading.swigValue()),
|
||||
|
||||
/**
|
||||
* In this state the torrent has finished downloading but
|
||||
* still doesn't have the entire torrent. i.e. some pieces
|
||||
* are filtered and won't get downloaded.
|
||||
*/
|
||||
FINISHED(torrent_status.state_t.finished.swigValue()),
|
||||
|
||||
/**
|
||||
* In this state the torrent has finished downloading and
|
||||
* is a pure seeder.
|
||||
*/
|
||||
SEEDING(torrent_status.state_t.seeding.swigValue()),
|
||||
|
||||
/**
|
||||
* The torrent is currently checking the fastresume data and
|
||||
* comparing it to the files on disk. This is typically
|
||||
* completed in a fraction of a second, but if you add a
|
||||
* large number of torrents at once, they will queue up.
|
||||
*/
|
||||
CHECKING_RESUME_DATA(torrent_status.state_t.checking_resume_data.swigValue()),
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
UNKNOWN(-1);
|
||||
|
||||
private final int swigValue;
|
||||
|
||||
State(int swigValue) {
|
||||
this.swigValue = swigValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param swigValue
|
||||
* @return
|
||||
*/
|
||||
public static State fromSwig(int swigValue) {
|
||||
State[] enumValues = State.class.getEnumConstants();
|
||||
for (State ev : enumValues) {
|
||||
if (ev.swig() == swigValue) {
|
||||
return ev;
|
||||
}
|
||||
}
|
||||
return UNKNOWN;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the native value
|
||||
*/
|
||||
public int swig() {
|
||||
return swigValue;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,63 @@
|
||||
package com.frostwire.jlibtorrent;
|
||||
|
||||
import com.frostwire.jlibtorrent.swig.address;
|
||||
import com.frostwire.jlibtorrent.swig.error_code;
|
||||
import com.frostwire.jlibtorrent.swig.udp_endpoint;
|
||||
|
||||
/**
|
||||
* @author gubatron
|
||||
* @author aldenml
|
||||
*/
|
||||
public final class UdpEndpoint implements Cloneable {
|
||||
|
||||
private final udp_endpoint endp;
|
||||
|
||||
public UdpEndpoint(udp_endpoint endp) {
|
||||
this.endp = endp;
|
||||
}
|
||||
|
||||
public UdpEndpoint() {
|
||||
this(new udp_endpoint());
|
||||
}
|
||||
|
||||
public UdpEndpoint(Address address, int port) {
|
||||
this(new udp_endpoint(address.swig(), port));
|
||||
}
|
||||
|
||||
public UdpEndpoint(String ip, int port) {
|
||||
error_code ec = new error_code();
|
||||
address addr = address.from_string(ip, ec);
|
||||
if (ec.value() != 0) {
|
||||
throw new IllegalArgumentException(ec.message());
|
||||
}
|
||||
this.endp = new udp_endpoint(addr, port);
|
||||
}
|
||||
|
||||
public udp_endpoint swig() {
|
||||
return endp;
|
||||
}
|
||||
|
||||
public Address address() {
|
||||
return new Address(endp.address());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the port associated with the endpoint. The port number is always in
|
||||
* the host's byte order.
|
||||
*
|
||||
* @return the port
|
||||
*/
|
||||
public int port() {
|
||||
return endp.port();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "udp:" + Address.toString(endp.address()) + ":" + endp.port();
|
||||
}
|
||||
|
||||
@Override
|
||||
public UdpEndpoint clone() {
|
||||
return new UdpEndpoint(new udp_endpoint(endp));
|
||||
}
|
||||
}
|
@ -0,0 +1,150 @@
|
||||
package com.frostwire.jlibtorrent;
|
||||
|
||||
import com.frostwire.jlibtorrent.swig.byte_const_span;
|
||||
import com.frostwire.jlibtorrent.swig.byte_vector;
|
||||
import com.frostwire.jlibtorrent.swig.int64_vector;
|
||||
import com.frostwire.jlibtorrent.swig.int_vector;
|
||||
import com.frostwire.jlibtorrent.swig.string_vector;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author gubatron
|
||||
* @author aldenml
|
||||
*/
|
||||
public final class Vectors {
|
||||
|
||||
private Vectors() {
|
||||
}
|
||||
|
||||
public static byte[] byte_vector2bytes(byte_vector v) {
|
||||
int size = (int) v.size();
|
||||
byte[] arr = new byte[size];
|
||||
|
||||
for (int i = 0; i < size; i++) {
|
||||
arr[i] = v.get(i);
|
||||
}
|
||||
|
||||
return arr;
|
||||
}
|
||||
|
||||
public static void byte_vector2bytes(byte_vector v, byte[] arr) {
|
||||
int size = (int) v.size();
|
||||
|
||||
for (int i = 0; i < size; i++) {
|
||||
arr[i] = v.get(i);
|
||||
}
|
||||
}
|
||||
|
||||
public static byte_vector bytes2byte_vector(byte[] arr) {
|
||||
byte_vector v = new byte_vector();
|
||||
|
||||
for (int i = 0; i < arr.length; i++) {
|
||||
v.push_back(arr[i]);
|
||||
}
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
public static void bytes2byte_vector(byte[] arr, byte_vector v) {
|
||||
for (int i = 0; i < arr.length; i++) {
|
||||
v.set(i, arr[i]);
|
||||
}
|
||||
}
|
||||
|
||||
public static int[] int_vector2ints(int_vector v) {
|
||||
int size = (int) v.size();
|
||||
int[] arr = new int[size];
|
||||
|
||||
for (int i = 0; i < size; i++) {
|
||||
arr[i] = v.get(i);
|
||||
}
|
||||
|
||||
return arr;
|
||||
}
|
||||
|
||||
public static long[] int64_vector2longs(int64_vector v) {
|
||||
int size = (int) v.size();
|
||||
long[] arr = new long[size];
|
||||
|
||||
for (int i = 0; i < size; i++) {
|
||||
arr[i] = v.get(i);
|
||||
}
|
||||
|
||||
return arr;
|
||||
}
|
||||
|
||||
public static byte[] byte_span2bytes(byte_const_span v) {
|
||||
int size = (int) v.size();
|
||||
byte[] arr = new byte[size];
|
||||
|
||||
for (int i = 0; i < size; i++) {
|
||||
arr[i] = v.get(i);
|
||||
}
|
||||
|
||||
return arr;
|
||||
}
|
||||
|
||||
public static byte_vector new_byte_vector(int size) {
|
||||
byte_vector v = new byte_vector();
|
||||
byte z = (byte) 0;
|
||||
for (int i = 0; i < size; i++) {
|
||||
v.push_back(z);
|
||||
}
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
public static List<String> string_vector2list(string_vector v) {
|
||||
int size = (int) v.size();
|
||||
ArrayList<String> l = new ArrayList<>(size);
|
||||
|
||||
for (int i = 0; i < size; i++) {
|
||||
l.add(v.get(i));
|
||||
}
|
||||
|
||||
return l;
|
||||
}
|
||||
|
||||
public static String byte_vector2string(byte_vector v, String encoding) {
|
||||
byte[] arr = Vectors.byte_vector2bytes(v);
|
||||
|
||||
int n = 0;
|
||||
for (; n < arr.length && arr[n] != 0; ) {
|
||||
n++;
|
||||
}
|
||||
|
||||
if (n == 0) {
|
||||
return "";
|
||||
}
|
||||
|
||||
try {
|
||||
return new String(arr, 0, n, encoding);
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public static String byte_vector2ascii(byte_vector v) {
|
||||
return byte_vector2string(v, "US-ASCII");
|
||||
}
|
||||
|
||||
public static String byte_vector2utf8(byte_vector v) {
|
||||
return byte_vector2string(v, "UTF-8");
|
||||
}
|
||||
|
||||
public static byte_vector string2byte_vector(String s, String encoding) {
|
||||
try {
|
||||
byte[] arr = s.getBytes(encoding);
|
||||
return bytes2byte_vector(arr);
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public static byte_vector ascii2byte_vector(String s) {
|
||||
return string2byte_vector(s, "US-ASCII");
|
||||
}
|
||||
}
|
@ -0,0 +1,126 @@
|
||||
package com.frostwire.jlibtorrent;
|
||||
|
||||
import com.frostwire.jlibtorrent.swig.string_string_pair;
|
||||
import com.frostwire.jlibtorrent.swig.string_string_pair_vector;
|
||||
import com.frostwire.jlibtorrent.swig.web_seed_entry;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
/**
|
||||
* The web_seed_entry holds information about a web seed (also known
|
||||
* as URL seed or HTTP seed). It is essentially a URL with some state
|
||||
* associated with it. For more information, see `BEP 17`_ and `BEP 19`_.
|
||||
*
|
||||
* @author gubatron
|
||||
* @author aldenml
|
||||
*/
|
||||
public final class WebSeedEntry {
|
||||
|
||||
private final web_seed_entry e;
|
||||
|
||||
public WebSeedEntry(web_seed_entry e) {
|
||||
this.e = e;
|
||||
}
|
||||
|
||||
public web_seed_entry swig() {
|
||||
return e;
|
||||
}
|
||||
|
||||
/**
|
||||
* The URL of the web seed.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public String url() {
|
||||
return e.getUrl();
|
||||
}
|
||||
|
||||
/**
|
||||
* Optional authentication. If this is set, it's passed
|
||||
* in as HTTP basic auth to the web seed. The format is:
|
||||
* username:password.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public String auth() {
|
||||
return e.getAuth();
|
||||
}
|
||||
|
||||
/**
|
||||
* Any extra HTTP headers that need to be passed to the web seed.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public ArrayList<Pair<String, String>> extraHeaders() {
|
||||
string_string_pair_vector v = e.getExtra_headers();
|
||||
int size = (int) v.size();
|
||||
|
||||
ArrayList<Pair<String, String>> l = new ArrayList<>(size);
|
||||
for (int i = 0; i < size; i++) {
|
||||
string_string_pair p = v.get(i);
|
||||
l.add(new Pair<>(p.getFirst(), p.getSecond()));
|
||||
}
|
||||
|
||||
return l;
|
||||
}
|
||||
|
||||
/**
|
||||
* The type of web seed.
|
||||
*
|
||||
* @return
|
||||
* @see Type
|
||||
*/
|
||||
public Type type() {
|
||||
return Type.fromSwig(e.getType());
|
||||
}
|
||||
|
||||
/**
|
||||
* Http seeds are different from url seeds in the
|
||||
* protocol they use. http seeds follows the original
|
||||
* http seed spec. by John Hoffman
|
||||
*/
|
||||
public enum Type {
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
URL_SEED(web_seed_entry.type_t.url_seed.swigValue()),
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
HTTP_SEED(web_seed_entry.type_t.http_seed.swigValue()),
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
UNKNOWN(-1);
|
||||
|
||||
private final int swigValue;
|
||||
|
||||
Type(int swigValue) {
|
||||
this.swigValue = swigValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param swigValue
|
||||
* @return
|
||||
*/
|
||||
public static Type fromSwig(int swigValue) {
|
||||
Type[] enumValues = Type.class.getEnumConstants();
|
||||
for (Type ev : enumValues) {
|
||||
if (ev.swig() == swigValue) {
|
||||
return ev;
|
||||
}
|
||||
}
|
||||
return UNKNOWN;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return
|
||||
*/
|
||||
public int swig() {
|
||||
return swigValue;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,109 @@
|
||||
package com.frostwire.jlibtorrent.alerts;
|
||||
|
||||
import com.frostwire.jlibtorrent.swig.alert;
|
||||
import com.frostwire.jlibtorrent.swig.alert_category_t;
|
||||
|
||||
/**
|
||||
* @author gubatron
|
||||
* @author aldenml
|
||||
*/
|
||||
public abstract class AbstractAlert<T extends alert> implements Alert<T> {
|
||||
|
||||
protected final T alert;
|
||||
private final AlertType type;
|
||||
|
||||
AbstractAlert(T alert) {
|
||||
this.alert = alert;
|
||||
this.type = AlertType.fromSwig(alert.type());
|
||||
}
|
||||
|
||||
@Override
|
||||
public final T swig() {
|
||||
return alert;
|
||||
}
|
||||
|
||||
/**
|
||||
* A timestamp is automatically created in the constructor (in milliseconds).
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public long timestamp() {
|
||||
return alert.get_timestamp();
|
||||
}
|
||||
|
||||
// returns an integer that is unique to this alert type. It can be
|
||||
// compared against a specific alert by querying a static constant called ``alert_type``
|
||||
// in the alert. It can be used to determine the run-time type of an alert* in
|
||||
// order to cast to that alert type and access specific members.
|
||||
//
|
||||
// e.g:
|
||||
//
|
||||
// .. code:: c++
|
||||
//
|
||||
// std::vector<alert*> alerts;
|
||||
// ses.pop_alerts(&alerts);
|
||||
// for (alert* i : alerts) {
|
||||
// switch (a->type()) {
|
||||
//
|
||||
// case read_piece_alert::alert_type:
|
||||
// {
|
||||
// read_piece_alert* p = (read_piece_alert*)a;
|
||||
// if (p->ec) {
|
||||
// // read_piece failed
|
||||
// break;
|
||||
// }
|
||||
// // use p
|
||||
// break;
|
||||
// }
|
||||
// case file_renamed_alert::alert_type:
|
||||
// {
|
||||
// // etc...
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
@Override
|
||||
public AlertType type() {
|
||||
return type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a string literal describing the type of the alert. It does
|
||||
* not include any information that might be bundled with the alert.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public String what() {
|
||||
return alert.what();
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a string describing the alert and the information bundled
|
||||
* with it. This is mainly intended for debug and development use. It is not suitable
|
||||
* to use this for applications that may be localized. Instead, handle each alert
|
||||
* type individually and extract and render the information from the alert depending
|
||||
* on the locale.
|
||||
*
|
||||
* @return the alert message
|
||||
*/
|
||||
@Override
|
||||
public String message() {
|
||||
return alert.message();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a bitmask specifying which categories this alert belong to.
|
||||
*
|
||||
* @return the alert category
|
||||
*/
|
||||
@Override
|
||||
public alert_category_t category() {
|
||||
return alert.category();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return type() + " - " + what() + " - " + message();
|
||||
}
|
||||
}
|
@ -0,0 +1,42 @@
|
||||
package com.frostwire.jlibtorrent.alerts;
|
||||
|
||||
import com.frostwire.jlibtorrent.AddTorrentParams;
|
||||
import com.frostwire.jlibtorrent.ErrorCode;
|
||||
import com.frostwire.jlibtorrent.swig.add_torrent_alert;
|
||||
|
||||
/**
|
||||
* This alert is always posted when a torrent was attempted to be added
|
||||
* and contains the return status of the add operation. The torrent handle
|
||||
* of the new torrent can be found in the {@link #handle()} member.
|
||||
* If adding the torrent failed, {@link #error()} contains the error code.
|
||||
*
|
||||
* @author gubatron
|
||||
* @author aldenml
|
||||
*/
|
||||
public final class AddTorrentAlert extends TorrentAlert<add_torrent_alert> {
|
||||
|
||||
AddTorrentAlert(add_torrent_alert alert) {
|
||||
super(alert);
|
||||
}
|
||||
|
||||
/**
|
||||
* A copy of the parameters used when adding the torrent, it can be used
|
||||
* to identify which invocation to
|
||||
* {@link com.frostwire.jlibtorrent.SessionHandle#asyncAddTorrent(AddTorrentParams)}
|
||||
* caused this alert.
|
||||
*
|
||||
* @return the params used to add the torrent
|
||||
*/
|
||||
public AddTorrentParams params() {
|
||||
return new AddTorrentParams(alert.getParams());
|
||||
}
|
||||
|
||||
/**
|
||||
* Set to the error, if one occurred while adding the torrent.
|
||||
*
|
||||
* @return the error
|
||||
*/
|
||||
public ErrorCode error() {
|
||||
return new ErrorCode(alert.getError());
|
||||
}
|
||||
}
|
@ -0,0 +1,103 @@
|
||||
package com.frostwire.jlibtorrent.alerts;
|
||||
|
||||
import com.frostwire.jlibtorrent.swig.alert;
|
||||
import com.frostwire.jlibtorrent.swig.alert_category_t;
|
||||
|
||||
/**
|
||||
* @author gubatron
|
||||
* @author aldenml
|
||||
*/
|
||||
public interface Alert<T extends alert> {
|
||||
|
||||
alert_category_t ERROR_NOTIFICATION = alert.error_notification;
|
||||
alert_category_t PEER_NOTIFICATION = alert.peer_notification;
|
||||
alert_category_t PORT_MAPPING_NOTIFICATION = alert.port_mapping_notification;
|
||||
alert_category_t STORAGE_NOTIFICATION = alert.storage_notification;
|
||||
alert_category_t TRACKER_NOTIFICATION = alert.tracker_notification;
|
||||
alert_category_t CONNECT_NOTIFICATION = alert.connect_notification;
|
||||
alert_category_t STATUS_NOTIFICATION = alert.status_notification;
|
||||
alert_category_t IP_BLOCK_NOTIFICATION = alert.ip_block_notification;
|
||||
alert_category_t PERFORMANCE_WARNING = alert.performance_warning;
|
||||
alert_category_t DHT_NOTIFICATION = alert.dht_notification;
|
||||
alert_category_t STATS_NOTIFICATION = alert.stats_notification;
|
||||
alert_category_t SESSION_LOG_NOTIFICATION = alert.session_log_notification;
|
||||
alert_category_t TORRENT_LOG_NOTIFICATION = alert.torrent_log_notification;
|
||||
alert_category_t PEER_LOG_NOTIFICATION = alert.peer_log_notification;
|
||||
alert_category_t INCOMING_REQUEST_NOTIFICATION = alert.incoming_request_notification;
|
||||
alert_category_t DHT_LOG_NOTIFICATION = alert.dht_log_notification;
|
||||
alert_category_t DHT_OPERATION_NOTIFICATION = alert.dht_operation_notification;
|
||||
alert_category_t PORT_MAPPING_LOG_NOTIFICATION = alert.port_mapping_log_notification;
|
||||
alert_category_t PICKER_LOG_NOTIFICATION = alert.picker_log_notification;
|
||||
alert_category_t FILE_PROGRESS_NOTIFICATION = alert.file_progress_notification;
|
||||
alert_category_t PIECE_PROGRESS_NOTIFICATION = alert.piece_progress_notification;
|
||||
alert_category_t UPLOAD_NOTIFICATION = alert.upload_notification;
|
||||
alert_category_t BLOCK_PROGRESS_NOTIFICATION = alert.block_progress_notification;
|
||||
alert_category_t ALL_CATEGORIES = alert.all_categories;
|
||||
|
||||
T swig();
|
||||
|
||||
/**
|
||||
* A timestamp is automatically created in the constructor (in milliseconds).
|
||||
*
|
||||
* @return the timestamp
|
||||
*/
|
||||
long timestamp();
|
||||
|
||||
// returns an integer that is unique to this alert type. It can be
|
||||
// compared against a specific alert by querying a static constant called ``alert_type``
|
||||
// in the alert. It can be used to determine the run-time type of an alert* in
|
||||
// order to cast to that alert type and access specific members.
|
||||
//
|
||||
// e.g:
|
||||
//
|
||||
// .. code:: c++
|
||||
//
|
||||
// std::vector<alert*> alerts;
|
||||
// ses.pop_alerts(&alerts);
|
||||
// for (alert* i : alerts) {
|
||||
// switch (a->type()) {
|
||||
//
|
||||
// case read_piece_alert::alert_type:
|
||||
// {
|
||||
// read_piece_alert* p = (read_piece_alert*)a;
|
||||
// if (p->ec) {
|
||||
// // read_piece failed
|
||||
// break;
|
||||
// }
|
||||
// // use p
|
||||
// break;
|
||||
// }
|
||||
// case file_renamed_alert::alert_type:
|
||||
// {
|
||||
// // etc...
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
AlertType type();
|
||||
|
||||
/**
|
||||
* Returns a string literal describing the type of the alert. It does
|
||||
* not include any information that might be bundled with the alert.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
String what();
|
||||
|
||||
/**
|
||||
* Generate a string describing the alert and the information bundled
|
||||
* with it. This is mainly intended for debug and development use. It is not suitable
|
||||
* to use this for applications that may be localized. Instead, handle each alert
|
||||
* type individually and extract and render the information from the alert depending
|
||||
* on the locale.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
String message();
|
||||
|
||||
/**
|
||||
* Returns a bitmask specifying which categories this alert belong to.
|
||||
*
|
||||
* @return the alert category
|
||||
*/
|
||||
alert_category_t category();
|
||||
}
|
@ -0,0 +1,312 @@
|
||||
package com.frostwire.jlibtorrent.alerts;
|
||||
|
||||
import com.frostwire.jlibtorrent.swig.add_torrent_alert;
|
||||
import com.frostwire.jlibtorrent.swig.alerts_dropped_alert;
|
||||
import com.frostwire.jlibtorrent.swig.block_downloading_alert;
|
||||
import com.frostwire.jlibtorrent.swig.block_finished_alert;
|
||||
import com.frostwire.jlibtorrent.swig.block_timeout_alert;
|
||||
import com.frostwire.jlibtorrent.swig.block_uploaded_alert;
|
||||
import com.frostwire.jlibtorrent.swig.cache_flushed_alert;
|
||||
import com.frostwire.jlibtorrent.swig.dht_announce_alert;
|
||||
import com.frostwire.jlibtorrent.swig.dht_bootstrap_alert;
|
||||
import com.frostwire.jlibtorrent.swig.dht_direct_response_alert;
|
||||
import com.frostwire.jlibtorrent.swig.dht_error_alert;
|
||||
import com.frostwire.jlibtorrent.swig.dht_get_peers_alert;
|
||||
import com.frostwire.jlibtorrent.swig.dht_get_peers_reply_alert;
|
||||
import com.frostwire.jlibtorrent.swig.dht_immutable_item_alert;
|
||||
import com.frostwire.jlibtorrent.swig.dht_live_nodes_alert;
|
||||
import com.frostwire.jlibtorrent.swig.dht_log_alert;
|
||||
import com.frostwire.jlibtorrent.swig.dht_mutable_item_alert;
|
||||
import com.frostwire.jlibtorrent.swig.dht_outgoing_get_peers_alert;
|
||||
import com.frostwire.jlibtorrent.swig.dht_pkt_alert;
|
||||
import com.frostwire.jlibtorrent.swig.dht_put_alert;
|
||||
import com.frostwire.jlibtorrent.swig.dht_reply_alert;
|
||||
import com.frostwire.jlibtorrent.swig.dht_sample_infohashes_alert;
|
||||
import com.frostwire.jlibtorrent.swig.dht_stats_alert;
|
||||
import com.frostwire.jlibtorrent.swig.external_ip_alert;
|
||||
import com.frostwire.jlibtorrent.swig.fastresume_rejected_alert;
|
||||
import com.frostwire.jlibtorrent.swig.file_completed_alert;
|
||||
import com.frostwire.jlibtorrent.swig.file_error_alert;
|
||||
import com.frostwire.jlibtorrent.swig.file_rename_failed_alert;
|
||||
import com.frostwire.jlibtorrent.swig.file_renamed_alert;
|
||||
import com.frostwire.jlibtorrent.swig.hash_failed_alert;
|
||||
import com.frostwire.jlibtorrent.swig.i2p_alert;
|
||||
import com.frostwire.jlibtorrent.swig.incoming_connection_alert;
|
||||
import com.frostwire.jlibtorrent.swig.incoming_request_alert;
|
||||
import com.frostwire.jlibtorrent.swig.invalid_request_alert;
|
||||
import com.frostwire.jlibtorrent.swig.listen_failed_alert;
|
||||
import com.frostwire.jlibtorrent.swig.listen_succeeded_alert;
|
||||
import com.frostwire.jlibtorrent.swig.log_alert;
|
||||
import com.frostwire.jlibtorrent.swig.lsd_error_alert;
|
||||
import com.frostwire.jlibtorrent.swig.lsd_peer_alert;
|
||||
import com.frostwire.jlibtorrent.swig.metadata_failed_alert;
|
||||
import com.frostwire.jlibtorrent.swig.metadata_received_alert;
|
||||
import com.frostwire.jlibtorrent.swig.peer_ban_alert;
|
||||
import com.frostwire.jlibtorrent.swig.peer_blocked_alert;
|
||||
import com.frostwire.jlibtorrent.swig.peer_connect_alert;
|
||||
import com.frostwire.jlibtorrent.swig.peer_disconnected_alert;
|
||||
import com.frostwire.jlibtorrent.swig.peer_error_alert;
|
||||
import com.frostwire.jlibtorrent.swig.peer_log_alert;
|
||||
import com.frostwire.jlibtorrent.swig.peer_snubbed_alert;
|
||||
import com.frostwire.jlibtorrent.swig.peer_unsnubbed_alert;
|
||||
import com.frostwire.jlibtorrent.swig.performance_alert;
|
||||
import com.frostwire.jlibtorrent.swig.picker_log_alert;
|
||||
import com.frostwire.jlibtorrent.swig.piece_finished_alert;
|
||||
import com.frostwire.jlibtorrent.swig.portmap_alert;
|
||||
import com.frostwire.jlibtorrent.swig.portmap_error_alert;
|
||||
import com.frostwire.jlibtorrent.swig.portmap_log_alert;
|
||||
import com.frostwire.jlibtorrent.swig.read_piece_alert;
|
||||
import com.frostwire.jlibtorrent.swig.request_dropped_alert;
|
||||
import com.frostwire.jlibtorrent.swig.save_resume_data_alert;
|
||||
import com.frostwire.jlibtorrent.swig.save_resume_data_failed_alert;
|
||||
import com.frostwire.jlibtorrent.swig.scrape_failed_alert;
|
||||
import com.frostwire.jlibtorrent.swig.scrape_reply_alert;
|
||||
import com.frostwire.jlibtorrent.swig.session_error_alert;
|
||||
import com.frostwire.jlibtorrent.swig.session_stats_alert;
|
||||
import com.frostwire.jlibtorrent.swig.session_stats_header_alert;
|
||||
import com.frostwire.jlibtorrent.swig.socks5_alert;
|
||||
import com.frostwire.jlibtorrent.swig.state_changed_alert;
|
||||
import com.frostwire.jlibtorrent.swig.state_update_alert;
|
||||
import com.frostwire.jlibtorrent.swig.stats_alert;
|
||||
import com.frostwire.jlibtorrent.swig.storage_moved_alert;
|
||||
import com.frostwire.jlibtorrent.swig.storage_moved_failed_alert;
|
||||
import com.frostwire.jlibtorrent.swig.torrent_checked_alert;
|
||||
import com.frostwire.jlibtorrent.swig.torrent_delete_failed_alert;
|
||||
import com.frostwire.jlibtorrent.swig.torrent_deleted_alert;
|
||||
import com.frostwire.jlibtorrent.swig.torrent_error_alert;
|
||||
import com.frostwire.jlibtorrent.swig.torrent_finished_alert;
|
||||
import com.frostwire.jlibtorrent.swig.torrent_log_alert;
|
||||
import com.frostwire.jlibtorrent.swig.torrent_need_cert_alert;
|
||||
import com.frostwire.jlibtorrent.swig.torrent_paused_alert;
|
||||
import com.frostwire.jlibtorrent.swig.torrent_removed_alert;
|
||||
import com.frostwire.jlibtorrent.swig.torrent_resumed_alert;
|
||||
import com.frostwire.jlibtorrent.swig.tracker_announce_alert;
|
||||
import com.frostwire.jlibtorrent.swig.tracker_error_alert;
|
||||
import com.frostwire.jlibtorrent.swig.tracker_reply_alert;
|
||||
import com.frostwire.jlibtorrent.swig.tracker_warning_alert;
|
||||
import com.frostwire.jlibtorrent.swig.trackerid_alert;
|
||||
import com.frostwire.jlibtorrent.swig.udp_error_alert;
|
||||
import com.frostwire.jlibtorrent.swig.unwanted_block_alert;
|
||||
import com.frostwire.jlibtorrent.swig.url_seed_alert;
|
||||
|
||||
/**
|
||||
* @author gubatron
|
||||
* @author aldenml
|
||||
*/
|
||||
public enum AlertType {
|
||||
|
||||
TORRENT_FINISHED(torrent_finished_alert.alert_type),
|
||||
TORRENT_REMOVED(torrent_removed_alert.alert_type),
|
||||
TORRENT_DELETED(torrent_deleted_alert.alert_type),
|
||||
TORRENT_PAUSED(torrent_paused_alert.alert_type),
|
||||
TORRENT_RESUMED(torrent_resumed_alert.alert_type),
|
||||
TORRENT_CHECKED(torrent_checked_alert.alert_type),
|
||||
TORRENT_ERROR(torrent_error_alert.alert_type),
|
||||
TORRENT_NEED_CERT(torrent_need_cert_alert.alert_type),
|
||||
INCOMING_CONNECTION(incoming_connection_alert.alert_type),
|
||||
ADD_TORRENT(add_torrent_alert.alert_type),
|
||||
SAVE_RESUME_DATA(save_resume_data_alert.alert_type),
|
||||
FASTRESUME_REJECTED(fastresume_rejected_alert.alert_type),
|
||||
BLOCK_FINISHED(block_finished_alert.alert_type),
|
||||
METADATA_RECEIVED(metadata_received_alert.alert_type),
|
||||
METADATA_FAILED(metadata_failed_alert.alert_type),
|
||||
FILE_COMPLETED(file_completed_alert.alert_type),
|
||||
FILE_RENAMED(file_renamed_alert.alert_type),
|
||||
FILE_RENAME_FAILED(file_rename_failed_alert.alert_type),
|
||||
FILE_ERROR(file_error_alert.alert_type),
|
||||
HASH_FAILED(hash_failed_alert.alert_type),
|
||||
PORTMAP(portmap_alert.alert_type),
|
||||
PORTMAP_ERROR(portmap_error_alert.alert_type),
|
||||
PORTMAP_LOG(portmap_log_alert.alert_type),
|
||||
TRACKER_ANNOUNCE(tracker_announce_alert.alert_type),
|
||||
TRACKER_REPLY(tracker_reply_alert.alert_type),
|
||||
TRACKER_WARNING(tracker_warning_alert.alert_type),
|
||||
TRACKER_ERROR(tracker_error_alert.alert_type),
|
||||
READ_PIECE(read_piece_alert.alert_type),
|
||||
STATE_CHANGED(state_changed_alert.alert_type),
|
||||
DHT_REPLY(dht_reply_alert.alert_type),
|
||||
DHT_BOOTSTRAP(dht_bootstrap_alert.alert_type),
|
||||
DHT_GET_PEERS(dht_get_peers_alert.alert_type),
|
||||
EXTERNAL_IP(external_ip_alert.alert_type),
|
||||
LISTEN_SUCCEEDED(listen_succeeded_alert.alert_type),
|
||||
STATE_UPDATE(state_update_alert.alert_type),
|
||||
SESSION_STATS(session_stats_alert.alert_type),
|
||||
SCRAPE_REPLY(scrape_reply_alert.alert_type),
|
||||
SCRAPE_FAILED(scrape_failed_alert.alert_type),
|
||||
LSD_PEER(lsd_peer_alert.alert_type),
|
||||
PEER_BLOCKED(peer_blocked_alert.alert_type),
|
||||
PERFORMANCE(performance_alert.alert_type),
|
||||
PIECE_FINISHED(piece_finished_alert.alert_type),
|
||||
SAVE_RESUME_DATA_FAILED(save_resume_data_failed_alert.alert_type),
|
||||
STATS(stats_alert.alert_type),
|
||||
STORAGE_MOVED(storage_moved_alert.alert_type),
|
||||
TORRENT_DELETE_FAILED(torrent_delete_failed_alert.alert_type),
|
||||
URL_SEED(url_seed_alert.alert_type),
|
||||
INVALID_REQUEST(invalid_request_alert.alert_type),
|
||||
LISTEN_FAILED(listen_failed_alert.alert_type),
|
||||
PEER_BAN(peer_ban_alert.alert_type),
|
||||
PEER_CONNECT(peer_connect_alert.alert_type),
|
||||
PEER_DISCONNECTED(peer_disconnected_alert.alert_type),
|
||||
PEER_ERROR(peer_error_alert.alert_type),
|
||||
PEER_SNUBBED(peer_snubbed_alert.alert_type),
|
||||
PEER_UNSNUBBED(peer_unsnubbed_alert.alert_type),
|
||||
REQUEST_DROPPED(request_dropped_alert.alert_type),
|
||||
UDP_ERROR(udp_error_alert.alert_type),
|
||||
BLOCK_DOWNLOADING(block_downloading_alert.alert_type),
|
||||
BLOCK_TIMEOUT(block_timeout_alert.alert_type),
|
||||
CACHE_FLUSHED(cache_flushed_alert.alert_type),
|
||||
DHT_ANNOUNCE(dht_announce_alert.alert_type),
|
||||
STORAGE_MOVED_FAILED(storage_moved_failed_alert.alert_type),
|
||||
TRACKERID(trackerid_alert.alert_type),
|
||||
UNWANTED_BLOCK(unwanted_block_alert.alert_type),
|
||||
DHT_ERROR(dht_error_alert.alert_type),
|
||||
DHT_PUT(dht_put_alert.alert_type),
|
||||
DHT_MUTABLE_ITEM(dht_mutable_item_alert.alert_type),
|
||||
DHT_IMMUTABLE_ITEM(dht_immutable_item_alert.alert_type),
|
||||
I2P(i2p_alert.alert_type),
|
||||
DHT_OUTGOING_GET_PEERS(dht_outgoing_get_peers_alert.alert_type),
|
||||
LOG(log_alert.alert_type),
|
||||
TORRENT_LOG(torrent_log_alert.alert_type),
|
||||
PEER_LOG(peer_log_alert.alert_type),
|
||||
LSD_ERROR(lsd_error_alert.alert_type),
|
||||
DHT_STATS(dht_stats_alert.alert_type),
|
||||
INCOMING_REQUEST(incoming_request_alert.alert_type),
|
||||
DHT_LOG(dht_log_alert.alert_type),
|
||||
DHT_PKT(dht_pkt_alert.alert_type),
|
||||
DHT_GET_PEERS_REPLY(dht_get_peers_reply_alert.alert_type),
|
||||
DHT_DIRECT_RESPONSE(dht_direct_response_alert.alert_type),
|
||||
PICKER_LOG(picker_log_alert.alert_type),
|
||||
SESSION_ERROR(session_error_alert.alert_type),
|
||||
DHT_LIVE_NODES(dht_live_nodes_alert.alert_type),
|
||||
SESSION_STATS_HEADER(session_stats_header_alert.alert_type),
|
||||
DHT_SAMPLE_INFOHASHES(dht_sample_infohashes_alert.alert_type),
|
||||
BLOCK_UPLOADED(block_uploaded_alert.alert_type),
|
||||
ALERTS_DROPPED(alerts_dropped_alert.alert_type),
|
||||
SOCKS5_ALERT(socks5_alert.alert_type),
|
||||
UNKNOWN(-1);
|
||||
|
||||
private static final AlertType[] TABLE = buildTable();
|
||||
private final int swigValue;
|
||||
|
||||
AlertType(int swigValue) {
|
||||
this.swigValue = swigValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param swigValue the native swig value
|
||||
* @return the API enum alert type
|
||||
*/
|
||||
public static AlertType fromSwig(int swigValue) {
|
||||
return TABLE[swigValue];
|
||||
}
|
||||
|
||||
private static AlertType[] buildTable() {
|
||||
AlertType[] arr = new AlertType[Alerts.NUM_ALERT_TYPES];
|
||||
|
||||
arr[0] = UNKNOWN;
|
||||
arr[1] = UNKNOWN;
|
||||
arr[2] = UNKNOWN;
|
||||
arr[3] = UNKNOWN;
|
||||
arr[4] = TORRENT_REMOVED;
|
||||
arr[5] = READ_PIECE;
|
||||
arr[6] = FILE_COMPLETED;
|
||||
arr[7] = FILE_RENAMED;
|
||||
arr[8] = FILE_RENAME_FAILED;
|
||||
arr[9] = PERFORMANCE;
|
||||
arr[10] = STATE_CHANGED;
|
||||
arr[11] = TRACKER_ERROR;
|
||||
arr[12] = TRACKER_WARNING;
|
||||
arr[13] = SCRAPE_REPLY;
|
||||
arr[14] = SCRAPE_FAILED;
|
||||
arr[15] = TRACKER_REPLY;
|
||||
arr[16] = DHT_REPLY;
|
||||
arr[17] = TRACKER_ANNOUNCE;
|
||||
arr[18] = HASH_FAILED;
|
||||
arr[19] = PEER_BAN;
|
||||
arr[20] = PEER_UNSNUBBED;
|
||||
arr[21] = PEER_SNUBBED;
|
||||
arr[22] = PEER_ERROR;
|
||||
arr[23] = PEER_CONNECT;
|
||||
arr[24] = PEER_DISCONNECTED;
|
||||
arr[25] = INVALID_REQUEST;
|
||||
arr[26] = TORRENT_FINISHED;
|
||||
arr[27] = PIECE_FINISHED;
|
||||
arr[28] = REQUEST_DROPPED;
|
||||
arr[29] = BLOCK_TIMEOUT;
|
||||
arr[30] = BLOCK_FINISHED;
|
||||
arr[31] = BLOCK_DOWNLOADING;
|
||||
arr[32] = UNWANTED_BLOCK;
|
||||
arr[33] = STORAGE_MOVED;
|
||||
arr[34] = STORAGE_MOVED_FAILED;
|
||||
arr[35] = TORRENT_DELETED;
|
||||
arr[36] = TORRENT_DELETE_FAILED;
|
||||
arr[37] = SAVE_RESUME_DATA;
|
||||
arr[38] = SAVE_RESUME_DATA_FAILED;
|
||||
arr[39] = TORRENT_PAUSED;
|
||||
arr[40] = TORRENT_RESUMED;
|
||||
arr[41] = TORRENT_CHECKED;
|
||||
arr[42] = URL_SEED;
|
||||
arr[43] = FILE_ERROR;
|
||||
arr[44] = METADATA_FAILED;
|
||||
arr[45] = METADATA_RECEIVED;
|
||||
arr[46] = UDP_ERROR;
|
||||
arr[47] = EXTERNAL_IP;
|
||||
arr[48] = LISTEN_FAILED;
|
||||
arr[49] = LISTEN_SUCCEEDED;
|
||||
arr[50] = PORTMAP_ERROR;
|
||||
arr[51] = PORTMAP;
|
||||
arr[52] = PORTMAP_LOG;
|
||||
arr[53] = FASTRESUME_REJECTED;
|
||||
arr[54] = PEER_BLOCKED;
|
||||
arr[55] = DHT_ANNOUNCE;
|
||||
arr[56] = DHT_GET_PEERS;
|
||||
arr[57] = STATS;
|
||||
arr[58] = CACHE_FLUSHED;
|
||||
arr[59] = UNKNOWN;
|
||||
arr[60] = LSD_PEER;
|
||||
arr[61] = TRACKERID;
|
||||
arr[62] = DHT_BOOTSTRAP;
|
||||
arr[63] = UNKNOWN;
|
||||
arr[64] = TORRENT_ERROR;
|
||||
arr[65] = TORRENT_NEED_CERT;
|
||||
arr[66] = INCOMING_CONNECTION;
|
||||
arr[67] = ADD_TORRENT;
|
||||
arr[68] = STATE_UPDATE;
|
||||
arr[69] = UNKNOWN;
|
||||
arr[70] = SESSION_STATS;
|
||||
arr[71] = UNKNOWN;
|
||||
arr[72] = UNKNOWN;
|
||||
arr[73] = DHT_ERROR;
|
||||
arr[74] = DHT_IMMUTABLE_ITEM;
|
||||
arr[75] = DHT_MUTABLE_ITEM;
|
||||
arr[76] = DHT_PUT;
|
||||
arr[77] = I2P;
|
||||
arr[78] = DHT_OUTGOING_GET_PEERS;
|
||||
arr[79] = LOG;
|
||||
arr[80] = TORRENT_LOG;
|
||||
arr[81] = PEER_LOG;
|
||||
arr[82] = LSD_ERROR;
|
||||
arr[83] = DHT_STATS;
|
||||
arr[84] = INCOMING_REQUEST;
|
||||
arr[85] = DHT_LOG;
|
||||
arr[86] = DHT_PKT;
|
||||
arr[87] = DHT_GET_PEERS_REPLY;
|
||||
arr[88] = DHT_DIRECT_RESPONSE;
|
||||
arr[89] = PICKER_LOG;
|
||||
arr[90] = SESSION_ERROR;
|
||||
arr[91] = DHT_LIVE_NODES;
|
||||
arr[92] = SESSION_STATS_HEADER;
|
||||
arr[93] = DHT_SAMPLE_INFOHASHES;
|
||||
arr[94] = BLOCK_UPLOADED;
|
||||
arr[95] = ALERTS_DROPPED;
|
||||
arr[96] = SOCKS5_ALERT;
|
||||
return arr;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the native swig value
|
||||
*/
|
||||
public int swig() {
|
||||
return swigValue;
|
||||
}
|
||||
}
|
@ -0,0 +1,701 @@
|
||||
package com.frostwire.jlibtorrent.alerts;
|
||||
|
||||
import com.frostwire.jlibtorrent.swig.alert;
|
||||
import com.frostwire.jlibtorrent.swig.libtorrent;
|
||||
|
||||
import static com.frostwire.jlibtorrent.swig.alert.cast_to_add_torrent_alert;
|
||||
import static com.frostwire.jlibtorrent.swig.alert.cast_to_alerts_dropped_alert;
|
||||
import static com.frostwire.jlibtorrent.swig.alert.cast_to_block_downloading_alert;
|
||||
import static com.frostwire.jlibtorrent.swig.alert.cast_to_block_finished_alert;
|
||||
import static com.frostwire.jlibtorrent.swig.alert.cast_to_block_timeout_alert;
|
||||
import static com.frostwire.jlibtorrent.swig.alert.cast_to_block_uploaded_alert;
|
||||
import static com.frostwire.jlibtorrent.swig.alert.cast_to_cache_flushed_alert;
|
||||
import static com.frostwire.jlibtorrent.swig.alert.cast_to_dht_announce_alert;
|
||||
import static com.frostwire.jlibtorrent.swig.alert.cast_to_dht_bootstrap_alert;
|
||||
import static com.frostwire.jlibtorrent.swig.alert.cast_to_dht_direct_response_alert;
|
||||
import static com.frostwire.jlibtorrent.swig.alert.cast_to_dht_error_alert;
|
||||
import static com.frostwire.jlibtorrent.swig.alert.cast_to_dht_get_peers_alert;
|
||||
import static com.frostwire.jlibtorrent.swig.alert.cast_to_dht_get_peers_reply_alert;
|
||||
import static com.frostwire.jlibtorrent.swig.alert.cast_to_dht_immutable_item_alert;
|
||||
import static com.frostwire.jlibtorrent.swig.alert.cast_to_dht_live_nodes_alert;
|
||||
import static com.frostwire.jlibtorrent.swig.alert.cast_to_dht_log_alert;
|
||||
import static com.frostwire.jlibtorrent.swig.alert.cast_to_dht_mutable_item_alert;
|
||||
import static com.frostwire.jlibtorrent.swig.alert.cast_to_dht_outgoing_get_peers_alert;
|
||||
import static com.frostwire.jlibtorrent.swig.alert.cast_to_dht_pkt_alert;
|
||||
import static com.frostwire.jlibtorrent.swig.alert.cast_to_dht_put_alert;
|
||||
import static com.frostwire.jlibtorrent.swig.alert.cast_to_dht_reply_alert;
|
||||
import static com.frostwire.jlibtorrent.swig.alert.cast_to_dht_sample_infohashes_alert;
|
||||
import static com.frostwire.jlibtorrent.swig.alert.cast_to_dht_stats_alert;
|
||||
import static com.frostwire.jlibtorrent.swig.alert.cast_to_external_ip_alert;
|
||||
import static com.frostwire.jlibtorrent.swig.alert.cast_to_fastresume_rejected_alert;
|
||||
import static com.frostwire.jlibtorrent.swig.alert.cast_to_file_completed_alert;
|
||||
import static com.frostwire.jlibtorrent.swig.alert.cast_to_file_error_alert;
|
||||
import static com.frostwire.jlibtorrent.swig.alert.cast_to_file_rename_failed_alert;
|
||||
import static com.frostwire.jlibtorrent.swig.alert.cast_to_file_renamed_alert;
|
||||
import static com.frostwire.jlibtorrent.swig.alert.cast_to_hash_failed_alert;
|
||||
import static com.frostwire.jlibtorrent.swig.alert.cast_to_i2p_alert;
|
||||
import static com.frostwire.jlibtorrent.swig.alert.cast_to_incoming_connection_alert;
|
||||
import static com.frostwire.jlibtorrent.swig.alert.cast_to_incoming_request_alert;
|
||||
import static com.frostwire.jlibtorrent.swig.alert.cast_to_invalid_request_alert;
|
||||
import static com.frostwire.jlibtorrent.swig.alert.cast_to_listen_failed_alert;
|
||||
import static com.frostwire.jlibtorrent.swig.alert.cast_to_listen_succeeded_alert;
|
||||
import static com.frostwire.jlibtorrent.swig.alert.cast_to_log_alert;
|
||||
import static com.frostwire.jlibtorrent.swig.alert.cast_to_lsd_error_alert;
|
||||
import static com.frostwire.jlibtorrent.swig.alert.cast_to_lsd_peer_alert;
|
||||
import static com.frostwire.jlibtorrent.swig.alert.cast_to_metadata_failed_alert;
|
||||
import static com.frostwire.jlibtorrent.swig.alert.cast_to_metadata_received_alert;
|
||||
import static com.frostwire.jlibtorrent.swig.alert.cast_to_peer_ban_alert;
|
||||
import static com.frostwire.jlibtorrent.swig.alert.cast_to_peer_blocked_alert;
|
||||
import static com.frostwire.jlibtorrent.swig.alert.cast_to_peer_connect_alert;
|
||||
import static com.frostwire.jlibtorrent.swig.alert.cast_to_peer_disconnected_alert;
|
||||
import static com.frostwire.jlibtorrent.swig.alert.cast_to_peer_error_alert;
|
||||
import static com.frostwire.jlibtorrent.swig.alert.cast_to_peer_log_alert;
|
||||
import static com.frostwire.jlibtorrent.swig.alert.cast_to_peer_snubbed_alert;
|
||||
import static com.frostwire.jlibtorrent.swig.alert.cast_to_peer_unsnubbed_alert;
|
||||
import static com.frostwire.jlibtorrent.swig.alert.cast_to_performance_alert;
|
||||
import static com.frostwire.jlibtorrent.swig.alert.cast_to_picker_log_alert;
|
||||
import static com.frostwire.jlibtorrent.swig.alert.cast_to_piece_finished_alert;
|
||||
import static com.frostwire.jlibtorrent.swig.alert.cast_to_portmap_alert;
|
||||
import static com.frostwire.jlibtorrent.swig.alert.cast_to_portmap_error_alert;
|
||||
import static com.frostwire.jlibtorrent.swig.alert.cast_to_portmap_log_alert;
|
||||
import static com.frostwire.jlibtorrent.swig.alert.cast_to_read_piece_alert;
|
||||
import static com.frostwire.jlibtorrent.swig.alert.cast_to_request_dropped_alert;
|
||||
import static com.frostwire.jlibtorrent.swig.alert.cast_to_save_resume_data_alert;
|
||||
import static com.frostwire.jlibtorrent.swig.alert.cast_to_save_resume_data_failed_alert;
|
||||
import static com.frostwire.jlibtorrent.swig.alert.cast_to_scrape_failed_alert;
|
||||
import static com.frostwire.jlibtorrent.swig.alert.cast_to_scrape_reply_alert;
|
||||
import static com.frostwire.jlibtorrent.swig.alert.cast_to_session_error_alert;
|
||||
import static com.frostwire.jlibtorrent.swig.alert.cast_to_session_stats_alert;
|
||||
import static com.frostwire.jlibtorrent.swig.alert.cast_to_session_stats_header_alert;
|
||||
import static com.frostwire.jlibtorrent.swig.alert.cast_to_state_changed_alert;
|
||||
import static com.frostwire.jlibtorrent.swig.alert.cast_to_state_update_alert;
|
||||
import static com.frostwire.jlibtorrent.swig.alert.cast_to_stats_alert;
|
||||
import static com.frostwire.jlibtorrent.swig.alert.cast_to_storage_moved_alert;
|
||||
import static com.frostwire.jlibtorrent.swig.alert.cast_to_storage_moved_failed_alert;
|
||||
import static com.frostwire.jlibtorrent.swig.alert.cast_to_torrent_checked_alert;
|
||||
import static com.frostwire.jlibtorrent.swig.alert.cast_to_torrent_delete_failed_alert;
|
||||
import static com.frostwire.jlibtorrent.swig.alert.cast_to_torrent_deleted_alert;
|
||||
import static com.frostwire.jlibtorrent.swig.alert.cast_to_torrent_error_alert;
|
||||
import static com.frostwire.jlibtorrent.swig.alert.cast_to_torrent_finished_alert;
|
||||
import static com.frostwire.jlibtorrent.swig.alert.cast_to_torrent_log_alert;
|
||||
import static com.frostwire.jlibtorrent.swig.alert.cast_to_torrent_need_cert_alert;
|
||||
import static com.frostwire.jlibtorrent.swig.alert.cast_to_torrent_paused_alert;
|
||||
import static com.frostwire.jlibtorrent.swig.alert.cast_to_torrent_removed_alert;
|
||||
import static com.frostwire.jlibtorrent.swig.alert.cast_to_torrent_resumed_alert;
|
||||
import static com.frostwire.jlibtorrent.swig.alert.cast_to_tracker_announce_alert;
|
||||
import static com.frostwire.jlibtorrent.swig.alert.cast_to_tracker_error_alert;
|
||||
import static com.frostwire.jlibtorrent.swig.alert.cast_to_tracker_reply_alert;
|
||||
import static com.frostwire.jlibtorrent.swig.alert.cast_to_tracker_warning_alert;
|
||||
import static com.frostwire.jlibtorrent.swig.alert.cast_to_trackerid_alert;
|
||||
import static com.frostwire.jlibtorrent.swig.alert.cast_to_udp_error_alert;
|
||||
import static com.frostwire.jlibtorrent.swig.alert.cast_to_unwanted_block_alert;
|
||||
import static com.frostwire.jlibtorrent.swig.alert.cast_to_url_seed_alert;
|
||||
|
||||
/**
|
||||
* @author gubatron
|
||||
* @author aldenml
|
||||
*/
|
||||
public final class Alerts {
|
||||
|
||||
public static final int NUM_ALERT_TYPES = libtorrent.getNum_alert_types();
|
||||
|
||||
private static final CastLambda[] TABLE = buildTable();
|
||||
|
||||
private Alerts() {
|
||||
}
|
||||
|
||||
public static Alert cast(alert a) {
|
||||
return TABLE[a.type()].cast(a);
|
||||
}
|
||||
|
||||
private static CastLambda[] buildTable() {
|
||||
CastLambda[] arr = new CastLambda[NUM_ALERT_TYPES];
|
||||
|
||||
arr[0] = new CastLambda() {
|
||||
@Override
|
||||
public Alert cast(alert a) {
|
||||
return handleUnknownAlert(a);
|
||||
}
|
||||
};
|
||||
arr[1] = new CastLambda() {
|
||||
@Override
|
||||
public Alert cast(alert a) {
|
||||
return handleUnknownAlert(a);
|
||||
}
|
||||
};
|
||||
arr[2] = new CastLambda() {
|
||||
@Override
|
||||
public Alert cast(alert a) {
|
||||
return handleUnknownAlert(a);
|
||||
}
|
||||
};
|
||||
arr[3] = new CastLambda() {
|
||||
@Override
|
||||
public Alert cast(alert a) {
|
||||
return handleUnknownAlert(a);
|
||||
}
|
||||
};
|
||||
arr[4] = new CastLambda() {
|
||||
@Override
|
||||
public Alert cast(alert a) {
|
||||
return new TorrentRemovedAlert(cast_to_torrent_removed_alert(a));
|
||||
}
|
||||
};
|
||||
arr[5] = new CastLambda() {
|
||||
@Override
|
||||
public Alert cast(alert a) {
|
||||
return new ReadPieceAlert(cast_to_read_piece_alert(a));
|
||||
}
|
||||
};
|
||||
arr[6] = new CastLambda() {
|
||||
@Override
|
||||
public Alert cast(alert a) {
|
||||
return new FileCompletedAlert(cast_to_file_completed_alert(a));
|
||||
}
|
||||
};
|
||||
arr[7] = new CastLambda() {
|
||||
@Override
|
||||
public Alert cast(alert a) {
|
||||
return new FileRenamedAlert(cast_to_file_renamed_alert(a));
|
||||
}
|
||||
};
|
||||
arr[8] = new CastLambda() {
|
||||
@Override
|
||||
public Alert cast(alert a) {
|
||||
return new FileRenameFailedAlert(cast_to_file_rename_failed_alert(a));
|
||||
}
|
||||
};
|
||||
arr[9] = new CastLambda() {
|
||||
@Override
|
||||
public Alert cast(alert a) {
|
||||
return new PerformanceAlert(cast_to_performance_alert(a));
|
||||
}
|
||||
};
|
||||
arr[10] = new CastLambda() {
|
||||
@Override
|
||||
public Alert cast(alert a) {
|
||||
return new StateChangedAlert(cast_to_state_changed_alert(a));
|
||||
}
|
||||
};
|
||||
arr[11] = new CastLambda() {
|
||||
@Override
|
||||
public Alert cast(alert a) {
|
||||
return new TrackerErrorAlert(cast_to_tracker_error_alert(a));
|
||||
}
|
||||
};
|
||||
arr[12] = new CastLambda() {
|
||||
@Override
|
||||
public Alert cast(alert a) {
|
||||
return new TrackerWarningAlert(cast_to_tracker_warning_alert(a));
|
||||
}
|
||||
};
|
||||
arr[13] = new CastLambda() {
|
||||
@Override
|
||||
public Alert cast(alert a) {
|
||||
return new ScrapeReplyAlert(cast_to_scrape_reply_alert(a));
|
||||
}
|
||||
};
|
||||
arr[14] = new CastLambda() {
|
||||
@Override
|
||||
public Alert cast(alert a) {
|
||||
return new ScrapeFailedAlert(cast_to_scrape_failed_alert(a));
|
||||
}
|
||||
};
|
||||
arr[15] = new CastLambda() {
|
||||
@Override
|
||||
public Alert cast(alert a) {
|
||||
return new TrackerReplyAlert(cast_to_tracker_reply_alert(a));
|
||||
}
|
||||
};
|
||||
arr[16] = new CastLambda() {
|
||||
@Override
|
||||
public Alert cast(alert a) {
|
||||
return new DhtReplyAlert(cast_to_dht_reply_alert(a));
|
||||
}
|
||||
};
|
||||
arr[17] = new CastLambda() {
|
||||
@Override
|
||||
public Alert cast(alert a) {
|
||||
return new TrackerAnnounceAlert(cast_to_tracker_announce_alert(a));
|
||||
}
|
||||
};
|
||||
arr[18] = new CastLambda() {
|
||||
@Override
|
||||
public Alert cast(alert a) {
|
||||
return new HashFailedAlert(cast_to_hash_failed_alert(a));
|
||||
}
|
||||
};
|
||||
arr[19] = new CastLambda() {
|
||||
@Override
|
||||
public Alert cast(alert a) {
|
||||
return new PeerBanAlert(cast_to_peer_ban_alert(a));
|
||||
}
|
||||
};
|
||||
arr[20] = new CastLambda() {
|
||||
@Override
|
||||
public Alert cast(alert a) {
|
||||
return new PeerUnsnubbedAlert(cast_to_peer_unsnubbed_alert(a));
|
||||
}
|
||||
};
|
||||
arr[21] = new CastLambda() {
|
||||
@Override
|
||||
public Alert cast(alert a) {
|
||||
return new PeerSnubbedAlert(cast_to_peer_snubbed_alert(a));
|
||||
}
|
||||
};
|
||||
arr[22] = new CastLambda() {
|
||||
@Override
|
||||
public Alert cast(alert a) {
|
||||
return new PeerErrorAlert(cast_to_peer_error_alert(a));
|
||||
}
|
||||
};
|
||||
arr[23] = new CastLambda() {
|
||||
@Override
|
||||
public Alert cast(alert a) {
|
||||
return new PeerConnectAlert(cast_to_peer_connect_alert(a));
|
||||
}
|
||||
};
|
||||
arr[24] = new CastLambda() {
|
||||
@Override
|
||||
public Alert cast(alert a) {
|
||||
return new PeerDisconnectedAlert(cast_to_peer_disconnected_alert(a));
|
||||
}
|
||||
};
|
||||
arr[25] = new CastLambda() {
|
||||
@Override
|
||||
public Alert cast(alert a) {
|
||||
return new InvalidRequestAlert(cast_to_invalid_request_alert(a));
|
||||
}
|
||||
};
|
||||
arr[26] = new CastLambda() {
|
||||
@Override
|
||||
public Alert cast(alert a) {
|
||||
return new TorrentFinishedAlert(cast_to_torrent_finished_alert(a));
|
||||
}
|
||||
};
|
||||
arr[27] = new CastLambda() {
|
||||
@Override
|
||||
public Alert cast(alert a) {
|
||||
return new PieceFinishedAlert(cast_to_piece_finished_alert(a));
|
||||
}
|
||||
};
|
||||
arr[28] = new CastLambda() {
|
||||
@Override
|
||||
public Alert cast(alert a) {
|
||||
return new RequestDroppedAlert(cast_to_request_dropped_alert(a));
|
||||
}
|
||||
};
|
||||
arr[29] = new CastLambda() {
|
||||
@Override
|
||||
public Alert cast(alert a) {
|
||||
return new BlockTimeoutAlert(cast_to_block_timeout_alert(a));
|
||||
}
|
||||
};
|
||||
arr[30] = new CastLambda() {
|
||||
@Override
|
||||
public Alert cast(alert a) {
|
||||
return new BlockFinishedAlert(cast_to_block_finished_alert(a));
|
||||
}
|
||||
};
|
||||
arr[31] = new CastLambda() {
|
||||
@Override
|
||||
public Alert cast(alert a) {
|
||||
return new BlockDownloadingAlert(cast_to_block_downloading_alert(a));
|
||||
}
|
||||
};
|
||||
arr[32] = new CastLambda() {
|
||||
@Override
|
||||
public Alert cast(alert a) {
|
||||
return new UnwantedBlockAlert(cast_to_unwanted_block_alert(a));
|
||||
}
|
||||
};
|
||||
arr[33] = new CastLambda() {
|
||||
@Override
|
||||
public Alert cast(alert a) {
|
||||
return new StorageMovedAlert(cast_to_storage_moved_alert(a));
|
||||
}
|
||||
};
|
||||
arr[34] = new CastLambda() {
|
||||
@Override
|
||||
public Alert cast(alert a) {
|
||||
return new StorageMovedFailedAlert(cast_to_storage_moved_failed_alert(a));
|
||||
}
|
||||
};
|
||||
arr[35] = new CastLambda() {
|
||||
@Override
|
||||
public Alert cast(alert a) {
|
||||
return new TorrentDeletedAlert(cast_to_torrent_deleted_alert(a));
|
||||
}
|
||||
};
|
||||
arr[36] = new CastLambda() {
|
||||
@Override
|
||||
public Alert cast(alert a) {
|
||||
return new TorrentDeleteFailedAlert(cast_to_torrent_delete_failed_alert(a));
|
||||
}
|
||||
};
|
||||
arr[37] = new CastLambda() {
|
||||
@Override
|
||||
public Alert cast(alert a) {
|
||||
return new SaveResumeDataAlert(cast_to_save_resume_data_alert(a));
|
||||
}
|
||||
};
|
||||
arr[38] = new CastLambda() {
|
||||
@Override
|
||||
public Alert cast(alert a) {
|
||||
return new SaveResumeDataFailedAlert(cast_to_save_resume_data_failed_alert(a));
|
||||
}
|
||||
};
|
||||
arr[39] = new CastLambda() {
|
||||
@Override
|
||||
public Alert cast(alert a) {
|
||||
return new TorrentPausedAlert(cast_to_torrent_paused_alert(a));
|
||||
}
|
||||
};
|
||||
arr[40] = new CastLambda() {
|
||||
@Override
|
||||
public Alert cast(alert a) {
|
||||
return new TorrentResumedAlert(cast_to_torrent_resumed_alert(a));
|
||||
}
|
||||
};
|
||||
arr[41] = new CastLambda() {
|
||||
@Override
|
||||
public Alert cast(alert a) {
|
||||
return new TorrentCheckedAlert(cast_to_torrent_checked_alert(a));
|
||||
}
|
||||
};
|
||||
arr[42] = new CastLambda() {
|
||||
@Override
|
||||
public Alert cast(alert a) {
|
||||
return new UrlSeedAlert(cast_to_url_seed_alert(a));
|
||||
}
|
||||
};
|
||||
arr[43] = new CastLambda() {
|
||||
@Override
|
||||
public Alert cast(alert a) {
|
||||
return new FileErrorAlert(cast_to_file_error_alert(a));
|
||||
}
|
||||
};
|
||||
arr[44] = new CastLambda() {
|
||||
@Override
|
||||
public Alert cast(alert a) {
|
||||
return new MetadataFailedAlert(cast_to_metadata_failed_alert(a));
|
||||
}
|
||||
};
|
||||
arr[45] = new CastLambda() {
|
||||
@Override
|
||||
public Alert cast(alert a) {
|
||||
return new MetadataReceivedAlert(cast_to_metadata_received_alert(a));
|
||||
}
|
||||
};
|
||||
arr[46] = new CastLambda() {
|
||||
@Override
|
||||
public Alert cast(alert a) {
|
||||
return new UdpErrorAlert(cast_to_udp_error_alert(a));
|
||||
}
|
||||
};
|
||||
arr[47] = new CastLambda() {
|
||||
@Override
|
||||
public Alert cast(alert a) {
|
||||
return new ExternalIpAlert(cast_to_external_ip_alert(a));
|
||||
}
|
||||
};
|
||||
arr[48] = new CastLambda() {
|
||||
@Override
|
||||
public Alert cast(alert a) {
|
||||
return new ListenFailedAlert(cast_to_listen_failed_alert(a));
|
||||
}
|
||||
};
|
||||
arr[49] = new CastLambda() {
|
||||
@Override
|
||||
public Alert cast(alert a) {
|
||||
return new ListenSucceededAlert(cast_to_listen_succeeded_alert(a));
|
||||
}
|
||||
};
|
||||
arr[50] = new CastLambda() {
|
||||
@Override
|
||||
public Alert cast(alert a) {
|
||||
return new PortmapErrorAlert(cast_to_portmap_error_alert(a));
|
||||
}
|
||||
};
|
||||
arr[51] = new CastLambda() {
|
||||
@Override
|
||||
public Alert cast(alert a) {
|
||||
return new PortmapAlert(cast_to_portmap_alert(a));
|
||||
}
|
||||
};
|
||||
arr[52] = new CastLambda() {
|
||||
@Override
|
||||
public Alert cast(alert a) {
|
||||
return new PortmapLogAlert(cast_to_portmap_log_alert(a));
|
||||
}
|
||||
};
|
||||
arr[53] = new CastLambda() {
|
||||
@Override
|
||||
public Alert cast(alert a) {
|
||||
return new FastresumeRejectedAlert(cast_to_fastresume_rejected_alert(a));
|
||||
}
|
||||
};
|
||||
arr[54] = new CastLambda() {
|
||||
@Override
|
||||
public Alert cast(alert a) {
|
||||
return new PeerBlockedAlert(cast_to_peer_blocked_alert(a));
|
||||
}
|
||||
};
|
||||
arr[55] = new CastLambda() {
|
||||
@Override
|
||||
public Alert cast(alert a) {
|
||||
return new DhtAnnounceAlert(cast_to_dht_announce_alert(a));
|
||||
}
|
||||
};
|
||||
arr[56] = new CastLambda() {
|
||||
@Override
|
||||
public Alert cast(alert a) {
|
||||
return new DhtGetPeersAlert(cast_to_dht_get_peers_alert(a));
|
||||
}
|
||||
};
|
||||
arr[57] = new CastLambda() {
|
||||
@Override
|
||||
public Alert cast(alert a) {
|
||||
return new StatsAlert(cast_to_stats_alert(a));
|
||||
}
|
||||
};
|
||||
arr[58] = new CastLambda() {
|
||||
@Override
|
||||
public Alert cast(alert a) {
|
||||
return new CacheFlushedAlert(cast_to_cache_flushed_alert(a));
|
||||
}
|
||||
};
|
||||
arr[59] = new CastLambda() {
|
||||
@Override
|
||||
public Alert cast(alert a) {
|
||||
return handleUnknownAlert(a);
|
||||
}
|
||||
};
|
||||
arr[60] = new CastLambda() {
|
||||
@Override
|
||||
public Alert cast(alert a) {
|
||||
return new LsdPeerAlert(cast_to_lsd_peer_alert(a));
|
||||
}
|
||||
};
|
||||
arr[61] = new CastLambda() {
|
||||
@Override
|
||||
public Alert cast(alert a) {
|
||||
return new TrackeridAlert(cast_to_trackerid_alert(a));
|
||||
}
|
||||
};
|
||||
arr[62] = new CastLambda() {
|
||||
@Override
|
||||
public Alert cast(alert a) {
|
||||
return new DhtBootstrapAlert(cast_to_dht_bootstrap_alert(a));
|
||||
}
|
||||
};
|
||||
arr[63] = new CastLambda() {
|
||||
@Override
|
||||
public Alert cast(alert a) {
|
||||
return handleUnknownAlert(a);
|
||||
}
|
||||
};
|
||||
arr[64] = new CastLambda() {
|
||||
@Override
|
||||
public Alert cast(alert a) {
|
||||
return new TorrentErrorAlert(cast_to_torrent_error_alert(a));
|
||||
}
|
||||
};
|
||||
arr[65] = new CastLambda() {
|
||||
@Override
|
||||
public Alert cast(alert a) {
|
||||
return new TorrentNeedCertAlert(cast_to_torrent_need_cert_alert(a));
|
||||
}
|
||||
};
|
||||
arr[66] = new CastLambda() {
|
||||
@Override
|
||||
public Alert cast(alert a) {
|
||||
return new IncomingConnectionAlert(cast_to_incoming_connection_alert(a));
|
||||
}
|
||||
};
|
||||
arr[67] = new CastLambda() {
|
||||
@Override
|
||||
public Alert cast(alert a) {
|
||||
return new AddTorrentAlert(cast_to_add_torrent_alert(a));
|
||||
}
|
||||
};
|
||||
arr[68] = new CastLambda() {
|
||||
@Override
|
||||
public Alert cast(alert a) {
|
||||
return new StateUpdateAlert(cast_to_state_update_alert(a));
|
||||
}
|
||||
};
|
||||
arr[69] = new CastLambda() {
|
||||
@Override
|
||||
public Alert cast(alert a) {
|
||||
return handleUnknownAlert(a);
|
||||
}
|
||||
};
|
||||
arr[70] = new CastLambda() {
|
||||
@Override
|
||||
public Alert cast(alert a) {
|
||||
return new SessionStatsAlert(cast_to_session_stats_alert(a));
|
||||
}
|
||||
};
|
||||
arr[71] = new CastLambda() {
|
||||
@Override
|
||||
public Alert cast(alert a) {
|
||||
return handleUnknownAlert(a);
|
||||
}
|
||||
};
|
||||
arr[72] = new CastLambda() {
|
||||
@Override
|
||||
public Alert cast(alert a) {
|
||||
return handleUnknownAlert(a);
|
||||
}
|
||||
};
|
||||
arr[73] = new CastLambda() {
|
||||
@Override
|
||||
public Alert cast(alert a) {
|
||||
return new DhtErrorAlert(cast_to_dht_error_alert(a));
|
||||
}
|
||||
};
|
||||
arr[74] = new CastLambda() {
|
||||
@Override
|
||||
public Alert cast(alert a) {
|
||||
return new DhtImmutableItemAlert(cast_to_dht_immutable_item_alert(a));
|
||||
}
|
||||
};
|
||||
arr[75] = new CastLambda() {
|
||||
@Override
|
||||
public Alert cast(alert a) {
|
||||
return new DhtMutableItemAlert(cast_to_dht_mutable_item_alert(a));
|
||||
}
|
||||
};
|
||||
arr[76] = new CastLambda() {
|
||||
@Override
|
||||
public Alert cast(alert a) {
|
||||
return new DhtPutAlert(cast_to_dht_put_alert(a));
|
||||
}
|
||||
};
|
||||
arr[77] = new CastLambda() {
|
||||
@Override
|
||||
public Alert cast(alert a) {
|
||||
return new I2pAlert(cast_to_i2p_alert(a));
|
||||
}
|
||||
};
|
||||
arr[78] = new CastLambda() {
|
||||
@Override
|
||||
public Alert cast(alert a) {
|
||||
return new DhtOutgoingGetPeersAlert(cast_to_dht_outgoing_get_peers_alert(a));
|
||||
}
|
||||
};
|
||||
arr[79] = new CastLambda() {
|
||||
@Override
|
||||
public Alert cast(alert a) {
|
||||
return new LogAlert(cast_to_log_alert(a));
|
||||
}
|
||||
};
|
||||
arr[80] = new CastLambda() {
|
||||
@Override
|
||||
public Alert cast(alert a) {
|
||||
return new TorrentLogAlert(cast_to_torrent_log_alert(a));
|
||||
}
|
||||
};
|
||||
arr[81] = new CastLambda() {
|
||||
@Override
|
||||
public Alert cast(alert a) {
|
||||
return new PeerLogAlert(cast_to_peer_log_alert(a));
|
||||
}
|
||||
};
|
||||
arr[82] = new CastLambda() {
|
||||
@Override
|
||||
public Alert cast(alert a) {
|
||||
return new LsdErrorAlert(cast_to_lsd_error_alert(a));
|
||||
}
|
||||
};
|
||||
arr[83] = new CastLambda() {
|
||||
@Override
|
||||
public Alert cast(alert a) {
|
||||
return new DhtStatsAlert(cast_to_dht_stats_alert(a));
|
||||
}
|
||||
};
|
||||
arr[84] = new CastLambda() {
|
||||
@Override
|
||||
public Alert cast(alert a) {
|
||||
return new IncomingRequestAlert(cast_to_incoming_request_alert(a));
|
||||
}
|
||||
};
|
||||
arr[85] = new CastLambda() {
|
||||
@Override
|
||||
public Alert cast(alert a) {
|
||||
return new DhtLogAlert(cast_to_dht_log_alert(a));
|
||||
}
|
||||
};
|
||||
arr[86] = new CastLambda() {
|
||||
@Override
|
||||
public Alert cast(alert a) {
|
||||
return new DhtPktAlert(cast_to_dht_pkt_alert(a));
|
||||
}
|
||||
};
|
||||
arr[87] = new CastLambda() {
|
||||
@Override
|
||||
public Alert cast(alert a) {
|
||||
return new DhtGetPeersReplyAlert(cast_to_dht_get_peers_reply_alert(a));
|
||||
}
|
||||
};
|
||||
arr[88] = new CastLambda() {
|
||||
@Override
|
||||
public Alert cast(alert a) {
|
||||
return new DhtDirectResponseAlert(cast_to_dht_direct_response_alert(a));
|
||||
}
|
||||
};
|
||||
arr[89] = new CastLambda() {
|
||||
@Override
|
||||
public Alert cast(alert a) {
|
||||
return new PickerLogAlert(cast_to_picker_log_alert(a));
|
||||
}
|
||||
};
|
||||
arr[90] = new CastLambda() {
|
||||
@Override
|
||||
public Alert cast(alert a) {
|
||||
return new SessionErrorAlert(cast_to_session_error_alert(a));
|
||||
}
|
||||
};
|
||||
arr[91] = new CastLambda() {
|
||||
@Override
|
||||
public Alert cast(alert a) {
|
||||
return new DhtLiveNodesAlert(cast_to_dht_live_nodes_alert(a));
|
||||
}
|
||||
};
|
||||
arr[92] = new CastLambda() {
|
||||
@Override
|
||||
public Alert cast(alert a) {
|
||||
return new SessionStatsHeaderAlert(cast_to_session_stats_header_alert(a));
|
||||
}
|
||||
};
|
||||
arr[93] = new CastLambda() {
|
||||
@Override
|
||||
public Alert cast(alert a) {
|
||||
return new DhtSampleInfohashesAlert(cast_to_dht_sample_infohashes_alert(a));
|
||||
}
|
||||
};
|
||||
arr[94] = new CastLambda() {
|
||||
@Override
|
||||
public Alert cast(alert a) {
|
||||
return new BlockUploadedAlert(cast_to_block_uploaded_alert(a));
|
||||
}
|
||||
};
|
||||
arr[95] = new CastLambda() {
|
||||
@Override
|
||||
public Alert cast(alert a) {
|
||||
return new AlertsDroppedAlert(cast_to_alerts_dropped_alert(a));
|
||||
}
|
||||
};
|
||||
|
||||
return arr;
|
||||
}
|
||||
|
||||
private static Alert handleUnknownAlert(alert a) {
|
||||
throw new IllegalArgumentException("alert not known: " + a.type() + " - " + a.message());
|
||||
}
|
||||
|
||||
private interface CastLambda {
|
||||
Alert cast(alert a);
|
||||
}
|
||||
}
|
@ -0,0 +1,19 @@
|
||||
package com.frostwire.jlibtorrent.alerts;
|
||||
|
||||
import com.frostwire.jlibtorrent.swig.alerts_dropped_alert;
|
||||
|
||||
/**
|
||||
* This alert is posted to indicate to the client that some alerts were
|
||||
* dropped. Dropped meaning that the alert failed to be delivered to the
|
||||
* client. The most common cause of such failure is that the internal alert
|
||||
* queue grew too big (controlled by alert_queue_size).
|
||||
*
|
||||
* @author gubatron
|
||||
* @author aldenml
|
||||
*/
|
||||
public final class AlertsDroppedAlert extends AbstractAlert<alerts_dropped_alert> {
|
||||
|
||||
AlertsDroppedAlert(alerts_dropped_alert alert) {
|
||||
super(alert);
|
||||
}
|
||||
}
|
@ -0,0 +1,30 @@
|
||||
package com.frostwire.jlibtorrent.alerts;
|
||||
|
||||
import com.frostwire.jlibtorrent.swig.block_downloading_alert;
|
||||
|
||||
/**
|
||||
* This alert is generated when a block request is sent to a peer.
|
||||
*
|
||||
* @author gubatron
|
||||
* @author aldenml
|
||||
*/
|
||||
public final class BlockDownloadingAlert extends PeerAlert<block_downloading_alert> {
|
||||
|
||||
BlockDownloadingAlert(block_downloading_alert alert) {
|
||||
super(alert);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the block index
|
||||
*/
|
||||
public int blockIndex() {
|
||||
return alert.getBlock_index();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the piece index
|
||||
*/
|
||||
public int pieceIndex() {
|
||||
return alert.getPiece_index();
|
||||
}
|
||||
}
|
@ -0,0 +1,30 @@
|
||||
package com.frostwire.jlibtorrent.alerts;
|
||||
|
||||
import com.frostwire.jlibtorrent.swig.block_finished_alert;
|
||||
|
||||
/**
|
||||
* This alert is generated when a block request receives a response.
|
||||
*
|
||||
* @author gubatron
|
||||
* @author aldenml
|
||||
*/
|
||||
public final class BlockFinishedAlert extends PeerAlert<block_finished_alert> {
|
||||
|
||||
BlockFinishedAlert(block_finished_alert alert) {
|
||||
super(alert);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the block index
|
||||
*/
|
||||
public int blockIndex() {
|
||||
return alert.getBlock_index();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the piece index
|
||||
*/
|
||||
public int pieceIndex() {
|
||||
return alert.getPiece_index();
|
||||
}
|
||||
}
|
@ -0,0 +1,30 @@
|
||||
package com.frostwire.jlibtorrent.alerts;
|
||||
|
||||
import com.frostwire.jlibtorrent.swig.block_timeout_alert;
|
||||
|
||||
/**
|
||||
* This alert is generated when a block request times out.
|
||||
*
|
||||
* @author gubatron
|
||||
* @author aldenml
|
||||
*/
|
||||
public final class BlockTimeoutAlert extends PeerAlert<block_timeout_alert> {
|
||||
|
||||
BlockTimeoutAlert(block_timeout_alert alert) {
|
||||
super(alert);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the block index
|
||||
*/
|
||||
public int blockIndex() {
|
||||
return alert.getBlock_index();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the piece index
|
||||
*/
|
||||
public int pieceIndex() {
|
||||
return alert.getPiece_index();
|
||||
}
|
||||
}
|
@ -0,0 +1,33 @@
|
||||
package com.frostwire.jlibtorrent.alerts;
|
||||
|
||||
import com.frostwire.jlibtorrent.swig.block_uploaded_alert;
|
||||
|
||||
/**
|
||||
* This alert is posted when a block intended to be sent to a peer is placed in the
|
||||
* send buffer. Note that if the connection is closed before the send buffer is sent,
|
||||
* the alert may be posted without the bytes having been sent to the peer.
|
||||
* It belongs to the ``progress_notification`` category.
|
||||
*
|
||||
* @author gubatron
|
||||
* @author aldenml
|
||||
*/
|
||||
public final class BlockUploadedAlert extends PeerAlert<block_uploaded_alert> {
|
||||
|
||||
BlockUploadedAlert(block_uploaded_alert alert) {
|
||||
super(alert);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the block index
|
||||
*/
|
||||
public int blockIndex() {
|
||||
return alert.getBlock_index();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the piece index
|
||||
*/
|
||||
public int pieceIndex() {
|
||||
return alert.getPiece_index();
|
||||
}
|
||||
}
|
@ -0,0 +1,21 @@
|
||||
package com.frostwire.jlibtorrent.alerts;
|
||||
|
||||
import com.frostwire.jlibtorrent.swig.cache_flushed_alert;
|
||||
|
||||
/**
|
||||
* This alert is posted when the disk cache has been flushed for a specific
|
||||
* torrent as a result of a call to torrent_handle::flush_cache(). This
|
||||
* alert belongs to the ``storage_notification`` category, which must be
|
||||
* enabled to let this alert through. The alert is also posted when removing
|
||||
* a torrent from the session, once the outstanding cache flush is complete
|
||||
* and the torrent does no longer have any files open.
|
||||
*
|
||||
* @author gubatron
|
||||
* @author aldenml
|
||||
*/
|
||||
public final class CacheFlushedAlert extends TorrentAlert<cache_flushed_alert> {
|
||||
|
||||
CacheFlushedAlert(cache_flushed_alert alert) {
|
||||
super(alert);
|
||||
}
|
||||
}
|
@ -0,0 +1,305 @@
|
||||
package com.frostwire.jlibtorrent.alerts;
|
||||
|
||||
import com.frostwire.jlibtorrent.swig.close_reason_t;
|
||||
|
||||
/**
|
||||
* These are all the reasons to disconnect a peer
|
||||
* all reasons caused by the peer sending unexpected data.
|
||||
*
|
||||
* @author gubatron
|
||||
* @author aldenml
|
||||
*/
|
||||
public enum CloseReason {
|
||||
|
||||
/**
|
||||
* No reason specified. Generic close.
|
||||
*/
|
||||
NONE(close_reason_t.none.swigValue()),
|
||||
|
||||
/**
|
||||
* We're already connected to.
|
||||
*/
|
||||
DUPLICATE_PEER_ID(close_reason_t.duplicate_peer_id.swigValue()),
|
||||
|
||||
/**
|
||||
* This torrent has been removed, paused or stopped from this client.
|
||||
*/
|
||||
TORRENT_REMOVED(close_reason_t.torrent_removed.swigValue()),
|
||||
|
||||
/**
|
||||
* Client failed to allocate necessary memory for this peer connection.
|
||||
*/
|
||||
NO_MEMORY(close_reason_t.no_memory.swigValue()),
|
||||
|
||||
/**
|
||||
* The source port of this peer is blocked.
|
||||
*/
|
||||
PORT_BLOCKED(close_reason_t.port_blocked.swigValue()),
|
||||
|
||||
/**
|
||||
* The source IP has been blocked.
|
||||
*/
|
||||
BLOCKED(close_reason_t.blocked.swigValue()),
|
||||
|
||||
/**
|
||||
* Both ends of the connection are upload-only. Staying connected would
|
||||
* be redundant.
|
||||
*/
|
||||
UPLOAD_TO_UPLOAD(close_reason_t.upload_to_upload.swigValue()),
|
||||
|
||||
/**
|
||||
* Connection was closed because the other end is upload only and does
|
||||
* not have any pieces we're interested in.
|
||||
*/
|
||||
NOT_INTERESTED_UPLOAD_ONLY(close_reason_t.not_interested_upload_only.swigValue()),
|
||||
|
||||
/**
|
||||
* Peer connection timed out (generic timeout).
|
||||
*/
|
||||
TIMEOUT(close_reason_t.timeout.swigValue()),
|
||||
|
||||
/**
|
||||
* The peers have not been interested in each other for a very long time.
|
||||
* disconnect.
|
||||
*/
|
||||
TIMED_OUT_INTEREST(close_reason_t.timed_out_interest.swigValue()),
|
||||
|
||||
/**
|
||||
* The peer has not sent any message in a long time.
|
||||
*/
|
||||
TIMED_OUT_ACTIVITY(close_reason_t.timed_out_activity.swigValue()),
|
||||
|
||||
/**
|
||||
* The peer did not complete the handshake in too long.
|
||||
*/
|
||||
TIMED_OUT_HANDSHAKE(close_reason_t.timed_out_handshake.swigValue()),
|
||||
|
||||
/**
|
||||
* The peer sent an interested message, but did not send a request
|
||||
* after a very long time after being unchoked.
|
||||
*/
|
||||
TIMED_OUT_REQUEST(close_reason_t.timed_out_request.swigValue()),
|
||||
|
||||
/**
|
||||
* The encryption mode is blocked.
|
||||
*/
|
||||
PROTOCOL_BLOCKED(close_reason_t.protocol_blocked.swigValue()),
|
||||
|
||||
/**
|
||||
* The peer was disconnected in the hopes of finding a better peer
|
||||
* in the swarm.
|
||||
*/
|
||||
PEER_CHURN(close_reason_t.peer_churn.swigValue()),
|
||||
|
||||
/**
|
||||
* We have too many peers connected.
|
||||
*/
|
||||
TOO_MANY_CONNECTIONS(close_reason_t.too_many_connections.swigValue()),
|
||||
|
||||
/**
|
||||
* We have too many file-descriptors open.
|
||||
*/
|
||||
TOO_MANY_FILES(close_reason_t.too_many_files.swigValue()),
|
||||
|
||||
/**
|
||||
* The encryption handshake failed.
|
||||
*/
|
||||
ENCRYPTION_ERROR(close_reason_t.encryption_error.swigValue()),
|
||||
|
||||
/**
|
||||
* The info hash sent as part of the handshake was not what we expected.
|
||||
*/
|
||||
INVALID_INFO_HASH(close_reason_t.invalid_info_hash.swigValue()),
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
SELF_CONNECTION(close_reason_t.self_connection.swigValue()),
|
||||
|
||||
/**
|
||||
* The metadata received matched the info-hash, but failed to parse.
|
||||
* this is either someone finding a SHA1 collision, or the author of
|
||||
* the magnet link creating it from an invalid torrent.
|
||||
*/
|
||||
INVALID_METADATA(close_reason_t.invalid_metadata.swigValue()),
|
||||
|
||||
/**
|
||||
* The advertised metadata size.
|
||||
*/
|
||||
METADATA_TOO_BIG(close_reason_t.metadata_too_big.swigValue()),
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
MESSAGE_TOO_BIG(close_reason_t.message_too_big.swigValue()),
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
INVALID_MESSAGE_ID(close_reason_t.invalid_message_id.swigValue()),
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
INVALID_MESSAGE(close_reason_t.invalid_message.swigValue()),
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
INVALID_PIECE_MESSAGE(close_reason_t.invalid_piece_message.swigValue()),
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
INVALID_HAVE_MESSAGE(close_reason_t.invalid_have_message.swigValue()),
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
INVALID_BITFIELD_MESSAGE(close_reason_t.invalid_bitfield_message.swigValue()),
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
INVALID_CHOKE_MESSAGE(close_reason_t.invalid_choke_message.swigValue()),
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
INVALID_UNCHOKE_MESSAGE(close_reason_t.invalid_unchoke_message.swigValue()),
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
INVALID_INTERESTED_MESSAGE(close_reason_t.invalid_interested_message.swigValue()),
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
INVALID_NOT_INTERESTED_MESSAGE(close_reason_t.invalid_not_interested_message.swigValue()),
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
INVALID_REQUEST_MESSAGE(close_reason_t.invalid_request_message.swigValue()),
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
INVALID_REJECT_MESSAGE(close_reason_t.invalid_reject_message.swigValue()),
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
INVALID_ALLOW_FAST_MESSAGE(close_reason_t.invalid_allow_fast_message.swigValue()),
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
NVALID_EXTENDED_MESSAGE(close_reason_t.invalid_extended_message.swigValue()),
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
INVALID_CANCEL_MESSAGE(close_reason_t.invalid_cancel_message.swigValue()),
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
INVALID_DHT_PORT_MESSAGE(close_reason_t.invalid_dht_port_message.swigValue()),
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
INVALID_SUGGEST_MESSAGE(close_reason_t.invalid_suggest_message.swigValue()),
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
INVALID_HAVE_ALL_MESSAGE(close_reason_t.invalid_have_all_message.swigValue()),
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
INVALID_DONT_HAVE_MESSAGE(close_reason_t.invalid_dont_have_message.swigValue()),
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
INVALID_HAVE_NONE_MESSAGE(close_reason_t.invalid_have_none_message.swigValue()),
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
INVALID_PEX_MESSAGE(close_reason_t.invalid_pex_message.swigValue()),
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
INVALID_METADATA_REQUEST_MESSAGE(close_reason_t.invalid_metadata_request_message.swigValue()),
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
INVALID_METADATA_MESSAGE(close_reason_t.invalid_metadata_message.swigValue()),
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
INVALID_METADATA_OFFSET(close_reason_t.invalid_metadata_offset.swigValue()),
|
||||
|
||||
/**
|
||||
* The peer sent a request while being choked.
|
||||
*/
|
||||
REQUEST_WHEN_CHOKED(close_reason_t.request_when_choked.swigValue()),
|
||||
|
||||
/**
|
||||
* The peer sent corrupt data.
|
||||
*/
|
||||
CORRUPT_PIECES(close_reason_t.corrupt_pieces.swigValue()),
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
PEX_MESSAGE_TOO_BIG(close_reason_t.pex_message_too_big.swigValue()),
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
PEX_TOO_FREQUENT(close_reason_t.pex_too_frequent.swigValue()),
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
UNKNOWN(-1);
|
||||
|
||||
private final int swigValue;
|
||||
|
||||
CloseReason(int swigValue) {
|
||||
this.swigValue = swigValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converted method, it's public in order to be used in other
|
||||
* internal packages.
|
||||
*
|
||||
* @param swigValue the native value
|
||||
* @return the enum value
|
||||
*/
|
||||
public static CloseReason fromSwig(int swigValue) {
|
||||
CloseReason[] enumValues = CloseReason.class.getEnumConstants();
|
||||
for (CloseReason ev : enumValues) {
|
||||
if (ev.swig() == swigValue) {
|
||||
return ev;
|
||||
}
|
||||
}
|
||||
return UNKNOWN;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the native value
|
||||
*/
|
||||
public int swig() {
|
||||
return swigValue;
|
||||
}
|
||||
}
|
@ -0,0 +1,40 @@
|
||||
package com.frostwire.jlibtorrent.alerts;
|
||||
|
||||
import com.frostwire.jlibtorrent.Address;
|
||||
import com.frostwire.jlibtorrent.Sha1Hash;
|
||||
import com.frostwire.jlibtorrent.swig.dht_announce_alert;
|
||||
|
||||
/**
|
||||
* This alert is generated when a DHT node announces to an info-hash on our
|
||||
* DHT node. It belongs to the ``dht_notification`` category.
|
||||
*
|
||||
* @author gubatron
|
||||
* @author aldenml
|
||||
*/
|
||||
public final class DhtAnnounceAlert extends AbstractAlert<dht_announce_alert> {
|
||||
|
||||
DhtAnnounceAlert(dht_announce_alert alert) {
|
||||
super(alert);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the ip
|
||||
*/
|
||||
public Address ip() {
|
||||
return new Address(alert.get_ip());
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the port
|
||||
*/
|
||||
public int port() {
|
||||
return alert.getPort();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the info-hash
|
||||
*/
|
||||
public Sha1Hash infoHash() {
|
||||
return new Sha1Hash(alert.getInfo_hash());
|
||||
}
|
||||
}
|
@ -0,0 +1,16 @@
|
||||
package com.frostwire.jlibtorrent.alerts;
|
||||
|
||||
import com.frostwire.jlibtorrent.swig.dht_bootstrap_alert;
|
||||
|
||||
/**
|
||||
* This alert is posted when the initial DHT bootstrap is done.
|
||||
*
|
||||
* @author gubatron
|
||||
* @author aldenml
|
||||
*/
|
||||
public final class DhtBootstrapAlert extends AbstractAlert<dht_bootstrap_alert> {
|
||||
|
||||
DhtBootstrapAlert(dht_bootstrap_alert alert) {
|
||||
super(alert);
|
||||
}
|
||||
}
|
@ -0,0 +1,43 @@
|
||||
package com.frostwire.jlibtorrent.alerts;
|
||||
|
||||
import com.frostwire.jlibtorrent.BDecodeNode;
|
||||
import com.frostwire.jlibtorrent.Entry;
|
||||
import com.frostwire.jlibtorrent.UdpEndpoint;
|
||||
import com.frostwire.jlibtorrent.swig.dht_direct_response_alert;
|
||||
|
||||
/**
|
||||
* This is posted exactly once for every call to
|
||||
* {@link com.frostwire.jlibtorrent.SessionHandle#dhtDirectRequest(UdpEndpoint, Entry, long)}.
|
||||
* <p>
|
||||
* If the request failed, {@link #response()} will return a default constructed {@link BDecodeNode}.
|
||||
*
|
||||
* @author gubatron
|
||||
* @author aldenml
|
||||
*/
|
||||
public final class DhtDirectResponseAlert extends AbstractAlert<dht_direct_response_alert> {
|
||||
|
||||
DhtDirectResponseAlert(dht_direct_response_alert alert) {
|
||||
super(alert);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the user data
|
||||
*/
|
||||
public long userdata() {
|
||||
return alert.get_userdata();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the endpoint
|
||||
*/
|
||||
public UdpEndpoint endpoint() {
|
||||
return new UdpEndpoint(alert.get_endpoint());
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the response
|
||||
*/
|
||||
public BDecodeNode response() {
|
||||
return new BDecodeNode(alert.response());
|
||||
}
|
||||
}
|
@ -0,0 +1,37 @@
|
||||
package com.frostwire.jlibtorrent.alerts;
|
||||
|
||||
import com.frostwire.jlibtorrent.ErrorCode;
|
||||
import com.frostwire.jlibtorrent.Operation;
|
||||
import com.frostwire.jlibtorrent.swig.dht_error_alert;
|
||||
|
||||
/**
|
||||
* Posted when something fails in the DHT. This is not necessarily a fatal
|
||||
* error, but it could prevent proper operation.
|
||||
*
|
||||
* @author gubatron
|
||||
* @author aldenml
|
||||
*/
|
||||
public final class DhtErrorAlert extends AbstractAlert<dht_error_alert> {
|
||||
|
||||
DhtErrorAlert(dht_error_alert alert) {
|
||||
super(alert);
|
||||
}
|
||||
|
||||
/**
|
||||
* The error code.
|
||||
*
|
||||
* @return the error.
|
||||
*/
|
||||
public ErrorCode error() {
|
||||
return new ErrorCode(alert.getError());
|
||||
}
|
||||
|
||||
/**
|
||||
* the operation that failed
|
||||
*
|
||||
* @return the operation.
|
||||
*/
|
||||
public Operation operation() {
|
||||
return Operation.fromSwig(alert.getOp());
|
||||
}
|
||||
}
|
@ -0,0 +1,25 @@
|
||||
package com.frostwire.jlibtorrent.alerts;
|
||||
|
||||
import com.frostwire.jlibtorrent.Sha1Hash;
|
||||
import com.frostwire.jlibtorrent.swig.dht_get_peers_alert;
|
||||
|
||||
/**
|
||||
* This alert is generated when a DHT node sends a ``get_peers`` message to
|
||||
* our DHT node. It belongs to the ``dht_notification`` category.
|
||||
*
|
||||
* @author gubatron
|
||||
* @author aldenml
|
||||
*/
|
||||
public final class DhtGetPeersAlert extends AbstractAlert<dht_get_peers_alert> {
|
||||
|
||||
DhtGetPeersAlert(dht_get_peers_alert alert) {
|
||||
super(alert);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the hash
|
||||
*/
|
||||
public Sha1Hash infoHash() {
|
||||
return new Sha1Hash(alert.getInfo_hash());
|
||||
}
|
||||
}
|
@ -0,0 +1,54 @@
|
||||
package com.frostwire.jlibtorrent.alerts;
|
||||
|
||||
import com.frostwire.jlibtorrent.Address;
|
||||
import com.frostwire.jlibtorrent.Sha1Hash;
|
||||
import com.frostwire.jlibtorrent.TcpEndpoint;
|
||||
import com.frostwire.jlibtorrent.swig.dht_get_peers_reply_alert;
|
||||
import com.frostwire.jlibtorrent.swig.tcp_endpoint;
|
||||
import com.frostwire.jlibtorrent.swig.tcp_endpoint_vector;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
/**
|
||||
* @author gubatron
|
||||
* @author aldenml
|
||||
*/
|
||||
public final class DhtGetPeersReplyAlert extends AbstractAlert<dht_get_peers_reply_alert> {
|
||||
|
||||
DhtGetPeersReplyAlert(dht_get_peers_reply_alert alert) {
|
||||
super(alert);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the hash
|
||||
*/
|
||||
public Sha1Hash infoHash() {
|
||||
return new Sha1Hash(alert.getInfo_hash());
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the number of peers
|
||||
*/
|
||||
public int numPeers() {
|
||||
return alert.num_peers();
|
||||
}
|
||||
|
||||
/**
|
||||
* This method creates a new list each time is called.
|
||||
*
|
||||
* @return the list of peers
|
||||
*/
|
||||
public ArrayList<TcpEndpoint> peers() {
|
||||
tcp_endpoint_vector v = alert.peers();
|
||||
int size = (int) v.size();
|
||||
ArrayList<TcpEndpoint> peers = new ArrayList<>(size);
|
||||
|
||||
for (int i = 0; i < size; i++) {
|
||||
tcp_endpoint endp = v.get(i);
|
||||
String ip = new Address(endp.address()).toString(); // clone
|
||||
peers.add(new TcpEndpoint(ip, endp.port()));
|
||||
}
|
||||
|
||||
return peers;
|
||||
}
|
||||
}
|
@ -0,0 +1,39 @@
|
||||
package com.frostwire.jlibtorrent.alerts;
|
||||
|
||||
import com.frostwire.jlibtorrent.Entry;
|
||||
import com.frostwire.jlibtorrent.SessionHandle;
|
||||
import com.frostwire.jlibtorrent.Sha1Hash;
|
||||
import com.frostwire.jlibtorrent.swig.dht_immutable_item_alert;
|
||||
|
||||
/**
|
||||
* This alert is posted as a response to a call to {@link SessionHandle#dhtGetItem(Sha1Hash)},
|
||||
* looking up immutable items in the DHT.
|
||||
*
|
||||
* @author gubatron
|
||||
* @author aldenml
|
||||
*/
|
||||
public final class DhtImmutableItemAlert extends AbstractAlert<dht_immutable_item_alert> {
|
||||
|
||||
DhtImmutableItemAlert(dht_immutable_item_alert alert) {
|
||||
super(alert);
|
||||
}
|
||||
|
||||
/**
|
||||
* The target hash of the immutable item. This must
|
||||
* match the sha-1 hash of the bencoded form of the item.
|
||||
*
|
||||
* @return the target of the original query
|
||||
*/
|
||||
public Sha1Hash target() {
|
||||
return new Sha1Hash(alert.getTarget());
|
||||
}
|
||||
|
||||
/**
|
||||
* the data for this item
|
||||
*
|
||||
* @return the entry returned by the DHT
|
||||
*/
|
||||
public Entry item() {
|
||||
return new Entry(alert.getItem());
|
||||
}
|
||||
}
|
@ -0,0 +1,56 @@
|
||||
package com.frostwire.jlibtorrent.alerts;
|
||||
|
||||
import com.frostwire.jlibtorrent.Pair;
|
||||
import com.frostwire.jlibtorrent.Sha1Hash;
|
||||
import com.frostwire.jlibtorrent.UdpEndpoint;
|
||||
import com.frostwire.jlibtorrent.swig.dht_live_nodes_alert;
|
||||
import com.frostwire.jlibtorrent.swig.sha1_hash_udp_endpoint_pair;
|
||||
import com.frostwire.jlibtorrent.swig.sha1_hash_udp_endpoint_pair_vector;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author gubatron
|
||||
* @author aldenml
|
||||
*/
|
||||
public final class DhtLiveNodesAlert extends AbstractAlert<dht_live_nodes_alert> {
|
||||
|
||||
DhtLiveNodesAlert(dht_live_nodes_alert alert) {
|
||||
super(alert);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the DHT node id
|
||||
*/
|
||||
public Sha1Hash nodeId() {
|
||||
return new Sha1Hash(alert.getNode_id());
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the number of nodes
|
||||
*/
|
||||
public int numNodes() {
|
||||
return alert.num_nodes();
|
||||
}
|
||||
|
||||
/**
|
||||
* This method creates a new list each time is called.
|
||||
*
|
||||
* @return the list of node, endpoint pairs
|
||||
*/
|
||||
public List<Pair<Sha1Hash, UdpEndpoint>> nodes() {
|
||||
sha1_hash_udp_endpoint_pair_vector v = alert.nodes();
|
||||
int size = (int) v.size();
|
||||
ArrayList<Pair<Sha1Hash, UdpEndpoint>> nodes = new ArrayList<>(size);
|
||||
|
||||
for (int i = 0; i < size; i++) {
|
||||
sha1_hash_udp_endpoint_pair p = v.get(i);
|
||||
Sha1Hash h = new Sha1Hash(p.getFirst()).clone();
|
||||
UdpEndpoint endp = new UdpEndpoint(p.getSecond()).clone();
|
||||
nodes.add(new Pair<>(h, endp));
|
||||
}
|
||||
|
||||
return nodes;
|
||||
}
|
||||
}
|
@ -0,0 +1,72 @@
|
||||
package com.frostwire.jlibtorrent.alerts;
|
||||
|
||||
import com.frostwire.jlibtorrent.swig.dht_log_alert;
|
||||
|
||||
/**
|
||||
* @author gubatron
|
||||
* @author aldenml
|
||||
*/
|
||||
public final class DhtLogAlert extends AbstractAlert<dht_log_alert> {
|
||||
|
||||
DhtLogAlert(dht_log_alert alert) {
|
||||
super(alert);
|
||||
}
|
||||
|
||||
/**
|
||||
* The log message.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public String logMessage() {
|
||||
return alert.log_message();
|
||||
}
|
||||
|
||||
/**
|
||||
* The module, or part, of the DHT that produced this log message.
|
||||
*
|
||||
* @return the dht module
|
||||
*/
|
||||
public DhtModule module() {
|
||||
return DhtModule.fromSwig(alert.getModule().swigValue());
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public enum DhtModule {
|
||||
|
||||
TRACKER(dht_log_alert.dht_module_t.tracker.swigValue()),
|
||||
NODE(dht_log_alert.dht_module_t.node.swigValue()),
|
||||
ROUTING_TABLE(dht_log_alert.dht_module_t.routing_table.swigValue()),
|
||||
RPC_MANAGER(dht_log_alert.dht_module_t.rpc_manager.swigValue()),
|
||||
TRAVERSAL(dht_log_alert.dht_module_t.traversal.swigValue()),
|
||||
UNKNOWN(-1);
|
||||
|
||||
private final int swigValue;
|
||||
|
||||
DhtModule(int swigValue) {
|
||||
this.swigValue = swigValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param swigValue the native value
|
||||
* @return the java enum
|
||||
*/
|
||||
public static DhtModule fromSwig(int swigValue) {
|
||||
DhtModule[] enumValues = DhtModule.class.getEnumConstants();
|
||||
for (DhtModule ev : enumValues) {
|
||||
if (ev.swig() == swigValue) {
|
||||
return ev;
|
||||
}
|
||||
}
|
||||
return UNKNOWN;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the native value
|
||||
*/
|
||||
public int swig() {
|
||||
return swigValue;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,69 @@
|
||||
package com.frostwire.jlibtorrent.alerts;
|
||||
|
||||
import com.frostwire.jlibtorrent.Entry;
|
||||
import com.frostwire.jlibtorrent.Vectors;
|
||||
import com.frostwire.jlibtorrent.swig.dht_mutable_item_alert;
|
||||
|
||||
/**
|
||||
* This alert is posted as a response to a call to session::get_item(),
|
||||
* specifically the overload for looking up mutable items in the DHT.
|
||||
*
|
||||
* @author gubatron
|
||||
* @author aldenml
|
||||
*/
|
||||
public final class DhtMutableItemAlert extends AbstractAlert<dht_mutable_item_alert> {
|
||||
|
||||
DhtMutableItemAlert(dht_mutable_item_alert alert) {
|
||||
super(alert);
|
||||
}
|
||||
|
||||
/**
|
||||
* The public key that was looked up.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public byte[] key() {
|
||||
return Vectors.byte_vector2bytes(alert.get_key());
|
||||
}
|
||||
|
||||
/**
|
||||
* The signature of the data. This is not the signature of the
|
||||
* plain encoded form of the item, but it includes the sequence number
|
||||
* and possibly the hash as well. See the dht_store document for more
|
||||
* information. This is primarily useful for echoing back in a store
|
||||
* request.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public byte[] signature() {
|
||||
return Vectors.byte_vector2bytes(alert.get_signature());
|
||||
}
|
||||
|
||||
/**
|
||||
* The sequence number of this item.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public long seq() {
|
||||
return alert.get_seq();
|
||||
}
|
||||
|
||||
/**
|
||||
* The salt, if any, used to lookup and store this item. If no
|
||||
* salt was used, this is an empty string.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public byte[] salt() {
|
||||
return Vectors.byte_vector2bytes(alert.get_salt());
|
||||
}
|
||||
|
||||
/**
|
||||
* The data for this item.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public Entry item() {
|
||||
return new Entry(alert.getItem());
|
||||
}
|
||||
}
|
@ -0,0 +1,47 @@
|
||||
package com.frostwire.jlibtorrent.alerts;
|
||||
|
||||
import com.frostwire.jlibtorrent.Sha1Hash;
|
||||
import com.frostwire.jlibtorrent.UdpEndpoint;
|
||||
import com.frostwire.jlibtorrent.swig.dht_outgoing_get_peers_alert;
|
||||
|
||||
/**
|
||||
* This alert is generated when we send a get_peers request.
|
||||
* It belongs to the {@code dht_notification} category.
|
||||
*
|
||||
* @author gubatron
|
||||
* @author aldenml
|
||||
*/
|
||||
public final class DhtOutgoingGetPeersAlert extends AbstractAlert<dht_outgoing_get_peers_alert> {
|
||||
|
||||
DhtOutgoingGetPeersAlert(dht_outgoing_get_peers_alert alert) {
|
||||
super(alert);
|
||||
}
|
||||
|
||||
/**
|
||||
* the info_hash of the torrent we're looking for peers for.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public Sha1Hash infoHash() {
|
||||
return new Sha1Hash(alert.getInfo_hash());
|
||||
}
|
||||
|
||||
/**
|
||||
* if this was an obfuscated lookup, this is the info-hash target
|
||||
* actually sent to the node.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public Sha1Hash obfuscatedInfoHash() {
|
||||
return new Sha1Hash(alert.getObfuscated_info_hash());
|
||||
}
|
||||
|
||||
/**
|
||||
* The endpoint we're sending this query to.
|
||||
*
|
||||
* @return the endpoint
|
||||
*/
|
||||
public UdpEndpoint endpoint() {
|
||||
return new UdpEndpoint(alert.get_endpoint());
|
||||
}
|
||||
}
|
@ -0,0 +1,99 @@
|
||||
package com.frostwire.jlibtorrent.alerts;
|
||||
|
||||
import com.frostwire.jlibtorrent.UdpEndpoint;
|
||||
import com.frostwire.jlibtorrent.Vectors;
|
||||
import com.frostwire.jlibtorrent.swig.dht_pkt_alert;
|
||||
|
||||
/**
|
||||
* This alert is posted every time a DHT message is sent or received. It is
|
||||
* only posted if the ``alert::dht_log_notification`` alert category is
|
||||
* enabled. It contains a verbatim copy of the message.
|
||||
*
|
||||
* @author gubatron
|
||||
* @author aldenml
|
||||
*/
|
||||
public final class DhtPktAlert extends AbstractAlert<dht_pkt_alert> {
|
||||
|
||||
DhtPktAlert(dht_pkt_alert alert) {
|
||||
super(alert);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a copy of the packet buffer and size of the packet,
|
||||
* respectively. This buffer is only valid for as long as the alert itself
|
||||
* is valid, which is owned by libtorrent and reclaimed whenever
|
||||
* pop_alerts() is called on the session.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public byte[] pktBuf() {
|
||||
return Vectors.byte_span2bytes(alert.pkt_buf());
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether this is an incoming or outgoing packet.
|
||||
*
|
||||
* @return the direction
|
||||
*/
|
||||
public Direction direction() {
|
||||
return Direction.fromSwig(alert.getDirection().swigValue());
|
||||
}
|
||||
|
||||
/**
|
||||
* The DHT node we received this packet from, or sent this packet to
|
||||
* (depending on {@link #direction()}).
|
||||
*
|
||||
* @return the node endpoint
|
||||
*/
|
||||
public UdpEndpoint node() {
|
||||
return new UdpEndpoint(alert.get_node());
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public enum Direction {
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
INCOMING(dht_pkt_alert.direction_t.incoming.swigValue()),
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
OUTGOING(dht_pkt_alert.direction_t.outgoing.swigValue()),
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
UNKNOWN(-1);
|
||||
|
||||
private final int swigValue;
|
||||
|
||||
Direction(int swigValue) {
|
||||
this.swigValue = swigValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param swigValue the native value
|
||||
* @return the java enum
|
||||
*/
|
||||
public static Direction fromSwig(int swigValue) {
|
||||
Direction[] enumValues = Direction.class.getEnumConstants();
|
||||
for (Direction ev : enumValues) {
|
||||
if (ev.swig() == swigValue) {
|
||||
return ev;
|
||||
}
|
||||
}
|
||||
return UNKNOWN;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the native value
|
||||
*/
|
||||
public int swig() {
|
||||
return swigValue;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,69 @@
|
||||
package com.frostwire.jlibtorrent.alerts;
|
||||
|
||||
import com.frostwire.jlibtorrent.Sha1Hash;
|
||||
import com.frostwire.jlibtorrent.Vectors;
|
||||
import com.frostwire.jlibtorrent.swig.dht_put_alert;
|
||||
|
||||
/**
|
||||
* This is posted when a DHT put operation completes. This is useful if the
|
||||
* client is waiting for a put to complete before shutting down for instance.
|
||||
*
|
||||
* @author gubatron
|
||||
* @author aldenml
|
||||
*/
|
||||
public final class DhtPutAlert extends AbstractAlert<dht_put_alert> {
|
||||
|
||||
DhtPutAlert(dht_put_alert alert) {
|
||||
super(alert);
|
||||
}
|
||||
|
||||
/**
|
||||
* The target hash the item was stored under if this was an *immutable*
|
||||
* item.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public Sha1Hash target() {
|
||||
return new Sha1Hash(alert.getTarget());
|
||||
}
|
||||
|
||||
/**
|
||||
* if a mutable item was stored, these are the public key, signature,
|
||||
* salt and sequence number the item was stored under.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public byte[] publicKey() {
|
||||
return Vectors.byte_vector2bytes(alert.get_public_key());
|
||||
}
|
||||
|
||||
/**
|
||||
* if a mutable item was stored, these are the public key, signature,
|
||||
* salt and sequence number the item was stored under.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public byte[] signature() {
|
||||
return Vectors.byte_vector2bytes(alert.get_signature());
|
||||
}
|
||||
|
||||
/**
|
||||
* if a mutable item was stored, these are the public key, signature,
|
||||
* salt and sequence number the item was stored under.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public byte[] salt() {
|
||||
return Vectors.byte_vector2bytes(alert.get_salt());
|
||||
}
|
||||
|
||||
/**
|
||||
* if a mutable item was stored, these are the public key, signature,
|
||||
* salt and sequence number the item was stored under.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public long seq() {
|
||||
return alert.get_seq();
|
||||
}
|
||||
}
|
@ -0,0 +1,26 @@
|
||||
package com.frostwire.jlibtorrent.alerts;
|
||||
|
||||
import com.frostwire.jlibtorrent.swig.dht_reply_alert;
|
||||
|
||||
/**
|
||||
* This alert is generated each time the DHT receives peers from a node. ``num_peers``
|
||||
* is the number of peers we received in this packet. Typically these packets are
|
||||
* received from multiple DHT nodes, and so the alerts are typically generated
|
||||
* a few at a time.
|
||||
*
|
||||
* @author gubatron
|
||||
* @author aldenml
|
||||
*/
|
||||
public final class DhtReplyAlert extends TrackerAlert<dht_reply_alert> {
|
||||
|
||||
DhtReplyAlert(dht_reply_alert alert) {
|
||||
super(alert);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return
|
||||
*/
|
||||
public int numPeers() {
|
||||
return alert.getNum_peers();
|
||||
}
|
||||
}
|
@ -0,0 +1,98 @@
|
||||
package com.frostwire.jlibtorrent.alerts;
|
||||
|
||||
import com.frostwire.jlibtorrent.Pair;
|
||||
import com.frostwire.jlibtorrent.Sha1Hash;
|
||||
import com.frostwire.jlibtorrent.UdpEndpoint;
|
||||
import com.frostwire.jlibtorrent.swig.dht_sample_infohashes_alert;
|
||||
import com.frostwire.jlibtorrent.swig.sha1_hash;
|
||||
import com.frostwire.jlibtorrent.swig.sha1_hash_udp_endpoint_pair;
|
||||
import com.frostwire.jlibtorrent.swig.sha1_hash_udp_endpoint_pair_vector;
|
||||
import com.frostwire.jlibtorrent.swig.sha1_hash_vector;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author gubatron
|
||||
* @author aldenml
|
||||
*/
|
||||
public final class DhtSampleInfohashesAlert extends AbstractAlert<dht_sample_infohashes_alert> {
|
||||
|
||||
DhtSampleInfohashesAlert(dht_sample_infohashes_alert alert) {
|
||||
super(alert);
|
||||
}
|
||||
|
||||
public UdpEndpoint endpoint() {
|
||||
return new UdpEndpoint(alert.get_endpoint());
|
||||
}
|
||||
|
||||
public long interval() {
|
||||
return alert.get_interval();
|
||||
}
|
||||
|
||||
/**
|
||||
* This value indicates how many infohash keys are currently
|
||||
* in the node's storage.
|
||||
* <p>
|
||||
* If the value is larger than the number of returned samples
|
||||
* it indicates that the indexer may obtain additional samples
|
||||
* after waiting out the interval.
|
||||
*
|
||||
* @return how many infohash keys are currently in the node's
|
||||
* storage
|
||||
*/
|
||||
public int numInfohashes() {
|
||||
return alert.getNum_infohashes();
|
||||
}
|
||||
|
||||
public int numSamples() {
|
||||
return alert.num_samples();
|
||||
}
|
||||
|
||||
public List<Sha1Hash> samples() {
|
||||
sha1_hash_vector v = alert.samples();
|
||||
int size = (int) v.size();
|
||||
ArrayList<Sha1Hash> samples = new ArrayList<>(size);
|
||||
|
||||
for (int i = 0; i < size; i++) {
|
||||
sha1_hash ih = v.get(i);
|
||||
Sha1Hash h = new Sha1Hash(ih).clone();
|
||||
samples.add(h);
|
||||
}
|
||||
|
||||
return samples;
|
||||
}
|
||||
|
||||
/**
|
||||
* The total number of nodes returned by {@link #nodes()}.
|
||||
*
|
||||
* @return the number of nodes
|
||||
*/
|
||||
public int numNodes() {
|
||||
return alert.num_nodes();
|
||||
}
|
||||
|
||||
/**
|
||||
* This is the set of more DHT nodes returned by the request.
|
||||
* <p>
|
||||
* The information is included so that indexing nodes can perform
|
||||
* a keyspace traversal with a single RPC per node by adjusting
|
||||
* the target value for each RPC.
|
||||
*
|
||||
* @return the set of more DHT nodes returned by the request
|
||||
*/
|
||||
public List<Pair<Sha1Hash, UdpEndpoint>> nodes() {
|
||||
sha1_hash_udp_endpoint_pair_vector v = alert.nodes();
|
||||
int size = (int) v.size();
|
||||
ArrayList<Pair<Sha1Hash, UdpEndpoint>> nodes = new ArrayList<>(size);
|
||||
|
||||
for (int i = 0; i < size; i++) {
|
||||
sha1_hash_udp_endpoint_pair p = v.get(i);
|
||||
Sha1Hash h = new Sha1Hash(p.getFirst()).clone();
|
||||
UdpEndpoint endp = new UdpEndpoint(p.getSecond()).clone();
|
||||
nodes.add(new Pair<>(h, endp));
|
||||
}
|
||||
|
||||
return nodes;
|
||||
}
|
||||
}
|
@ -0,0 +1,59 @@
|
||||
package com.frostwire.jlibtorrent.alerts;
|
||||
|
||||
import com.frostwire.jlibtorrent.DhtLookup;
|
||||
import com.frostwire.jlibtorrent.DhtRoutingBucket;
|
||||
import com.frostwire.jlibtorrent.swig.dht_lookup_vector;
|
||||
import com.frostwire.jlibtorrent.swig.dht_routing_bucket_vector;
|
||||
import com.frostwire.jlibtorrent.swig.dht_stats_alert;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
/**
|
||||
* Contains current DHT state. Posted in response to
|
||||
* {@link com.frostwire.jlibtorrent.SessionHandle#postDhtStats()}.
|
||||
*
|
||||
* @author gubatron
|
||||
* @author aldenml
|
||||
*/
|
||||
public final class DhtStatsAlert extends AbstractAlert<dht_stats_alert> {
|
||||
|
||||
DhtStatsAlert(dht_stats_alert alert) {
|
||||
super(alert);
|
||||
}
|
||||
|
||||
/**
|
||||
* An array (list) with the currently running DHT lookups.
|
||||
*
|
||||
* @return the list of active requests
|
||||
*/
|
||||
public ArrayList<DhtLookup> activeRequests() {
|
||||
dht_lookup_vector v = alert.getActive_requests();
|
||||
int size = (int) v.size();
|
||||
|
||||
ArrayList<DhtLookup> l = new ArrayList<>(size);
|
||||
|
||||
for (int i = 0; i < size; i++) {
|
||||
l.add(new DhtLookup(v.get(i)));
|
||||
}
|
||||
|
||||
return l;
|
||||
}
|
||||
|
||||
/**
|
||||
* Contains information about every bucket in the DHT routing
|
||||
* table.
|
||||
*
|
||||
* @return the routing table
|
||||
*/
|
||||
public ArrayList<DhtRoutingBucket> routingTable() {
|
||||
dht_routing_bucket_vector v = alert.getRouting_table();
|
||||
int size = (int) v.size();
|
||||
ArrayList<DhtRoutingBucket> l = new ArrayList<>(size);
|
||||
|
||||
for (int i = 0; i < size; i++) {
|
||||
l.add(new DhtRoutingBucket(v.get(i)));
|
||||
}
|
||||
|
||||
return l;
|
||||
}
|
||||
}
|
@ -0,0 +1,29 @@
|
||||
package com.frostwire.jlibtorrent.alerts;
|
||||
|
||||
import com.frostwire.jlibtorrent.Address;
|
||||
import com.frostwire.jlibtorrent.swig.external_ip_alert;
|
||||
|
||||
/**
|
||||
* Whenever libtorrent learns about the machines external IP, this alert is
|
||||
* generated. The external IP address can be acquired from the tracker (if it
|
||||
* supports that) or from peers that supports the extension protocol.
|
||||
* The address can be accessed through the {@link #externalAddress()} member.
|
||||
*
|
||||
* @author gubatron
|
||||
* @author aldenml
|
||||
*/
|
||||
public final class ExternalIpAlert extends AbstractAlert<external_ip_alert> {
|
||||
|
||||
ExternalIpAlert(external_ip_alert alert) {
|
||||
super(alert);
|
||||
}
|
||||
|
||||
/**
|
||||
* The IP address that is believed to be our external IP.
|
||||
*
|
||||
* @return the external address
|
||||
*/
|
||||
public Address externalAddress() {
|
||||
return new Address(alert.get_external_address());
|
||||
}
|
||||
}
|
@ -0,0 +1,44 @@
|
||||
package com.frostwire.jlibtorrent.alerts;
|
||||
|
||||
import com.frostwire.jlibtorrent.ErrorCode;
|
||||
import com.frostwire.jlibtorrent.Operation;
|
||||
import com.frostwire.jlibtorrent.swig.fastresume_rejected_alert;
|
||||
|
||||
/**
|
||||
* This alert is generated when a fastresume file has been passed
|
||||
* to {@code addTorrent} but the files on disk did not match the
|
||||
* fastresume file. The {@link #error()} explains the reason why
|
||||
* the resume file was rejected.
|
||||
*
|
||||
* @author gubatron
|
||||
* @author aldenml
|
||||
*/
|
||||
public final class FastresumeRejectedAlert extends TorrentAlert<fastresume_rejected_alert> {
|
||||
|
||||
FastresumeRejectedAlert(fastresume_rejected_alert alert) {
|
||||
super(alert);
|
||||
}
|
||||
|
||||
public ErrorCode error() {
|
||||
return new ErrorCode(alert.getError());
|
||||
}
|
||||
|
||||
/**
|
||||
* If the error happened to a specific file, this returns the path to it.
|
||||
*
|
||||
* @return the file path.
|
||||
*/
|
||||
public String filePath() {
|
||||
return alert.file_path();
|
||||
}
|
||||
|
||||
/**
|
||||
* If the error happened in a disk operation, a string with
|
||||
* the name of that operation.
|
||||
*
|
||||
* @return the operation.
|
||||
*/
|
||||
public Operation operation() {
|
||||
return Operation.fromSwig(alert.getOp());
|
||||
}
|
||||
}
|
@ -0,0 +1,26 @@
|
||||
package com.frostwire.jlibtorrent.alerts;
|
||||
|
||||
import com.frostwire.jlibtorrent.swig.file_completed_alert;
|
||||
|
||||
/**
|
||||
* This is posted whenever an individual file completes its download. i.e.
|
||||
* All pieces overlapping this file have passed their hash check.
|
||||
*
|
||||
* @author gubatron
|
||||
* @author aldenml
|
||||
*/
|
||||
public final class FileCompletedAlert extends TorrentAlert<file_completed_alert> {
|
||||
|
||||
FileCompletedAlert(file_completed_alert alert) {
|
||||
super(alert);
|
||||
}
|
||||
|
||||
/**
|
||||
* Refers to the index of the file that completed.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public int index() {
|
||||
return alert.getIndex();
|
||||
}
|
||||
}
|
@ -0,0 +1,46 @@
|
||||
package com.frostwire.jlibtorrent.alerts;
|
||||
|
||||
import com.frostwire.jlibtorrent.ErrorCode;
|
||||
import com.frostwire.jlibtorrent.Operation;
|
||||
import com.frostwire.jlibtorrent.swig.file_error_alert;
|
||||
|
||||
/**
|
||||
* If the storage fails to read or write files that it needs access
|
||||
* to, this alert is generated and the torrent is paused.
|
||||
*
|
||||
* @author gubatron
|
||||
* @author aldenml
|
||||
*/
|
||||
public final class FileErrorAlert extends TorrentAlert<file_error_alert> {
|
||||
|
||||
FileErrorAlert(file_error_alert alert) {
|
||||
super(alert);
|
||||
}
|
||||
|
||||
/**
|
||||
* The error code describing the error.
|
||||
*
|
||||
* @return the error.
|
||||
*/
|
||||
public ErrorCode error() {
|
||||
return new ErrorCode(alert.getError());
|
||||
}
|
||||
|
||||
/**
|
||||
* The file that experienced the error.
|
||||
*
|
||||
* @return te filename.
|
||||
*/
|
||||
public String filename() {
|
||||
return alert.filename();
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates which underlying operation caused the error.
|
||||
*
|
||||
* @return the operation.
|
||||
*/
|
||||
public Operation operation() {
|
||||
return Operation.fromSwig(alert.getOp());
|
||||
}
|
||||
}
|
@ -0,0 +1,36 @@
|
||||
package com.frostwire.jlibtorrent.alerts;
|
||||
|
||||
import com.frostwire.jlibtorrent.ErrorCode;
|
||||
import com.frostwire.jlibtorrent.swig.file_rename_failed_alert;
|
||||
|
||||
/**
|
||||
* This is posted as a response to a torrent_handle::rename_file() call, if the rename
|
||||
* operation failed.
|
||||
*
|
||||
* @author gubatron
|
||||
* @author aldenml
|
||||
*/
|
||||
public final class FileRenameFailedAlert extends TorrentAlert<file_rename_failed_alert> {
|
||||
|
||||
public FileRenameFailedAlert(file_rename_failed_alert alert) {
|
||||
super(alert);
|
||||
}
|
||||
|
||||
/**
|
||||
* refers to the index of the file that was supposed to be renamed.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public int getIndex() {
|
||||
return alert.getIndex();
|
||||
}
|
||||
|
||||
/**
|
||||
* is the error code returned from the filesystem.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public ErrorCode getError() {
|
||||
return new ErrorCode(alert.getError());
|
||||
}
|
||||
}
|
@ -0,0 +1,30 @@
|
||||
package com.frostwire.jlibtorrent.alerts;
|
||||
|
||||
import com.frostwire.jlibtorrent.swig.file_renamed_alert;
|
||||
|
||||
/**
|
||||
* This is posted as a response to a {@link com.frostwire.jlibtorrent.TorrentHandle#renameFile(int, String)}, if the rename
|
||||
* operation succeeds.
|
||||
*
|
||||
* @author gubatron
|
||||
* @author aldenml
|
||||
*/
|
||||
public final class FileRenamedAlert extends TorrentAlert<file_renamed_alert> {
|
||||
|
||||
public FileRenamedAlert(file_renamed_alert alert) {
|
||||
super(alert);
|
||||
}
|
||||
|
||||
public String newName() {
|
||||
return alert.new_name();
|
||||
}
|
||||
|
||||
/**
|
||||
* Refers to the index of the file that was renamed.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public int index() {
|
||||
return alert.getIndex();
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user