Skip to content

Commit

Permalink
master - documentation and cleanup.
Browse files Browse the repository at this point in the history
  • Loading branch information
masterwok committed Aug 1, 2018
1 parent 2c80360 commit 326fd4d
Show file tree
Hide file tree
Showing 8 changed files with 179 additions and 63 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import com.masterwok.demosimpletorrentandroid.R
import com.masterwok.simpletorrentandroid.models.TorrentSessionBufferState
import com.masterwok.simpletorrentandroid.models.TorrentSessionBuffer
import com.masterwok.simpletorrentandroid.models.TorrentSessionStatus

class TorrentPieceAdapter : RecyclerView.Adapter<TorrentPieceAdapter.PieceViewHolder>() {
Expand All @@ -23,7 +23,7 @@ class TorrentPieceAdapter : RecyclerView.Adapter<TorrentPieceAdapter.PieceViewHo

}

private lateinit var bufferState: TorrentSessionBufferState
private lateinit var torrentSessionBuffer: TorrentSessionBuffer

private var isInitialized = false

Expand All @@ -38,7 +38,7 @@ class TorrentPieceAdapter : RecyclerView.Adapter<TorrentPieceAdapter.PieceViewHo
false
))

override fun getItemCount(): Int = if (isInitialized) bufferState.pieceCount else 0
override fun getItemCount(): Int = if (isInitialized) torrentSessionBuffer.pieceCount else 0

