Skip to content

Commit

Permalink
Merge pull request #2209 from devos50/get_downloads_endpoint
Browse files Browse the repository at this point in the history
Implemented endpoint to get all downloads in Tribler
  • Loading branch information
whirm committed May 20, 2016
2 parents f2688ed + 4d6ffd7 commit 4e95419
Show file tree
Hide file tree
Showing 5 changed files with 195 additions and 2 deletions.
92 changes: 92 additions & 0 deletions Tribler/Core/Modules/restapi/downloads_endpoint.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
import json

from twisted.web import resource
from Tribler.Core.Libtorrent.LibtorrentDownloadImpl import LibtorrentStatisticsResponse

from Tribler.Core.simpledefs import DOWNLOAD, UPLOAD, dlstatus_strings


class DownloadsEndpoint(resource.Resource):
"""
This endpoint is responsible for all requests regarding downloads. Examples include getting all downloads,
starting, pausing and stopping downloads.
"""

def __init__(self, session):
resource.Resource.__init__(self)
self.session = session

def render_GET(self, request):
"""
A GET request to this endpoint returns all downloads in Tribler, both active and inactive. The progress is a
number ranging from 0 to 1, indicating the progress of the specific state (downloading, checking etc). The
download speeds have the unit bytes/sec. The size of the torrent is given in bytes. The estimated time assumed
is given in seconds. A description of the possible download statuses can be found in the REST API documentation.
Example response:
{
"downloads": [{
"name": "Ubuntu-16.04-desktop-amd64",
"progress": 0.31459265,
"infohash": "4344503b7e797ebf31582327a5baae35b11bda01",
"speed_down": 4938.83,
"speed_up": 321.84,
"status": "DLSTATUS_DOWNLOADING",
"size": 89432483,
"eta": 38493,
"num_peers": 53,
"num_seeds": 93,
"files": [{
"index": 0,
"name": "ubuntu.iso",
"size": 89432483,
"included": True
}, ...],
"trackers": [{
"url": "http://ipv6.torrent.ubuntu.com:6969/announce",
"status": "Working",
"peers": 42
}, ...],
"hops": 1,
"anon_download": True,
"safe_seeding": True,
"max_upload_speed": 0,
"max_download_speed": 0,
}, ...]
}
"""
downloads_json = []
downloads = self.session.get_downloads()
for download in downloads:
stats = download.network_create_statistics_reponse() or LibtorrentStatisticsResponse(0, 0, 0, 0, 0, 0, 0)

# Create files information of the download
selected_files = download.get_selected_files()
files_array = []
for file, size in download.get_def().get_files_as_unicode_with_length():
if download.get_def().is_multifile_torrent():
file_index = download.get_def().get_index_of_file_in_files(file)
else:
file_index = 0

files_array.append({"index": file_index, "name": file, "size": size,
"included": (file in selected_files)})

# Create tracker information of the download
tracker_info = []
for url, url_info in download.network_tracker_status().iteritems():
tracker_info.append({"url": url, "peers": url_info[0], "status": url_info[1]})

download_json = {"name": download.correctedinfoname, "progress": download.get_progress(),
"infohash": download.get_def().get_infohash().encode('hex'),
"speed_down": download.get_current_speed(DOWNLOAD),
"speed_up": download.get_current_speed(UPLOAD),
"status": dlstatus_strings[download.get_status()],
"size": download.get_length(), "eta": download.network_calc_eta(),
"num_peers": stats.numPeers, "num_seeds": stats.numSeeds, "files": files_array,
"trackers": tracker_info, "hops": download.get_hops(),
"anon_download": download.get_anon_mode(), "safe_seeding": download.get_safe_seeding(),
"max_upload_speed": download.get_max_speed(UPLOAD),
"max_download_speed": download.get_max_speed(DOWNLOAD)}
downloads_json.append(download_json)
return json.dumps({"downloads": downloads_json})
4 changes: 3 additions & 1 deletion Tribler/Core/Modules/restapi/root_endpoint.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from twisted.web import resource

from Tribler.Core.Modules.restapi.channels_endpoint import ChannelsEndpoint
from Tribler.Core.Modules.restapi.downloads_endpoint import DownloadsEndpoint
from Tribler.Core.Modules.restapi.events_endpoint import EventsEndpoint
from Tribler.Core.Modules.restapi.my_channel_endpoint import MyChannelEndpoint
from Tribler.Core.Modules.restapi.search_endpoint import SearchEndpoint
Expand All @@ -19,7 +20,8 @@ def __init__(self, session):
self.session = session

child_handler_dict = {"search": SearchEndpoint, "channels": ChannelsEndpoint, "mychannel": MyChannelEndpoint,
"settings": SettingsEndpoint, "variables": VariablesEndpoint, "events": EventsEndpoint}
"settings": SettingsEndpoint, "variables": VariablesEndpoint, "events": EventsEndpoint,
"downloads": DownloadsEndpoint}

