murder 0.0.0.pre
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +1 -0
- data/LICENSE +17 -0
- data/README +224 -0
- data/Rakefile +52 -0
- data/VERSION +1 -0
- data/dist/BitTornado/BT1/Choker.py +128 -0
- data/dist/BitTornado/BT1/Connecter.py +288 -0
- data/dist/BitTornado/BT1/Downloader.py +594 -0
- data/dist/BitTornado/BT1/DownloaderFeedback.py +155 -0
- data/dist/BitTornado/BT1/Encrypter.py +333 -0
- data/dist/BitTornado/BT1/FileSelector.py +245 -0
- data/dist/BitTornado/BT1/Filter.py +12 -0
- data/dist/BitTornado/BT1/HTTPDownloader.py +251 -0
- data/dist/BitTornado/BT1/NatCheck.py +95 -0
- data/dist/BitTornado/BT1/PiecePicker.py +320 -0
- data/dist/BitTornado/BT1/Rerequester.py +426 -0
- data/dist/BitTornado/BT1/Statistics.py +177 -0
- data/dist/BitTornado/BT1/Storage.py +584 -0
- data/dist/BitTornado/BT1/StorageWrapper.py +1045 -0
- data/dist/BitTornado/BT1/StreamCheck.py +135 -0
- data/dist/BitTornado/BT1/T2T.py +193 -0
- data/dist/BitTornado/BT1/Uploader.py +145 -0
- data/dist/BitTornado/BT1/__init__.py +1 -0
- data/dist/BitTornado/BT1/btformats.py +100 -0
- data/dist/BitTornado/BT1/fakeopen.py +89 -0
- data/dist/BitTornado/BT1/makemetafile.py +263 -0
- data/dist/BitTornado/BT1/track.py +1067 -0
- data/dist/BitTornado/ConfigDir.py +401 -0
- data/dist/BitTornado/ConfigReader.py +1068 -0
- data/dist/BitTornado/ConnChoice.py +31 -0
- data/dist/BitTornado/CreateIcons.py +105 -0
- data/dist/BitTornado/CurrentRateMeasure.py +37 -0
- data/dist/BitTornado/HTTPHandler.py +167 -0
- data/dist/BitTornado/PSYCO.py +5 -0
- data/dist/BitTornado/RateLimiter.py +153 -0
- data/dist/BitTornado/RateMeasure.py +75 -0
- data/dist/BitTornado/RawServer.py +195 -0
- data/dist/BitTornado/ServerPortHandler.py +188 -0
- data/dist/BitTornado/SocketHandler.py +375 -0
- data/dist/BitTornado/__init__.py +63 -0
- data/dist/BitTornado/bencode.py +319 -0
- data/dist/BitTornado/bitfield.py +162 -0
- data/dist/BitTornado/clock.py +27 -0
- data/dist/BitTornado/download_bt1.py +882 -0
- data/dist/BitTornado/inifile.py +169 -0
- data/dist/BitTornado/iprangeparse.py +194 -0
- data/dist/BitTornado/launchmanycore.py +381 -0
- data/dist/BitTornado/natpunch.py +254 -0
- data/dist/BitTornado/parseargs.py +137 -0
- data/dist/BitTornado/parsedir.py +150 -0
- data/dist/BitTornado/piecebuffer.py +86 -0
- data/dist/BitTornado/selectpoll.py +109 -0
- data/dist/BitTornado/subnetparse.py +218 -0
- data/dist/BitTornado/torrentlistparse.py +38 -0
- data/dist/BitTornado/zurllib.py +100 -0
- data/dist/murder_client.py +291 -0
- data/dist/murder_make_torrent.py +46 -0
- data/dist/murder_tracker.py +28 -0
- data/doc/examples/Capfile +28 -0
- data/lib/capistrano/recipes/deploy/strategy/murder.rb +52 -0
- data/lib/murder.rb +43 -0
- data/lib/murder/admin.rb +47 -0
- data/lib/murder/murder.rb +121 -0
- data/murder.gemspec +101 -0
- metadata +129 -0
@@ -0,0 +1,100 @@
|
|
1
|
+
# Written by John Hoffman
|
2
|
+
# see LICENSE.txt for license information
|
3
|
+
|
4
|
+
from httplib import HTTPConnection, HTTPSConnection, HTTPException
|
5
|
+
from urlparse import urlparse
|
6
|
+
from bencode import bdecode
|
7
|
+
import socket
|
8
|
+
from gzip import GzipFile
|
9
|
+
from StringIO import StringIO
|
10
|
+
from urllib import quote, unquote
|
11
|
+
from __init__ import product_name, version_short
|
12
|
+
|
13
|
+
VERSION = product_name+'/'+version_short
|
14
|
+
MAX_REDIRECTS = 10
|
15
|
+
|
16
|
+
|
17
|
+
class btHTTPcon(HTTPConnection): # attempt to add automatic connection timeout
|
18
|
+
def connect(self):
|
19
|
+
HTTPConnection.connect(self)
|
20
|
+
try:
|
21
|
+
self.sock.settimeout(30)
|
22
|
+
except:
|
23
|
+
pass
|
24
|
+
|
25
|
+
class btHTTPScon(HTTPSConnection): # attempt to add automatic connection timeout
|
26
|
+
def connect(self):
|
27
|
+
HTTPSConnection.connect(self)
|
28
|
+
try:
|
29
|
+
self.sock.settimeout(30)
|
30
|
+
except:
|
31
|
+
pass
|
32
|
+
|
33
|
+
class urlopen:
|
34
|
+
def __init__(self, url):
|
35
|
+
self.tries = 0
|
36
|
+
self._open(url.strip())
|
37
|
+
self.error_return = None
|
38
|
+
|
39
|
+
def _open(self, url):
|
40
|
+
self.tries += 1
|
41
|
+
if self.tries > MAX_REDIRECTS:
|
42
|
+
raise IOError, ('http error', 500,
|
43
|
+
"Internal Server Error: Redirect Recursion")
|
44
|
+
(scheme, netloc, path, pars, query, fragment) = urlparse(url)
|
45
|
+
if scheme != 'http' and scheme != 'https':
|
46
|
+
raise IOError, ('url error', 'unknown url type', scheme, url)
|
47
|
+
url = path
|
48
|
+
if pars:
|
49
|
+
url += ';'+pars
|
50
|
+
if query:
|
51
|
+
url += '?'+query
|
52
|
+
# if fragment:
|
53
|
+
try:
|
54
|
+
if scheme == 'http':
|
55
|
+
self.connection = btHTTPcon(netloc)
|
56
|
+
else:
|
57
|
+
self.connection = btHTTPScon(netloc)
|
58
|
+
self.connection.request('GET', url, None,
|
59
|
+
{ 'User-Agent': VERSION,
|
60
|
+
'Accept-Encoding': 'gzip' } )
|
61
|
+
self.response = self.connection.getresponse()
|
62
|
+
except HTTPException, e:
|
63
|
+
raise IOError, ('http error', str(e))
|
64
|
+
status = self.response.status
|
65
|
+
if status in (301,302):
|
66
|
+
try:
|
67
|
+
self.connection.close()
|
68
|
+
except:
|
69
|
+
pass
|
70
|
+
self._open(self.response.getheader('Location'))
|
71
|
+
return
|
72
|
+
if status != 200:
|
73
|
+
try:
|
74
|
+
data = self._read()
|
75
|
+
d = bdecode(data)
|
76
|
+
if d.has_key('failure reason'):
|
77
|
+
self.error_return = data
|
78
|
+
return
|
79
|
+
except:
|
80
|
+
pass
|
81
|
+
raise IOError, ('http error', status, self.response.reason)
|
82
|
+
|
83
|
+
def read(self):
|
84
|
+
if self.error_return:
|
85
|
+
return self.error_return
|
86
|
+
return self._read()
|
87
|
+
|
88
|
+
def _read(self):
|
89
|
+
data = self.response.read()
|
90
|
+
if self.response.getheader('Content-Encoding','').find('gzip') >= 0:
|
91
|
+
try:
|
92
|
+
compressed = StringIO(data)
|
93
|
+
f = GzipFile(fileobj = compressed)
|
94
|
+
data = f.read()
|
95
|
+
except:
|
96
|
+
raise IOError, ('http error', 'got corrupt response')
|
97
|
+
return data
|
98
|
+
|
99
|
+
def close(self):
|
100
|
+
self.connection.close()
|
@@ -0,0 +1,291 @@
|
|
1
|
+
# Copyright 2010 Twitter, Inc.
|
2
|
+
# Copyright 2010 Larry Gadea <lg@twitter.com>
|
3
|
+
#
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
5
|
+
# not use this file except in compliance with the License. You may obtain
|
6
|
+
# a copy of the License at
|
7
|
+
#
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
9
|
+
#
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
12
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
13
|
+
# See the License for the specific language governing permissions and
|
14
|
+
# limitations under the License.
|
15
|
+
|
16
|
+
# Usage: python murder_client.py peer/seed out.torrent OUT.OUT 127.0.0.1
|
17
|
+
# last parameter is the local ip address, normally 10.x.x.x
|
18
|
+
|
19
|
+
import warnings
|
20
|
+
warnings.filterwarnings('ignore', category=DeprecationWarning)
|
21
|
+
|
22
|
+
from BitTornado import PSYCO
|
23
|
+
if PSYCO.psyco:
|
24
|
+
try:
|
25
|
+
import psyco
|
26
|
+
assert psyco.__version__ >= 0x010100f0
|
27
|
+
psyco.full()
|
28
|
+
except:
|
29
|
+
pass
|
30
|
+
|
31
|
+
from BitTornado.download_bt1 import BT1Download, defaults, parse_params, get_usage, get_response
|
32
|
+
from BitTornado.RawServer import RawServer, UPnP_ERROR
|
33
|
+
from random import seed
|
34
|
+
from socket import error as socketerror
|
35
|
+
from BitTornado.bencode import bencode
|
36
|
+
from BitTornado.natpunch import UPnP_test
|
37
|
+
from threading import Event
|
38
|
+
from os.path import abspath
|
39
|
+
from sys import argv, stdout
|
40
|
+
import sys
|
41
|
+
import os
|
42
|
+
import threading
|
43
|
+
from sha import sha
|
44
|
+
from time import strftime
|
45
|
+
from BitTornado.clock import clock
|
46
|
+
from BitTornado import createPeerID, version
|
47
|
+
from BitTornado.ConfigDir import ConfigDir
|
48
|
+
|
49
|
+
assert sys.version >= '2', "Install Python 2.0 or greater"
|
50
|
+
try:
|
51
|
+
True
|
52
|
+
except:
|
53
|
+
True = 1
|
54
|
+
False = 0
|
55
|
+
|
56
|
+
doneFlag = None
|
57
|
+
isPeer = False
|
58
|
+
|
59
|
+
def ok_close_now():
|
60
|
+
doneFlag.set()
|
61
|
+
|
62
|
+
def hours(n):
|
63
|
+
if n == 0:
|
64
|
+
return 'complete!'
|
65
|
+
try:
|
66
|
+
n = int(n)
|
67
|
+
assert n >= 0 and n < 5184000 # 60 days
|
68
|
+
except:
|
69
|
+
return '<unknown>'
|
70
|
+
m, s = divmod(n, 60)
|
71
|
+
h, m = divmod(m, 60)
|
72
|
+
if h > 0:
|
73
|
+
return '%d hour %02d min %02d sec' % (h, m, s)
|
74
|
+
else:
|
75
|
+
return '%d min %02d sec' % (m, s)
|
76
|
+
|
77
|
+
class HeadlessDisplayer:
|
78
|
+
def __init__(self):
|
79
|
+
self.done = False
|
80
|
+
self.file = ''
|
81
|
+
self.percentDone = ''
|
82
|
+
self.timeEst = ''
|
83
|
+
self.downloadTo = ''
|
84
|
+
self.downRate = ''
|
85
|
+
self.upRate = ''
|
86
|
+
self.shareRating = ''
|
87
|
+
self.seedStatus = ''
|
88
|
+
self.peerStatus = ''
|
89
|
+
self.errors = []
|
90
|
+
self.last_update_time = -1
|
91
|
+
|
92
|
+
def finished(self):
|
93
|
+
global doneFlag
|
94
|
+
|
95
|
+
self.done = True
|
96
|
+
self.percentDone = '100'
|
97
|
+
self.timeEst = 'Download Succeeded!'
|
98
|
+
self.downRate = ''
|
99
|
+
#self.display()
|
100
|
+
|
101
|
+
global isPeer
|
102
|
+
|
103
|
+
print "done and done"
|
104
|
+
|
105
|
+
if isPeer:
|
106
|
+
if os.fork():
|
107
|
+
os._exit(0)
|
108
|
+
return
|
109
|
+
|
110
|
+
os.setsid()
|
111
|
+
if os.fork():
|
112
|
+
os._exit(0)
|
113
|
+
return
|
114
|
+
|
115
|
+
os.close(0)
|
116
|
+
os.close(1)
|
117
|
+
os.close(2)
|
118
|
+
|
119
|
+
t = threading.Timer(30.0, ok_close_now)
|
120
|
+
t.start()
|
121
|
+
|
122
|
+
def failed(self):
|
123
|
+
self.done = True
|
124
|
+
self.percentDone = '0'
|
125
|
+
self.timeEst = 'Download Failed!'
|
126
|
+
self.downRate = ''
|
127
|
+
global doneFlag
|
128
|
+
doneFlag.set()
|
129
|
+
#self.display()
|
130
|
+
|
131
|
+
def error(self, errormsg):
|
132
|
+
#self.errors.append(errormsg)
|
133
|
+
self.display()
|
134
|
+
global doneFlag
|
135
|
+
print errormsg
|
136
|
+
doneFlag.set()
|
137
|
+
|
138
|
+
def display(self, dpflag = Event(), fractionDone = None, timeEst = None,
|
139
|
+
downRate = None, upRate = None, activity = None,
|
140
|
+
statistics = None, **kws):
|
141
|
+
if self.last_update_time + 0.1 > clock() and fractionDone not in (0.0, 1.0) and activity is not None:
|
142
|
+
return
|
143
|
+
self.last_update_time = clock()
|
144
|
+
if fractionDone is not None:
|
145
|
+
self.percentDone = str(float(int(fractionDone * 1000)) / 10)
|
146
|
+
if timeEst is not None:
|
147
|
+
self.timeEst = hours(timeEst)
|
148
|
+
if activity is not None and not self.done:
|
149
|
+
self.timeEst = activity
|
150
|
+
if downRate is not None:
|
151
|
+
self.downRate = '%.1f kB/s' % (float(downRate) / (1 << 10))
|
152
|
+
if upRate is not None:
|
153
|
+
self.upRate = '%.1f kB/s' % (float(upRate) / (1 << 10))
|
154
|
+
if statistics is not None:
|
155
|
+
if (statistics.shareRating < 0) or (statistics.shareRating > 100):
|
156
|
+
self.shareRating = 'oo (%.1f MB up / %.1f MB down)' % (float(statistics.upTotal) / (1<<20), float(statistics.downTotal) / (1<<20))
|
157
|
+
else:
|
158
|
+
self.shareRating = '%.3f (%.1f MB up / %.1f MB down)' % (statistics.shareRating, float(statistics.upTotal) / (1<<20), float(statistics.downTotal) / (1<<20))
|
159
|
+
if not self.done:
|
160
|
+
self.seedStatus = '%d seen now, plus %.3f distributed copies' % (statistics.numSeeds,0.001*int(1000*statistics.numCopies))
|
161
|
+
else:
|
162
|
+
self.seedStatus = '%d seen recently, plus %.3f distributed copies' % (statistics.numOldSeeds,0.001*int(1000*statistics.numCopies))
|
163
|
+
self.peerStatus = '%d seen now, %.1f%% done at %.1f kB/s' % (statistics.numPeers,statistics.percentDone,float(statistics.torrentRate) / (1 << 10))
|
164
|
+
#print '\n\n\n\n'
|
165
|
+
for err in self.errors:
|
166
|
+
print 'ERROR:\n' + err + '\n'
|
167
|
+
#print 'saving: ', self.file
|
168
|
+
#print 'percent done: ', self.percentDone
|
169
|
+
#print 'time left: ', self.timeEst
|
170
|
+
#print 'download to: ', self.downloadTo
|
171
|
+
#print 'download rate: ', self.downRate
|
172
|
+
#print 'upload rate: ', self.upRate
|
173
|
+
#print 'share rating: ', self.shareRating
|
174
|
+
#print 'seed status: ', self.seedStatus
|
175
|
+
#print 'peer status: ', self.peerStatus
|
176
|
+
#stdout.flush()
|
177
|
+
dpflag.set()
|
178
|
+
|
179
|
+
def chooseFile(self, default, size, saveas, dir):
|
180
|
+
self.file = '%s (%.1f MB)' % (default, float(size) / (1 << 20))
|
181
|
+
if saveas != '':
|
182
|
+
default = saveas
|
183
|
+
self.downloadTo = abspath(default)
|
184
|
+
return default
|
185
|
+
|
186
|
+
def newpath(self, path):
|
187
|
+
self.downloadTo = path
|
188
|
+
|
189
|
+
def run(params):
|
190
|
+
cols = 80
|
191
|
+
|
192
|
+
h = HeadlessDisplayer()
|
193
|
+
while 1:
|
194
|
+
configdir = ConfigDir('downloadheadless')
|
195
|
+
defaultsToIgnore = ['responsefile', 'url', 'priority']
|
196
|
+
configdir.setDefaults(defaults,defaultsToIgnore)
|
197
|
+
configdefaults = configdir.loadConfig()
|
198
|
+
defaults.append(('save_options',0,
|
199
|
+
"whether to save the current options as the new default configuration " +
|
200
|
+
"(only for btdownloadheadless.py)"))
|
201
|
+
try:
|
202
|
+
config = parse_params(params, configdefaults)
|
203
|
+
except ValueError, e:
|
204
|
+
print 'error: ' + str(e) + '\nrun with no args for parameter explanations'
|
205
|
+
break
|
206
|
+
if not config:
|
207
|
+
print get_usage(defaults, 80, configdefaults)
|
208
|
+
break
|
209
|
+
if config['save_options']:
|
210
|
+
configdir.saveConfig(config)
|
211
|
+
configdir.deleteOldCacheData(config['expire_cache_data'])
|
212
|
+
|
213
|
+
myid = createPeerID()
|
214
|
+
seed(myid)
|
215
|
+
|
216
|
+
global doneFlag
|
217
|
+
doneFlag = Event()
|
218
|
+
def disp_exception(text):
|
219
|
+
print text
|
220
|
+
rawserver = RawServer(doneFlag, config['timeout_check_interval'],
|
221
|
+
config['timeout'], ipv6_enable = config['ipv6_enabled'],
|
222
|
+
failfunc = h.failed, errorfunc = disp_exception)
|
223
|
+
upnp_type = UPnP_test(config['upnp_nat_access'])
|
224
|
+
while True:
|
225
|
+
try:
|
226
|
+
listen_port = rawserver.find_and_bind(config['minport'], config['maxport'],
|
227
|
+
config['bind'], ipv6_socket_style = config['ipv6_binds_v4'],
|
228
|
+
upnp = upnp_type, randomizer = config['random_port'])
|
229
|
+
break
|
230
|
+
except socketerror, e:
|
231
|
+
if upnp_type and e == UPnP_ERROR:
|
232
|
+
print 'WARNING: COULD NOT FORWARD VIA UPnP'
|
233
|
+
upnp_type = 0
|
234
|
+
continue
|
235
|
+
print "error: Couldn't listen - " + str(e)
|
236
|
+
h.failed()
|
237
|
+
return
|
238
|
+
|
239
|
+
response = get_response(config['responsefile'], config['url'], h.error)
|
240
|
+
if not response:
|
241
|
+
break
|
242
|
+
|
243
|
+
infohash = sha(bencode(response['info'])).digest()
|
244
|
+
|
245
|
+
dow = BT1Download(h.display, h.finished, h.error, disp_exception, doneFlag,
|
246
|
+
config, response, infohash, myid, rawserver, listen_port,
|
247
|
+
configdir)
|
248
|
+
|
249
|
+
if not dow.saveAs(h.chooseFile, h.newpath):
|
250
|
+
break
|
251
|
+
|
252
|
+
if not dow.initFiles(old_style = True):
|
253
|
+
break
|
254
|
+
if not dow.startEngine():
|
255
|
+
dow.shutdown()
|
256
|
+
break
|
257
|
+
dow.startRerequester()
|
258
|
+
dow.autoStats()
|
259
|
+
|
260
|
+
if not dow.am_I_finished():
|
261
|
+
h.display(activity = 'connecting to peers')
|
262
|
+
rawserver.listen_forever(dow.getPortHandler())
|
263
|
+
h.display(activity = 'shutting down')
|
264
|
+
dow.shutdown()
|
265
|
+
break
|
266
|
+
try:
|
267
|
+
rawserver.shutdown()
|
268
|
+
except:
|
269
|
+
pass
|
270
|
+
if not h.done:
|
271
|
+
h.failed()
|
272
|
+
|
273
|
+
if __name__ == '__main__':
|
274
|
+
|
275
|
+
if len(argv) != 5:
|
276
|
+
print "Incorrect number of arguments"
|
277
|
+
print
|
278
|
+
print """Usage:
|
279
|
+
python murder_client.py peer/seed out.torrent OUT.OUT 127.0.0.1
|
280
|
+
|
281
|
+
The last parameter is the local ip address, normally 10.x.x.x
|
282
|
+
"""
|
283
|
+
sys.exit(1)
|
284
|
+
|
285
|
+
argv = ["--responsefile", sys.argv[2],
|
286
|
+
"--saveas", sys.argv[3],
|
287
|
+
"--ip", sys.argv[4]]
|
288
|
+
|
289
|
+
isPeer = sys.argv[1] == "peer"
|
290
|
+
|
291
|
+
run(argv[1:])
|
@@ -0,0 +1,46 @@
|
|
1
|
+
# Copyright 2010 Twitter, Inc.
|
2
|
+
# Copyright 2010 Larry Gadea <lg@twitter.com>
|
3
|
+
#
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
5
|
+
# not use this file except in compliance with the License. You may obtain
|
6
|
+
# a copy of the License at
|
7
|
+
#
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
9
|
+
#
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
12
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
13
|
+
# See the License for the specific language governing permissions and
|
14
|
+
# limitations under the License.
|
15
|
+
|
16
|
+
# Usage: python murder_make_torrent.py <file> <trackerhost:port> <target>
|
17
|
+
# Usage: python murder_make_torrent.py deploy.tar.gz tracker.twitter.com:8998 deploy.torrent
|
18
|
+
|
19
|
+
import warnings
|
20
|
+
warnings.filterwarnings('ignore', category=DeprecationWarning)
|
21
|
+
|
22
|
+
from sys import argv, version, exit
|
23
|
+
from os.path import split
|
24
|
+
assert version >= '2', "Install Python 2.0 or greater"
|
25
|
+
from BitTornado.BT1.makemetafile import make_meta_file
|
26
|
+
|
27
|
+
if __name__ == '__main__':
|
28
|
+
|
29
|
+
if len(argv) != 4:
|
30
|
+
print "Incorrect number of arguments"
|
31
|
+
print
|
32
|
+
print """Usage:
|
33
|
+
python murder_make_torrent.py <file> <trackerhost:port> <target>
|
34
|
+
|
35
|
+
For example:
|
36
|
+
python murder_make_torrent.py deploy.tar.gz tracker.twitter.com:8998 deploy.torrent
|
37
|
+
"""
|
38
|
+
exit(1)
|
39
|
+
|
40
|
+
try:
|
41
|
+
params = {}
|
42
|
+
params["target"] = argv[3]
|
43
|
+
make_meta_file(argv[1], "http://" + argv[2] + "/announce", params)
|
44
|
+
except ValueError, e:
|
45
|
+
print str(e)
|
46
|
+
exit(1)
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# Copyright 2010 Twitter, Inc.
|
2
|
+
# Copyright 2010 Larry Gadea <lg@twitter.com>
|
3
|
+
#
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
5
|
+
# not use this file except in compliance with the License. You may obtain
|
6
|
+
# a copy of the License at
|
7
|
+
#
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
9
|
+
#
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
12
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
13
|
+
# See the License for the specific language governing permissions and
|
14
|
+
# limitations under the License.
|
15
|
+
|
16
|
+
# Usage: python murder_tracker.py <optionalparams>
|
17
|
+
# Usage: python murder_tracker.py
|
18
|
+
|
19
|
+
import warnings
|
20
|
+
warnings.filterwarnings('ignore', category=DeprecationWarning)
|
21
|
+
|
22
|
+
from BitTornado.BT1.track import track
|
23
|
+
from sys import argv
|
24
|
+
|
25
|
+
if __name__ == '__main__':
|
26
|
+
args = ["--dfile", "data",
|
27
|
+
"--port", "8998"] + argv[1:]
|
28
|
+
track(args)
|