-
Notifications
You must be signed in to change notification settings - Fork 11
/
tracker.js
111 lines (103 loc) · 3.46 KB
/
tracker.js
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
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
var sys = require('sys'), http = require('http'), bencode = require('bencode'), url = require('url');
function toHexDigit(n){
return '0123456789abcdef'[n];
}
function escapeBinary(s){
// Node's querystring.stringify doesn't escape binary strings
// correctly. (It inserts escape charcters. Not sure why, maybe
// it is treating the data as UTF8 encoded or some other encoding.)
var result = '', i, len, c, cc;
s = '' + s;
for (i = 0, len = s.length; i < len; i += 1) {
c = s.charAt(i);
if ((c >= '0' && c <= '9') || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') ||
(c == '.' || c == '-' || c == '_' || c == '~')) {
result += c;
}
else {
cc = s.charCodeAt(i);
result += '%' + toHexDigit(0xf & (cc >> 4)) + toHexDigit(0xf & cc);
}
}
return result;
}
function queryStringify(params){
var result = '', key, first = true;
for (key in params) {
if (params.hasOwnProperty(key)) {
if (first) {
first = false;
}
else {
result += '&';
}
result += key + '=' + escapeBinary(params[key]);
}
}
return result;
}
function create(metaInfo){
var announce = metaInfo.announce, parsedUrl = url.parse(announce), port = parsedUrl.port ? parsedUrl.port : 80;
return {
metaInfo: metaInfo,
port: port,
trackerRelativeUri: parsedUrl.pathname,
host: parsedUrl.hostname,
peers: {}
};
}
// callback(exception, response, body)
// Handles redirects, coalescing response.
function httpRequestHelper(verb, host, port, path, headers, redirectLimit, callback){
headers.host = host;
var client = http.createClient(port, host), request = client.request(verb, path, headers);
request.addListener('response', function(response){
var statusCode = response.statusCode, body = '';
if (statusCode == 200) {
response.setEncoding('binary');
response.addListener('error', function(error){
callback(error, response, body);
});
response.addListener('end', function(){
callback(null, response, body);
});
response.addListener('data', function(chunk){
body += chunk;
});
}
else
if (statusCode >= 300 && statusCode <= 399) {
if (redirectLimit <= 0) {
callback('Too many redirects', response);
}
else {
sys.log('redirect ' + statusCode + ' ' + JSON.stringify(body));
httpRequestHelper(verb, host, port, path, headers, redirectLimit - 1, callback);
}
}
else {
callback('error', response, body);
}
});
request.end();
}
// callback(error, {response})
function ping(trackerClient, params, callback){
var path = trackerClient.trackerRelativeUri + '?' +
queryStringify(params);
sys.log('pinging tracker');
httpRequestHelper('GET', trackerClient.host, trackerClient.port, path, {}, 10, function(error, response, body){
var result = {};
if (!error) {
try {
result = bencode.decode(body);
}
catch (e) {
error = e;
}
}
callback(error, result);
});
}
exports.create = create;
exports.ping = ping;