for path, child_cls in child_handler_dict.iteritems():
self.putChild(path, child_cls(self.session))
39 changes: 39 additions & 0 deletions Tribler/Test/Core/Modules/RestApi/test_downloads_endpoint.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import json
import os
from urllib import pathname2url

from Tribler.Core.DownloadConfig import DownloadStartupConfig
from Tribler.Core.Utilities.twisted_thread import deferred
from Tribler.Test.Core.Modules.RestApi.base_api_test import AbstractApiTest
from Tribler.Test.test_as_server import TESTS_DATA_DIR


class TestDownloadsEndpoint(AbstractApiTest):

def setUpPreSession(self):
super(TestDownloadsEndpoint, self).setUpPreSession()
self.config.set_libtorrent(True)

@deferred(timeout=10)
def test_get_downloads_no_downloads(self):
"""
Testing whether the API returns an empty list when downloads are fetched but no downloads are active
"""
return self.do_request('downloads', expected_code=200, expected_json={"downloads": []})

@deferred(timeout=20)
def test_get_downloads(self):
"""
Testing whether the API returns the right download when a download is added
"""
def verify_download(downloads):
downloads_json = json.loads(downloads)
self.assertEqual(len(downloads_json['downloads']), 2)

video_tdef, self.torrent_path = self.create_local_torrent(os.path.join(TESTS_DATA_DIR, 'video.avi'))
self.session.start_download_from_tdef(video_tdef, DownloadStartupConfig())
self.session.start_download_from_uri("file:" + pathname2url(
os.path.join(TESTS_DATA_DIR, "bak_multiple.torrent")))

self.should_check_equality = False
return self.do_request('downloads', expected_code=200).addCallback(verify_download)
2 changes: 1 addition & 1 deletion Tribler/Test/Core/Modules/channel/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
"""
This testing package contains tests for the channel module.
This package contains tests for the channel management objects.
"""
60 changes: 60 additions & 0 deletions doc/Tribler REST API.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,21 @@ If a valid request of a client caused a recoverable error the response will have
}
```

## Download states
There are various download states possible which are returned when fetching downloads. These states are explained in the table below.

| State | Description |
| ---- | --------------- |
| DLSTATUS_ALLOCATING_DISKSPACE | Libtorrent is allocating disk space for the download |
| DLSTATUS_WAITING4HASHCHECK | The download is waiting for the hash check to be performed |
| DLSTATUS_HASHCHECKING | Libtorrent is checking the hashes of the download |
| DLSTATUS_DOWNLOADING | The torrent is being downloaded |
| DLSTATUS_SEEDING | The torrent has been downloaded and is now being seeded to other peers |
| DLSTATUS_STOPPED | The torrent has stopped downloading, either because the downloading has completed or the user has stopped the download |
| DLSTATUS_STOPPED_ON_ERROR | The torrent has stopped because an error occurred |
| DLSTATUS_METADATA | The torrent information is being fetched from the DHT |
| DLSTATUS_CIRCUITS | The (anonymous) download is building circuits |

## Endpoints

### Channels
Expand Down Expand Up @@ -78,6 +93,12 @@ If a valid request of a client caused a recoverable error the response will have
| ---- | --------------- |
| GET /variables | Returns runtime-defined variables used by the current Tribler session |

### Downloads

| Endpoint | Description |
| ---- | --------------- |
| GET /downloads | Get information about the downloads in Tribler, both active and inactive |

### Events

| Endpoint | Description |
Expand Down Expand Up @@ -329,6 +350,45 @@ Returns a dictionary with the runtime-defined variables that the current Tribler
}
```

## `GET /downloads`

A GET request to this endpoint returns all downloads in Tribler, both active and inactive. The progress is a number ranging from 0 to 1, indicating the progress of the specific state (downloading, checking etc). The download speeds have the unit bytes/sec. The size of the torrent is given in bytes. The estimated time assumed is given in seconds.

### Example response

```
{
"downloads": [{
"name": "Ubuntu-16.04-desktop-amd64",
"progress": 0.31459265,
"infohash": "4344503b7e797ebf31582327a5baae35b11bda01",
"speed_down": 4938.83,
"speed_up": 321.84,
"status": "DLSTATUS_DOWNLOADING",
"size": 89432483,
"eta": 38493,
"num_peers": 53,
"num_seeds": 93,
"files": [{
"index": 0,
"name": "ubuntu.iso",
"size": 89432483,
"included": True
}, ...],
"trackers": [{
"url": "http://ipv6.torrent.ubuntu.com:6969/announce",
"status": "Working",
"peers": 42
}, ...],
"hops": 1,
"anon_download": True,
"safe_seeding": True,
"max_upload_speed": 0,
"max_download_speed": 0,
}, ...]
}
```

## `GET /events`

Open the event connection. Important events in Tribler are returned over the events endpoint.
Expand Down

0 comments on commit 4e95419

Please sign in to comment.