Browse Source

Added support for torrent (tracker) details.

rewrite-connect
Eric Kok 8 years ago
parent
commit
468cea70d2
  1. 15
      connect/src/main/java/org/transdroid/connect/clients/ClientDelegate.kt
  2. 1
      connect/src/main/java/org/transdroid/connect/clients/ClientSpec.kt
  3. 8
      connect/src/main/java/org/transdroid/connect/clients/Feature.kt
  4. 16
      connect/src/main/java/org/transdroid/connect/clients/rtorrent/Rtorrent.kt
  5. 8
      connect/src/main/java/org/transdroid/connect/clients/rtorrent/Service.kt
  6. 3
      connect/src/main/java/org/transdroid/connect/clients/rtorrent/TrackerSpec.kt
  7. 23
      connect/src/main/java/org/transdroid/connect/model/Torrent.kt
  8. 5
      connect/src/main/java/org/transdroid/connect/model/TorrentDetails.kt
  9. 3
      connect/src/main/java/org/transdroid/connect/util/RxUtil.kt
  10. 8
      connect/src/test/java/org/transdroid/connect/clients/rtorrent/RtorrentLiveTest.kt
  11. 16
      connect/src/test/java/org/transdroid/connect/clients/rtorrent/RtorrentMockTest.kt
  12. 9
      connect/src/test/java/org/transdroid/connect/mock/MockTorrent.kt

15
connect/src/main/java/org/transdroid/connect/clients/ClientDelegate.kt

