/
httpcontrolserver.py
96 lines (80 loc) · 3.59 KB
/
httpcontrolserver.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
"""
The HTTPControlServer manages an HTTP control channel for a client. It
implements HTTP route handlers using the Klein microframework. It handles
incoming messages by passing them off to the client for processing and then
sending the appropriate HTTP response.
"""
import json
from commands import MsgError
from klein import Klein
from twisted.web.static import File
class HTTPControlServer(object):
app = Klein()
def __init__(self, client):
self._client = client
@app.route('/', branch=True)
def static(self, request):
"""
For get requests to /, this route handler responds with the file
static/index.html. For get requests to /path, aside from those defined
below (e.g. /torrents), the route handler responds with the file
static/path.
"""
return File("./static")
@app.route('/torrents')
def torrents(self, request):
"""
The route handler for get requests to /torrents responds with a json
formatted string which represents a dictionary containing information
about torrents which the client is handling keyed by info hash.
"""
return json.dumps(self._client.get_torrents())
@app.route('/add', methods=['POST'])
def add(self, request):
"""
The route handler for post requests to /add asks the client to start
handling the torrent specified by the filename supplied in the header.
If successful, it sends a response with a key for the torrent, the name
of the torrent and the request id that was supplied in the post
request. If unsuccessful, it responds with a 400 status code and a
json formatted string containing an error message and the request id.
"""
filename = request.args.get('filename', [''])[0]
requestid = request.args.get('requestid', [''])[0]
request.setHeader('Content-Type', 'application/json')
def success((info_hash, name), request, requestid):
return json.dumps(dict(key=info_hash, name=name,
requestid=requestid))
def failure(err, request, requestid):
request.setResponseCode(400)
return json.dumps(dict(message=err.value.message,
requestid=requestid))
return (self._client.add_torrent(filename)
.addCallbacks(success, failure,
callbackArgs=(request, requestid),
errbackArgs=(request, requestid)))
@app.route('/status')
def status(self, request):
"""
The route handler for get requests to /status asks the client for the
status of the torrent with the supplied key. It responds with a json
formatted string which represents status information about the torrent,
currently only the percent downloaded. If the client is not handling
a torrent with the specified key, it responds with a 400 status code
along with a json formatted string containing the error message.
"""
key = request.args.get('key', [""])[0]
request.setHeader('Content-Type', 'application/json')
try:
status = self._client.get_status(key)
except MsgError as err:
request.setResponseCode(400)
return json.dumps(dict(message=err.message))
return json.dumps(status)
@app.route('/quit', methods=['POST'])
def quit(self, request):
"""
The route handler for post requests to /quit asks the client to shut
down.
"""
self._client.quit()