override fun onBindViewHolder(holder: PieceViewHolder, position: Int) {
val context = holder.itemView.context
Expand All @@ -50,26 +50,26 @@ class TorrentPieceAdapter : RecyclerView.Adapter<TorrentPieceAdapter.PieceViewHo
context: Context
, position: Int
): Int {
val isDownloaded = bufferState.isPieceDownloaded(position)
val isDownloaded = torrentSessionBuffer.isPieceDownloaded(position)

if (isDownloaded) {
return ContextCompat.getColor(context, R.color.green)
}

if (bufferState.bufferSize == 0) {
if (torrentSessionBuffer.bufferSize == 0) {
return ContextCompat.getColor(context, R.color.purple)
}

if (bufferState.bufferHeadIndex == position) {
if (torrentSessionBuffer.bufferHeadIndex == position) {
if (isDownloaded) {
return ContextCompat.getColor(context, R.color.blue)
}

return ContextCompat.getColor(context, R.color.red)
}

if (position > bufferState.bufferHeadIndex
&& position <= bufferState.bufferTailIndex) {
if (position > torrentSessionBuffer.bufferHeadIndex
&& position <= torrentSessionBuffer.bufferTailIndex) {
return ContextCompat.getColor(context, R.color.yellow)
}

Expand All @@ -78,12 +78,12 @@ class TorrentPieceAdapter : RecyclerView.Adapter<TorrentPieceAdapter.PieceViewHo

fun configure(torrentSessionStatus: TorrentSessionStatus) {
val downloadedPieceCount = torrentSessionStatus
.torrentSessionBufferState
.torrentSessionBuffer
.downloadedPieceCount

if (downloadedPieceCount != lastCompletedPieceCount) {
lastCompletedPieceCount = downloadedPieceCount
bufferState = torrentSessionStatus.torrentSessionBufferState
torrentSessionBuffer = torrentSessionStatus.torrentSessionBuffer
isInitialized = true

notifyDataSetChanged()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,19 @@ import com.frostwire.jlibtorrent.TorrentHandle
import com.frostwire.jlibtorrent.alerts.*
import com.masterwok.simpletorrentandroid.contracts.TorrentSessionListener
import com.masterwok.simpletorrentandroid.extensions.*
import com.masterwok.simpletorrentandroid.models.TorrentSessionBufferState
import com.masterwok.simpletorrentandroid.models.TorrentSessionBuffer
import com.masterwok.simpletorrentandroid.models.TorrentSessionStatus
import java.lang.ref.WeakReference
import java.net.URL
import java.net.URLDecoder
import java.security.InvalidParameterException


@Suppress("MemberVisibilityCanBePrivate")
/**
* This class is used to control a torrent download session for the provided [torrentUri].
* It is configured using the provided [torrentSessionOptions].
*/
@Suppress("MemberVisibilityCanBePrivate", "unused")
class TorrentSession(
val torrentUri: Uri
, private val torrentSessionOptions: TorrentSessionOptions
Expand All @@ -28,13 +32,22 @@ class TorrentSession(
private const val Tag = "TorrentSession"
}

/**
* Whether or not the session is paused.
*/
val isPaused get() = sessionManager.isPaused

/**
* Whether or not the session is running (started).
*/
val isRunning get() = sessionManager.isRunning

/**
* The provided [listener] will receive status updates during the torrent download.
*/
var listener: TorrentSessionListener? = null

private lateinit var bufferState: TorrentSessionBufferState
private lateinit var torrentSessionBuffer: TorrentSessionBuffer
private lateinit var saveLocationUri: Uri
private lateinit var largestFileUri: Uri

Expand All @@ -44,7 +57,6 @@ class TorrentSession(

init {
sessionManager.addListener(alertListener)
sessionManager.start(torrentSessionOptions.build())
}

private class TorrentSessionAlertListener(
Expand Down Expand Up @@ -95,7 +107,7 @@ class TorrentSession(
private fun createTorrentSessionStatus(torrentHandle: TorrentHandle): TorrentSessionStatus =
TorrentSessionStatus.createInstance(
torrentHandle
, bufferState
, torrentSessionBuffer
, saveLocationUri
, largestFileUri
)
Expand Down Expand Up @@ -149,16 +161,16 @@ class TorrentSession(

val pieceIndex = pieceFinishedAlert.pieceIndex()

if (pieceIndex < bufferState.startIndex || pieceIndex > bufferState.endIndex) {
if (pieceIndex < torrentSessionBuffer.startIndex || pieceIndex > torrentSessionBuffer.endIndex) {
// TODO: WHY IS THIS HAPPENING?
Log.w(Tag, "Out of range piece downloaded.")
return
}

bufferState.setPieceDownloaded(pieceIndex)
torrentSessionBuffer.setPieceDownloaded(pieceIndex)

if (torrentSessionOptions.shouldStream) {
torrentHandle.setBufferPriorities(bufferState)
torrentHandle.setBufferPriorities(torrentSessionBuffer)
}

listener?.onPieceFinished(createTorrentSessionStatus(torrentHandle))
Expand All @@ -172,14 +184,14 @@ class TorrentSession(
torrentHandle.prioritizeLargestFile(Priority.NORMAL)
}

bufferState = TorrentSessionBufferState(
bufferState.bufferSize
torrentSessionBuffer = TorrentSessionBuffer(
torrentSessionBuffer.bufferSize
, torrentHandle.getFirstNonIgnoredPieceIndex()
, torrentHandle.getLastNonIgnoredPieceIndex()
)

if (torrentSessionOptions.shouldStream) {
torrentHandle.setBufferPriorities(bufferState)
torrentHandle.setBufferPriorities(torrentSessionBuffer)
}

listener?.onAddTorrent(createTorrentSessionStatus(torrentHandle))
Expand Down Expand Up @@ -247,10 +259,14 @@ class TorrentSession(
saveLocationUri = Uri.EMPTY
largestFileUri = Uri.EMPTY

bufferState = TorrentSessionBufferState(
torrentSessionBuffer = TorrentSessionBuffer(
bufferSize = if (torrentSessionOptions.shouldStream) torrentSessionOptions.bufferSize else 0
)

if (!sessionManager.isRunning) {
sessionManager.start(torrentSessionOptions.build())
}

val path = torrentUri.toString()

if (path.startsWith("magnet")) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,14 @@ import com.frostwire.jlibtorrent.SessionParams
import com.frostwire.jlibtorrent.SettingsPack
import java.io.File

data class TorrentSessionOptions(

/**
* This class provides the options for the [@see TorrentSession].
*
* For more information, [@see https://www.libtorrent.org/reference-Settings.html]
*/
@Suppress("MemberVisibilityCanBePrivate")
class TorrentSessionOptions private constructor(
val bufferSize: Int
, val onlyDownloadLargestFile: Boolean
, val shouldStream: Boolean
Expand Down Expand Up @@ -41,6 +48,9 @@ data class TorrentSessionOptions(
private var dhtNodeLimit: Int = 88
private var anonymousMode: Boolean = false

/**
* Build the [TorrentSessionOptions] instance.
*/
fun build(): TorrentSessionOptions {
return TorrentSessionOptions(
bufferSize
Expand All @@ -56,46 +66,91 @@ data class TorrentSessionOptions(
)
}

/**
* If [onlyDownloadLargestFile] is true, then only the largest file in
* the torrent is downloaded. Default value is, false.
*/
fun onlyDownloadLargestFile(onlyDownloadLargestFile: Boolean): Builder {
this.onlyDownloadLargestFile = onlyDownloadLargestFile
return this
}

/**
* If [shouldStream] is true, then all downloaded files are downloaded
* sequentially. Default value is, false
*/
fun stream(shouldStream: Boolean): Builder {
this.shouldStream = shouldStream
return this
}

/**
* When streaming, the value of [bufferSize] is used to determine the maximum
* number of pieces to prioritize in the [@see TorrentSessionBuffer]. Default
* value, 8.
*/
fun streamBufferSize(bufferSize: Int): Builder {
this.bufferSize = bufferSize
return this
}

/**
* The session-global limits of upload and download rate limits, in bytes per second.
* By default peers on the local network are not rate limited. Default value, 0 (infinity).
*/
fun downloadRateLimit(downloadRateLimit: Int): Builder {
this.downloadRateLimit = downloadRateLimit
return this
}

/**
* The session-global limits of upload and download rate limits, in bytes per second.
* By default peers on the local network are not rate limited. Default value, 0 (infinity).
*/
fun uploadRateLimit(uploadRateLimit: Int): Builder {
this.uploadRateLimit = uploadRateLimit
return this
}

/**
* The 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. Default
* value, 200.
*/
fun connectionsLimit(connectionsLimit: Int): Builder {
this.connectionsLimit = connectionsLimit
return this
}

/**
* The minimum number of DHT nodes to wait for until magnet link downloads will start.
* Default value, 10.
*/
fun dhtNodeMinimum(dhtMin: Int): Builder {
this.dhtNodeMinimum = dhtMin
return this
}

/**
* 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.
*/
fun dhtNodeLimit(dhtLimit: Int): Builder {
this.dhtNodeLimit = dhtLimit
return this
}

/**
* When [useAnonymousMode]is 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. Trackers will only be used if they are using
* a proxy server. The listen sockets are closed, and incoming connections will
* only be accepted through a SOCKS5 or I2P proxy (if a peer proxy is set up and
* is run on the same machine as the tracker proxy). Since no incoming
* connections are accepted, NAT-PMP, UPnP, DHT and local peer discovery are all
* turned off when this setting is enabled.
*/
fun anonymousMode(useAnonymousMode: Boolean): Builder {
this.anonymousMode = useAnonymousMode
return this
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,30 +2,70 @@ package com.masterwok.simpletorrentandroid.contracts

import com.masterwok.simpletorrentandroid.models.TorrentSessionStatus


/**
* This contract provides callbacks to [@see TorrentSession] status updates.
*/
interface TorrentSessionListener {

/**
* Invoked when a piece is finished downloading.
*/
fun onPieceFinished(torrentSessionStatus: TorrentSessionStatus)

/**
* Invoked when the torrent is added.
*/
fun onAddTorrent(torrentSessionStatus: TorrentSessionStatus)

/**
* Invoked when a torrent error occurs.
*/
fun onTorrentError(torrentSessionStatus: TorrentSessionStatus)

/**
* Invoked when the torrent finishes downloading.
*/
fun onTorrentFinished(torrentSessionStatus: TorrentSessionStatus)

/**
* Invoked when fetching metadata for the provided magnet fails.
*/
fun onMetadataFailed(torrentSessionStatus: TorrentSessionStatus)

/**
* Invoked when metadata is successfully fetched.
*/
fun onMetadataReceived(torrentSessionStatus: TorrentSessionStatus)

/**
* Invoked when deleting the torrent fails.
*/
fun onTorrentDeleteFailed(torrentSessionStatus: TorrentSessionStatus)

/**
* Invoked when the torrent is paused.
*/
fun onTorrentPaused(torrentSessionStatus: TorrentSessionStatus)

/**
* Invoked when the torrent is deleted.
*/
fun onTorrentDeleted(torrentSessionStatus: TorrentSessionStatus)

/**
* Invoked when the torrent is removed.
*/
fun onTorrentRemoved(torrentSessionStatus: TorrentSessionStatus)

/**
* Invoked when the torrent is removed.
*/
fun onTorrentResumed(torrentSessionStatus: TorrentSessionStatus)

/**
* Invoked when a block of the torrent is uploaded to a peer.
*/
fun onBlockUploaded(torrentSessionStatus: TorrentSessionStatus)

}
Loading

0 comments on commit 326fd4d

Please sign in to comment.