@ -69,11 +69,9 @@ import de.timroes.axmlrpc.XMLRPCClient.UnauthorizdException;
import de.timroes.axmlrpc.XMLRPCException ;
import de.timroes.axmlrpc.XMLRPCException ;
/ * *
/ * *
* An adapter that allows for easy access to rTorrent torrent data . Communication
* An adapter that allows for easy access to rTorrent torrent data . Communication is handled via the XML - RPC protocol as
* is handled via the XML - RPC protocol as implemented by the aXMLRPC library .
* implemented by the aXMLRPC library .
*
* @author erickok
* @author erickok
*
* /
* /
public class RtorrentAdapter implements IDaemonAdapter {
public class RtorrentAdapter implements IDaemonAdapter {
@ -96,18 +94,63 @@ public class RtorrentAdapter implements IDaemonAdapter {
switch ( task . getMethod ( ) ) {
switch ( task . getMethod ( ) ) {
case Retrieve :
case Retrieve :
Object result = makeRtorrentCall ( "d.multicall" , new String [ ] { "main" , "d.get_hash=" , "d.get_name=" , "d.get_state=" , "d.get_down_rate=" , "d.get_up_rate=" , "d.get_peers_connected=" , "d.get_peers_not_connected=" , "d.get_peers_accounted=" , "d.get_bytes_done=" , "d.get_up_total=" , "d.get_size_bytes=" , "d.get_creation_date=" , "d.get_left_bytes=" , "d.get_complete=" , "d.is_active=" , "d.is_hash_checking=" , "d.get_base_path=" , "d.get_base_filename=" , "d.get_message=" , "d.get_custom=addtime" , "d.get_custom=seedingtime" , "d.get_custom1=" } ) ;
// @formatter:off
Object result = makeRtorrentCall ( "d.multicall" ,
new String [ ] { "main" ,
"d.get_hash=" ,
"d.get_name=" ,
"d.get_state=" ,
"d.get_down_rate=" ,
"d.get_up_rate=" ,
"d.get_peers_connected=" ,
"d.get_peers_not_connected=" ,
"d.get_peers_accounted=" ,
"d.get_bytes_done=" ,
"d.get_up_total=" ,
"d.get_size_bytes=" ,
"d.get_creation_date=" ,
"d.get_left_bytes=" ,
"d.get_complete=" ,
"d.is_active=" ,
"d.is_hash_checking=" ,
"d.get_base_path=" ,
"d.get_base_filename=" ,
"d.get_message=" ,
"d.get_custom=addtime" ,
"d.get_custom=seedingtime" ,
"d.get_custom1=" ,
"d.get_peers_complete=" ,
"d.get_peers_accounted=" } ) ;
// @formatter:on
return new RetrieveTaskSuccessResult ( ( RetrieveTask ) task , onTorrentsRetrieved ( result ) , lastKnownLabels ) ;
return new RetrieveTaskSuccessResult ( ( RetrieveTask ) task , onTorrentsRetrieved ( result ) , lastKnownLabels ) ;
case GetTorrentDetails :
case GetTorrentDetails :
Object dresult = makeRtorrentCall ( "t.multicall" , new String [ ] { task . getTargetTorrent ( ) . getUniqueID ( ) , "" , "t.get_url=" } ) ;
// @formatter:off
return new GetTorrentDetailsTaskSuccessResult ( ( GetTorrentDetailsTask ) task , onTorrentDetailsRetrieved ( dresult ) ) ;
Object dresult = makeRtorrentCall ( "t.multicall" , new String [ ] {
task . getTargetTorrent ( ) . getUniqueID ( ) ,
"" ,
"t.get_url=" } ) ;
// @formatter:on
return new GetTorrentDetailsTaskSuccessResult ( ( GetTorrentDetailsTask ) task ,
onTorrentDetailsRetrieved ( dresult ) ) ;
case GetFileList :
case GetFileList :
Object fresult = makeRtorrentCall ( "f.multicall" , new String [ ] { task . getTargetTorrent ( ) . getUniqueID ( ) , "" , "f.get_path=" , "f.get_size_bytes=" , "f.get_priority=" , "f.get_completed_chunks=" , "f.get_size_chunks=" , "f.get_priority=" , "f.get_frozen_path=" } ) ;
// @formatter:off
return new GetFileListTaskSuccessResult ( ( GetFileListTask ) task , onTorrentFilesRetrieved ( fresult , task . getTargetTorrent ( ) ) ) ;
Object fresult = makeRtorrentCall ( "f.multicall" , new String [ ] {
task . getTargetTorrent ( ) . getUniqueID ( ) ,
"" ,
"f.get_path=" ,
"f.get_size_bytes=" ,
"f.get_priority=" ,
"f.get_completed_chunks=" ,
"f.get_size_chunks=" ,
"f.get_priority=" ,
"f.get_frozen_path=" } ) ;
// @formatter:on
return new GetFileListTaskSuccessResult ( ( GetFileListTask ) task , onTorrentFilesRetrieved ( fresult ,
task . getTargetTorrent ( ) ) ) ;
case AddByFile :
case AddByFile :
@ -206,7 +249,8 @@ public class RtorrentAdapter implements IDaemonAdapter {
String newPriority = "" + convertPriority ( prioTask . getNewPriority ( ) ) ;
String newPriority = "" + convertPriority ( prioTask . getNewPriority ( ) ) ;
// One at a time; rTorrent doesn't seem to support a multicall on a selective number of files
// One at a time; rTorrent doesn't seem to support a multicall on a selective number of files
for ( TorrentFile forFile : prioTask . getForFiles ( ) ) {
for ( TorrentFile forFile : prioTask . getForFiles ( ) ) {
makeRtorrentCall ( "f.set_priority" , new String [ ] { task . getTargetTorrent ( ) . getUniqueID ( ) + ":f" + forFile . getKey ( ) , newPriority } ) ;
makeRtorrentCall ( "f.set_priority" , new String [ ] {
task . getTargetTorrent ( ) . getUniqueID ( ) + ":f" + forFile . getKey ( ) , newPriority } ) ;
}
}
return new DaemonTaskSuccessResult ( task ) ;
return new DaemonTaskSuccessResult ( task ) ;
@ -214,14 +258,17 @@ public class RtorrentAdapter implements IDaemonAdapter {
// Request to set the maximum transfer rates
// Request to set the maximum transfer rates
SetTransferRatesTask ratesTask = ( SetTransferRatesTask ) task ;
SetTransferRatesTask ratesTask = ( SetTransferRatesTask ) task ;
makeRtorrentCall ( "set_download_rate" , new String [ ] { ( ratesTask . getDownloadRate ( ) = = null ? "0" : ratesTask . getDownloadRate ( ) . toString ( ) + "k" ) } ) ;
makeRtorrentCall ( "set_download_rate" , new String [ ] { ( ratesTask . getDownloadRate ( ) = = null ? "0"
makeRtorrentCall ( "set_upload_rate" , new String [ ] { ( ratesTask . getUploadRate ( ) = = null ? "0" : ratesTask . getUploadRate ( ) . toString ( ) + "k" ) } ) ;
: ratesTask . getDownloadRate ( ) . toString ( ) + "k" ) } ) ;
makeRtorrentCall ( "set_upload_rate" , new String [ ] { ( ratesTask . getUploadRate ( ) = = null ? "0" : ratesTask
. getUploadRate ( ) . toString ( ) + "k" ) } ) ;
return new DaemonTaskSuccessResult ( task ) ;
return new DaemonTaskSuccessResult ( task ) ;
case SetLabel :
case SetLabel :
SetLabelTask labelTask = ( SetLabelTask ) task ;
SetLabelTask labelTask = ( SetLabelTask ) task ;
makeRtorrentCall ( "d.set_custom1" , new String [ ] { task . getTargetTorrent ( ) . getUniqueID ( ) , labelTask . getNewLabel ( ) } ) ;
makeRtorrentCall ( "d.set_custom1" ,
new String [ ] { task . getTargetTorrent ( ) . getUniqueID ( ) , labelTask . getNewLabel ( ) } ) ;
return new DaemonTaskSuccessResult ( task ) ;
return new DaemonTaskSuccessResult ( task ) ;
case ForceRecheck :
case ForceRecheck :
@ -231,7 +278,8 @@ public class RtorrentAdapter implements IDaemonAdapter {
return new DaemonTaskSuccessResult ( task ) ;
return new DaemonTaskSuccessResult ( task ) ;
default :
default :
return new DaemonTaskFailureResult ( task , new DaemonException ( ExceptionType . MethodUnsupported , task . getMethod ( ) + " is not supported by " + getType ( ) ) ) ;
return new DaemonTaskFailureResult ( task , new DaemonException ( ExceptionType . MethodUnsupported ,
task . getMethod ( ) + " is not supported by " + getType ( ) ) ) ;
}
}
} catch ( DaemonException e ) {
} catch ( DaemonException e ) {
return new DaemonTaskFailureResult ( task , e ) ;
return new DaemonTaskFailureResult ( task , e ) ;
@ -242,7 +290,8 @@ public class RtorrentAdapter implements IDaemonAdapter {
}
}
}
}
private Object makeRtorrentCall ( String serverMethod , Object [ ] arguments ) throws DaemonException , MalformedURLException {
private Object makeRtorrentCall ( String serverMethod , Object [ ] arguments ) throws DaemonException ,
MalformedURLException {
// Initialise the HTTP client
// Initialise the HTTP client
if ( rpcclient = = null ) {
if ( rpcclient = = null ) {
@ -250,9 +299,12 @@ public class RtorrentAdapter implements IDaemonAdapter {
}
}
String params = "" ;
String params = "" ;
for ( Object arg : arguments ) params + = " " + arg . toString ( ) ;
for ( Object arg : arguments )
params + = " " + arg . toString ( ) ;
try {
try {
DLog . d ( LOG_NAME , "Calling " + serverMethod + " with params [" + ( params . length ( ) > 100 ? params . substring ( 0 , 100 ) + "..." : params ) + " ]" ) ;
DLog . d ( LOG_NAME ,
"Calling " + serverMethod + " with params ["
+ ( params . length ( ) > 100 ? params . substring ( 0 , 100 ) + "..." : params ) + " ]" ) ;
return rpcclient . call ( serverMethod , arguments ) ;
return rpcclient . call ( serverMethod , arguments ) ;
} catch ( XMLRPCException e ) {
} catch ( XMLRPCException e ) {
DLog . d ( LOG_NAME , e . toString ( ) ) ;
DLog . d ( LOG_NAME , e . toString ( ) ) ;
@ -260,7 +312,9 @@ public class RtorrentAdapter implements IDaemonAdapter {
throw new DaemonException ( ExceptionType . AuthenticationFailure , e . toString ( ) ) ;
throw new DaemonException ( ExceptionType . AuthenticationFailure , e . toString ( ) ) ;
if ( e . getCause ( ) instanceof DaemonException )
if ( e . getCause ( ) instanceof DaemonException )
throw ( DaemonException ) e . getCause ( ) ;
throw ( DaemonException ) e . getCause ( ) ;
throw new DaemonException ( ExceptionType . ConnectionError , "Error making call to " + serverMethod + " with params [" + ( params . length ( ) > 100 ? params . substring ( 0 , 100 ) + "..." : params ) + " ]: " + e . toString ( ) ) ;
throw new DaemonException ( ExceptionType . ConnectionError , "Error making call to " + serverMethod
+ " with params [" + ( params . length ( ) > 100 ? params . substring ( 0 , 100 ) + "..." : params ) + " ]: "
+ e . toString ( ) ) ;
}
}
}
}
@ -282,15 +336,20 @@ public class RtorrentAdapter implements IDaemonAdapter {
* @return The URL of the RPC API
* @return The URL of the RPC API
* /
* /
private String buildWebUIUrl ( ) {
private String buildWebUIUrl ( ) {
return ( settings . getSsl ( ) ? "https://" : "http://" ) + settings . getAddress ( ) + ":" + settings . getPort ( ) +
return ( settings . getSsl ( ) ? "https://" : "http://" )
( settings . getFolder ( ) = = null | | settings . getFolder ( ) . equals ( "" ) ? DEFAULT_RPC_URL : settings . getFolder ( ) ) ;
+ settings . getAddress ( )
+ ":"
+ settings . getPort ( )
+ ( settings . getFolder ( ) = = null | | settings . getFolder ( ) . equals ( "" ) ? DEFAULT_RPC_URL : settings
. getFolder ( ) ) ;
}
}
private List < Torrent > onTorrentsRetrieved ( Object response ) throws DaemonException {
private List < Torrent > onTorrentsRetrieved ( Object response ) throws DaemonException {
if ( response = = null | | ! ( response instanceof Object [ ] ) ) {
if ( response = = null | | ! ( response instanceof Object [ ] ) ) {
throw new DaemonException ( ExceptionType . ParsingFailed , "Response on retrieveing torrents did not return a list of objects" ) ;
throw new DaemonException ( ExceptionType . ParsingFailed ,
"Response on retrieveing torrents did not return a list of objects" ) ;
} else {
} else {
@ -355,6 +414,7 @@ public class RtorrentAdapter implements IDaemonAdapter {
long rateDownload = ( Long ) info [ 3 ] ;
long rateDownload = ( Long ) info [ 3 ] ;
String basePath = ( String ) info [ 16 ] ;
String basePath = ( String ) info [ 16 ] ;
// @formatter:off
torrents . add ( new Torrent (
torrents . add ( new Torrent (
i ,
i ,
( String ) info [ 0 ] , // hash
( String ) info [ 0 ] , // hash
@ -363,10 +423,10 @@ public class RtorrentAdapter implements IDaemonAdapter {
basePath . substring ( 0 , basePath . indexOf ( ( String ) info [ 17 ] ) ) , // locationDir
basePath . substring ( 0 , basePath . indexOf ( ( String ) info [ 17 ] ) ) , // locationDir
( ( Long ) info [ 3 ] ) . intValue ( ) , // rateDownload
( ( Long ) info [ 3 ] ) . intValue ( ) , // rateDownload
( ( Long ) info [ 4 ] ) . intValue ( ) , // rateUpload
( ( Long ) info [ 4 ] ) . intValue ( ) , // rateUpload
( ( Long ) info [ 5 ] ) . intValue ( ) , // peersGettingFromUs
( ( Long ) info [ 22 ] ) . intValue ( ) , // seedersConnected
( ( Long ) info [ 5 ] ) . intValue ( ) , // peersSendingToUs
( ( Long ) info [ 5 ] ) . intValue ( ) + ( ( Long ) info [ 6 ] ) . intValue ( ) , // seedersKnown
( ( Long ) info [ 5 ] ) . intValue ( ) , // pe ersConnected
( ( Long ) info [ 23 ] ) . intValue ( ) , // leech ersConnected
( ( Long ) info [ 5 ] ) . intValue ( ) + ( ( Long ) info [ 6 ] ) . intValue ( ) , // pe ersKnown
( ( Long ) info [ 5 ] ) . intValue ( ) + ( ( Long ) info [ 6 ] ) . intValue ( ) , // leech ersKnown
( rateDownload > 0 ? ( int ) ( ( ( Long ) info [ 12 ] ) / rateDownload ) : - 1 ) , // eta (bytes left / rate download, if rate > 0)
( rateDownload > 0 ? ( int ) ( ( ( Long ) info [ 12 ] ) / rateDownload ) : - 1 ) , // eta (bytes left / rate download, if rate > 0)
( Long ) info [ 8 ] , // downloadedEver
( Long ) info [ 8 ] , // downloadedEver
( Long ) info [ 9 ] , // uploadedEver
( Long ) info [ 9 ] , // uploadedEver
@ -378,6 +438,7 @@ public class RtorrentAdapter implements IDaemonAdapter {
finished ,
finished ,
error ,
error ,
settings . getType ( ) ) ) ;
settings . getType ( ) ) ) ;
// @formatter:on
} else {
} else {
@ -385,6 +446,7 @@ public class RtorrentAdapter implements IDaemonAdapter {
int rateDownload = ( Integer ) info [ 3 ] ;
int rateDownload = ( Integer ) info [ 3 ] ;
String basePath = ( String ) info [ 16 ] ;
String basePath = ( String ) info [ 16 ] ;
// @formatter:off
torrents . add ( new Torrent (
torrents . add ( new Torrent (
i ,
i ,
( String ) info [ 0 ] , // hash
( String ) info [ 0 ] , // hash
@ -393,10 +455,10 @@ public class RtorrentAdapter implements IDaemonAdapter {
basePath . substring ( 0 , basePath . indexOf ( ( String ) info [ 17 ] ) ) , // locationDir
basePath . substring ( 0 , basePath . indexOf ( ( String ) info [ 17 ] ) ) , // locationDir
rateDownload , // rateDownload
rateDownload , // rateDownload
( Integer ) info [ 4 ] , // rateUpload
( Integer ) info [ 4 ] , // rateUpload
( Integer ) info [ 5 ] , // peersGettingFromUs
( ( Integer ) info [ 22 ] ) . intValue ( ) , // seedersConnected
( Integer ) info [ 5 ] , // peersSendingToUs
( ( Integer ) info [ 5 ] ) . intValue ( ) + ( ( Integer ) info [ 6 ] ) . intValue ( ) , // seedersKnown
( Integer ) info [ 5 ] , // pe ersConnected
( ( Integer ) info [ 23 ] ) . intValue ( ) , // leech ersConnected
( Integer ) info [ 5 ] + ( Integer ) info [ 6 ] , // pe ersKnown
( ( Integer ) info [ 5 ] ) . intValue ( ) + ( ( Integer ) info [ 6 ] ) . intValue ( ) , // leech ersKnown
( rateDownload > 0 ? ( int ) ( ( Integer ) info [ 12 ] / rateDownload ) : - 1 ) , // eta (bytes left / rate download, if rate > 0)
( rateDownload > 0 ? ( int ) ( ( Integer ) info [ 12 ] / rateDownload ) : - 1 ) , // eta (bytes left / rate download, if rate > 0)
( Integer ) info [ 8 ] , // downloadedEver
( Integer ) info [ 8 ] , // downloadedEver
( Integer ) info [ 9 ] , // uploadedEver
( Integer ) info [ 9 ] , // uploadedEver
@ -408,6 +470,7 @@ public class RtorrentAdapter implements IDaemonAdapter {
finished ,
finished ,
error ,
error ,
settings . getType ( ) ) ) ;
settings . getType ( ) ) ) ;
// @formatter:on
}
}
}
}
@ -426,7 +489,8 @@ public class RtorrentAdapter implements IDaemonAdapter {
if ( response = = null | | ! ( response instanceof Object [ ] ) ) {
if ( response = = null | | ! ( response instanceof Object [ ] ) ) {
throw new DaemonException ( ExceptionType . ParsingFailed , "Response on retrieveing torrent files did not return a list of objects" ) ;
throw new DaemonException ( ExceptionType . ParsingFailed ,
"Response on retrieveing torrent files did not return a list of objects" ) ;
} else {
} else {
@ -445,6 +509,7 @@ public class RtorrentAdapter implements IDaemonAdapter {
Long chunksTotal = ( Long ) info [ 4 ] ;
Long chunksTotal = ( Long ) info [ 4 ] ;
Long priority = ( Long ) info [ 5 ] ;
Long priority = ( Long ) info [ 5 ] ;
// @formatter:off
files . add ( new TorrentFile (
files . add ( new TorrentFile (
"" + i ,
"" + i ,
( String ) info [ 0 ] , // name
( String ) info [ 0 ] , // name
@ -453,7 +518,7 @@ public class RtorrentAdapter implements IDaemonAdapter {
size , // size
size , // size
( long ) ( size * ( ( float ) chunksDone / ( float ) chunksTotal ) ) , // done
( long ) ( size * ( ( float ) chunksDone / ( float ) chunksTotal ) ) , // done
convertRtorrentPriority ( priority . intValue ( ) ) ) ) ; // priority
convertRtorrentPriority ( priority . intValue ( ) ) ) ) ; // priority
//(Long)info[2] has priority
// @formatter:on
} else {
} else {
@ -463,6 +528,7 @@ public class RtorrentAdapter implements IDaemonAdapter {
Integer chunksTotal = ( Integer ) info [ 4 ] ;
Integer chunksTotal = ( Integer ) info [ 4 ] ;
Integer priority = ( Integer ) info [ 5 ] ;
Integer priority = ( Integer ) info [ 5 ] ;
// @formatter:off
files . add ( new TorrentFile (
files . add ( new TorrentFile (
"" + i ,
"" + i ,
( String ) info [ 0 ] , // name
( String ) info [ 0 ] , // name
@ -471,7 +537,7 @@ public class RtorrentAdapter implements IDaemonAdapter {
size , // size
size , // size
( int ) ( size * ( ( float ) chunksDone / ( float ) chunksTotal ) ) , // done
( int ) ( size * ( ( float ) chunksDone / ( float ) chunksTotal ) ) , // done
convertRtorrentPriority ( priority ) ) ) ; // priority
convertRtorrentPriority ( priority ) ) ) ; // priority
//(Long)info[2] has priority
// @formatter:on
}
}
}
}
@ -525,7 +591,8 @@ public class RtorrentAdapter implements IDaemonAdapter {
if ( response = = null | | ! ( response instanceof Object [ ] ) ) {
if ( response = = null | | ! ( response instanceof Object [ ] ) ) {
throw new DaemonException ( ExceptionType . ParsingFailed , "Response on retrieveing trackers did not return a list of objects" ) ;
throw new DaemonException ( ExceptionType . ParsingFailed ,
"Response on retrieveing trackers did not return a list of objects" ) ;
} else {
} else {