@ -4,6 +4,7 @@ import io.reactivex.Completable @@ -4,6 +4,7 @@ import io.reactivex.Completable
import io.reactivex.Flowable
import io.reactivex.Single
import org.transdroid.connect.model.Torrent
import org.transdroid.connect.model.TorrentDetails
import java.io.InputStream
/**
@ -12,16 +13,22 @@ import java.io.InputStream @@ -12,16 +13,22 @@ import java.io.InputStream
*/
internal class ClientDelegate(private val client: Client, private val actual: Any) : ClientSpec {
override fun clientVersion(): Single<String> {
if (client.supports(Feature.VERSION))
return (actual as Feature.Version).clientVersion()
throw UnsupportedFeatureException(client, Feature.VERSION)
}
override fun torrents(): Flowable<Torrent> {
if (client.supports(Feature.LISTING))
return (actual as Feature.Listing).torrents()
throw UnsupportedFeatureException(client, Feature.LISTING)
}
override fun clientVersion(): Single<String> {
if (client.supports(Feature.VERSION))
return (actual as Feature.Version).clientVersion()
throw UnsupportedFeatureException(client, Feature.VERSION)
override fun details(torrent: Torrent): Single<TorrentDetails> {
if (client.supports(Feature.DETAILS))
return (actual as Feature.Details).details(torrent)
throw UnsupportedFeatureException(client, Feature.DETAILS)
}
override fun resume(torrent: Torrent): Single<Torrent> {

1
connect/src/main/java/org/transdroid/connect/clients/ClientSpec.kt

@ -3,6 +3,7 @@ package org.transdroid.connect.clients @@ -3,6 +3,7 @@ package org.transdroid.connect.clients
interface ClientSpec :
Feature.Version,
Feature.Listing,
Feature.Details,
Feature.StartingStopping,
Feature.ResumingPausing,
Feature.ForceStarting,

8
connect/src/main/java/org/transdroid/connect/clients/Feature.kt

@ -4,6 +4,7 @@ import io.reactivex.Completable @@ -4,6 +4,7 @@ import io.reactivex.Completable
import io.reactivex.Flowable
import io.reactivex.Single
import org.transdroid.connect.model.Torrent
import org.transdroid.connect.model.TorrentDetails
import java.io.InputStream
import kotlin.reflect.KClass
@ -14,6 +15,7 @@ enum class Feature constructor(val type: KClass<*>) { @@ -14,6 +15,7 @@ enum class Feature constructor(val type: KClass<*>) {
VERSION(Version::class),
LISTING(Listing::class),
DETAILS(Details::class),
STARTING_STOPPING(StartingStopping::class),
RESUMING_PAUSING(ResumingPausing::class),
FORCE_STARTING(ForceStarting::class),
@ -33,6 +35,12 @@ enum class Feature constructor(val type: KClass<*>) { @@ -33,6 +35,12 @@ enum class Feature constructor(val type: KClass<*>) {
}
interface Details {
fun details(torrent: Torrent): Single<TorrentDetails>
}
interface StartingStopping {
fun start(torrent: Torrent): Single<Torrent>

16
connect/src/main/java/org/transdroid/connect/clients/rtorrent/Rtorrent.kt

@ -7,6 +7,7 @@ import nl.nl2312.xmlrpc.XmlRpcConverterFactory @@ -7,6 +7,7 @@ import nl.nl2312.xmlrpc.XmlRpcConverterFactory
import org.transdroid.connect.Configuration
import org.transdroid.connect.clients.Feature
import org.transdroid.connect.model.Torrent
import org.transdroid.connect.model.TorrentDetails
import org.transdroid.connect.model.TorrentStatus
import org.transdroid.connect.util.OkHttpBuilder
import org.transdroid.connect.util.flatten
@ -18,6 +19,7 @@ import java.util.* @@ -18,6 +19,7 @@ import java.util.*
class Rtorrent(private val configuration: Configuration) :
Feature.Version,
Feature.Listing,
Feature.Details,
Feature.StartingStopping,
Feature.ResumingPausing,
Feature.AddByFile,
@ -60,6 +62,9 @@ class Rtorrent(private val configuration: Configuration) : @@ -60,6 +62,9 @@ class Rtorrent(private val configuration: Configuration) :
)
}
.addArrayDeserializer(TrackerSpec::class.java) { arrayValues ->
TrackerSpec(arrayValues.asString(0))
}
.create())
.build().create(Service::class.java)
@ -123,11 +128,20 @@ class Rtorrent(private val configuration: Configuration) : @@ -123,11 +128,20 @@ class Rtorrent(private val configuration: Configuration) :
null,
label,
torrentTimeAdded(timeAdded, timeCreated),
torrentTimeFinished(timeFinished), errorMessage
torrentTimeFinished(timeFinished),
errorMessage
)
}
}
override fun details(torrent: Torrent): Single<TorrentDetails> {
return service.trackers(configuration.endpoint, torrent.uniqueId, "", "t.url=")
.flatten()
.map { (url) -> url }
.toList()
.map { trackers -> TorrentDetails(trackers, listOfNotNull(torrent.error)) }
}
override fun start(torrent: Torrent): Single<Torrent> {
return service.open(configuration.endpoint, torrent.uniqueId)
.flatMap { service.start(configuration.endpoint, torrent.uniqueId) }

8
connect/src/main/java/org/transdroid/connect/clients/rtorrent/Service.kt

@ -1,7 +1,5 @@ @@ -1,7 +1,5 @@
package org.transdroid.connect.clients.rtorrent
import io.reactivex.Completable
import io.reactivex.Flowable
import io.reactivex.Single
import nl.nl2312.xmlrpc.Nothing
import nl.nl2312.xmlrpc.XmlRpc
@ -17,7 +15,11 @@ internal interface Service { @@ -17,7 +15,11 @@ internal interface Service {
@XmlRpc("d.multicall2")
@POST("{endpoint}")
fun torrents(@Path("endpoint") endpoint: String?, @Body vararg args: String): Flowable<Array<TorrentSpec>>
fun torrents(@Path("endpoint") endpoint: String?, @Body vararg args: String): Single<Array<TorrentSpec>>
@XmlRpc("t.multicall")
@POST("{endpoint}")
fun trackers(@Path("endpoint") endpoint: String?, @Body vararg args: String): Single<Array<TrackerSpec>>
@XmlRpc("d.start")
@POST("{endpoint}")

3
connect/src/main/java/org/transdroid/connect/clients/rtorrent/TrackerSpec.kt

@ -0,0 +1,3 @@ @@ -0,0 +1,3 @@
package org.transdroid.connect.clients.rtorrent
data class TrackerSpec(val url: String)

23
connect/src/main/java/org/transdroid/connect/model/Torrent.kt

@ -22,31 +22,18 @@ data class Torrent( @@ -22,31 +22,18 @@ data class Torrent(
val available: Float?,
val label: String?,
val dateAdded: Date,
val realDateDone: Date?,
private val realDateDone: Date?,
val error: String?) {
val dateDone: Date
init {
if (realDateDone != null) {
this.dateDone = realDateDone
} else {
if (this.partDone == 1f) {
// Finished but no finished date: set so move to bottom of list
this.dateDone = Calendar.getInstance().apply {
val dateDone: Date = realDateDone ?:
if (this.partDone == 1f) Calendar.getInstance().apply {
clear()
set(1900, Calendar.DECEMBER, 31)
}.time
} else if (eta == null || eta == -1L || eta == -2L) {
// Unknown eta: move to the top of the list
this.dateDone = Date(java.lang.Long.MAX_VALUE)
} else {
this.dateDone = Calendar.getInstance().apply {
else if (eta == null || eta == -1L || eta == -2L) Date(java.lang.Long.MAX_VALUE)
else Calendar.getInstance().apply {
add(Calendar.SECOND, eta.toInt())
}.time
}
}
}
/**
* The unique torrent-specific id, which is the torrent's hash or (if not available) the local index number

5
connect/src/main/java/org/transdroid/connect/model/TorrentDetails.kt

@ -0,0 +1,5 @@ @@ -0,0 +1,5 @@
package org.transdroid.connect.model
data class TorrentDetails(
val trackers: List<String>,
var errors: List<String>)

3
connect/src/main/java/org/transdroid/connect/util/RxUtil.kt

@ -1,5 +1,6 @@ @@ -1,5 +1,6 @@
package org.transdroid.connect.util
import io.reactivex.Flowable
import io.reactivex.Single
fun <T : Any> Flowable<Array<T>>.flatten(): Flowable<T> = this.flatMapIterable { items -> items.toList() }
fun <T : Any> Single<Array<T>>.flatten(): Flowable<T> = this.flattenAsFlowable { items -> items.toList() }

8
connect/src/test/java/org/transdroid/connect/clients/rtorrent/RtorrentLiveTest.kt

@ -1,6 +1,5 @@ @@ -1,6 +1,5 @@
package org.transdroid.connect.clients.rtorrent
import com.burgstaller.okhttp.digest.Credentials
import com.google.common.truth.Truth.assertThat
import org.junit.Before
import org.junit.Test
@ -43,6 +42,13 @@ class RtorrentLiveTest { @@ -43,6 +42,13 @@ class RtorrentLiveTest {
.assertValue("0.9.6")
}
@Test
fun details() {
rtorrent.details(firstLiveTorrent())
.test()
.assertValue { it.trackers.isNotEmpty() }
}
@Test
fun torrents() {
rtorrent.torrents()

16
connect/src/test/java/org/transdroid/connect/clients/rtorrent/RtorrentMockTest.kt

@ -7,7 +7,6 @@ import org.junit.Test @@ -7,7 +7,6 @@ import org.junit.Test
import org.transdroid.connect.Configuration
import org.transdroid.connect.clients.Client
import org.transdroid.connect.mock.MockTorrent
import java.io.File
class RtorrentMockTest {
@ -38,6 +37,21 @@ class RtorrentMockTest { @@ -38,6 +37,21 @@ class RtorrentMockTest {
server.takeRequest()
}
@Test
fun details() {
server.enqueue(mock("<array><data><value><array><data><value><string>http://torrent.ubuntu.com:6969/announce</string></value></data></array></value><value><array><data><value><string>http://ipv6.torrent.ubuntu.com:6969/announce</string></value></data></array></value></data></array>"))
rtorrent.details(MockTorrent.error)
.test()
.assertValue {
it.trackers.size == 2 &&
it.trackers[0] == "http://torrent.ubuntu.com:6969/announce" &&
it.trackers[1] == "http://ipv6.torrent.ubuntu.com:6969/announce" &&
it.errors.size == 1 &&
it.errors[0] == "tracker error"
}
server.takeRequest()
}
@Test
fun addByUrl() {
server.enqueue(mock("<string>0.9.6</string>"))

9
connect/src/test/java/org/transdroid/connect/mock/MockTorrent.kt

@ -12,8 +12,13 @@ object MockTorrent { @@ -12,8 +12,13 @@ object MockTorrent {
val torrentFile = File("connect/src/test/resources/test/ubuntu.torrent").inputStream()
val downloading = Torrent(0, "59066769B9AD42DA2E508611C33D7C4480B3857B", "ubuntu-17.04-desktop-amd64.iso", TorrentStatus.DOWNLOADING,
"/downloads/", 1000000, 200000, 20, 20, 2, 50, null, 804519936, 160903987, 1609039872, 0.5F, 0.8F, "distros", Date(1492681983), null, null)
"/downloads/", 1000000, 200000, 20, 20, 2, 50, null, 804519936, 160903987, 1609039872, 0.5F, 0.8F, "distros", Date(1492681983),
null, null)
val seeding = Torrent(0, "59066769B9AD42DA2E508611C33D7C4480B3857B", "ubuntu-17.04-desktop-amd64.iso", TorrentStatus.SEEDING,
"/downloads/", 0, 1000000, 0, 24, 10, 50, null, 1609039872, 2609039872, 1609039872, 1F, 1F, "distros", Date(1492681983), Date(1492781983), null)
"/downloads/", 0, 1000000, 0, 24, 10, 50, null, 1609039872, 2609039872, 1609039872, 1F, 1F, "distros", Date(1492681983),
Date(1492781983), null)
val error = Torrent(0, "59066769B9AD42DA2E508611C33D7C4480B3857B", "ubuntu-17.04-desktop-amd64.iso", TorrentStatus.ERROR,
"/downloads/", 0, 1000000, 0, 0, 0, 0, null, 1609039872, 2609039872, 1609039872, 1F, 1F, "distros", Date(1492681983),
Date(1492781983), "tracker error")
}
Loading…
Cancel
Save