~ubuntu-branches/ubuntu/oneiric/bittornado/oneiric

« back to all changes in this revision

Viewing changes to .pc/25_errors_in_error_handling.dpatch/btdownloadheadless.py

  • Committer: Bazaar Package Importer
  • Author(s): Cameron Dale
  • Date: 2010-03-21 14:36:30 UTC
  • Revision ID: james.westby@ubuntu.com-20100321143630-d1zk1zdasaf8125s
Tags: 0.3.18-10
* New patch from upstream's CVS to allow torrents that only have an
  announce list: 30_announce_list_only_torrents.dpatch (Closes: #551766)
* Fix a lot of lintian warnings
  - Update standards version to 3.8.4 (no changes)
* Fix for when compact_reqd is turned off:
  31_fix_for_compact_reqd_off.dpatch (Closes: #574860)
* Switch to the new "3.0 (quilt)" source format

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#!/usr/bin/env python
 
2
 
 
3
# Written by Bram Cohen
 
4
# see LICENSE.txt for license information
 
5
 
 
6
from BitTornado import PSYCO
 
7
if PSYCO.psyco:
 
8
    try:
 
9
        import psyco
 
10
        assert psyco.__version__ >= 0x010100f0
 
11
        psyco.full()
 
12
    except:
 
13
        pass
 
14
    
 
15
from BitTornado.download_bt1 import BT1Download, defaults, parse_params, get_usage, get_response
 
16
from BitTornado.RawServer import RawServer, UPnP_ERROR
 
17
from random import seed
 
18
from socket import error as socketerror
 
19
from BitTornado.bencode import bencode
 
20
from BitTornado.natpunch import UPnP_test
 
21
from threading import Event
 
22
from os.path import abspath
 
23
from sys import argv, stdout
 
24
import sys
 
25
from sha import sha
 
26
from time import strftime
 
27
from BitTornado.clock import clock
 
28
from BitTornado import createPeerID, version
 
29
from BitTornado.ConfigDir import ConfigDir
 
30
 
 
31
assert sys.version >= '2', "Install Python 2.0 or greater"
 
32
try:
 
33
    True
 
34
except:
 
35
    True = 1
 
36
    False = 0
 
37
 
 
38
PROFILER = False
 
39
 
 
40
def hours(n):
 
41
    if n == 0:
 
42
        return 'complete!'
 
43
    try:
 
44
        n = int(n)
 
45
        assert n >= 0 and n < 5184000  # 60 days
 
46
    except:
 
47
        return '<unknown>'
 
48
    m, s = divmod(n, 60)
 
49
    h, m = divmod(m, 60)
 
50
    if h > 0:
 
51
        return '%d hour %02d min %02d sec' % (h, m, s)
 
52
    else:
 
53
        return '%d min %02d sec' % (m, s)
 
54
 
 
55
class HeadlessDisplayer:
 
56
    def __init__(self):
 
57
        self.done = False
 
58
        self.file = ''
 
59
        self.percentDone = ''
 
60
        self.timeEst = ''
 
61
        self.downloadTo = ''
 
62
        self.downRate = ''
 
63
        self.upRate = ''
 
64
        self.shareRating = ''
 
65
        self.seedStatus = ''
 
66
        self.peerStatus = ''
 
67
        self.errors = []
 
68
        self.last_update_time = -1
 
69
 
 
70
    def finished(self):
 
71
        self.done = True
 
72
        self.percentDone = '100'
 
73
        self.timeEst = 'Download Succeeded!'
 
74
        self.downRate = ''
 
75
        self.display()
 
76
 
 
77
    def failed(self):
 
78
        self.done = True
 
79
        self.percentDone = '0'
 
80
        self.timeEst = 'Download Failed!'
 
81
        self.downRate = ''
 
82
        self.display()
 
83
 
 
84
    def error(self, errormsg):
 
85
        self.errors.append(errormsg)
 
86
        self.display()
 
87
 
 
88
    def display(self, dpflag = Event(), fractionDone = None, timeEst = None, 
 
89
            downRate = None, upRate = None, activity = None,
 
90
            statistics = None,  **kws):
 
91
        if self.last_update_time + 0.1 > clock() and fractionDone not in (0.0, 1.0) and activity is not None:
 
92
            return
 
93
        self.last_update_time = clock()        
 
94
        if fractionDone is not None:
 
95
            self.percentDone = str(float(int(fractionDone * 1000)) / 10)
 
96
        if timeEst is not None:
 
97
            self.timeEst = hours(timeEst)
 
98
        if activity is not None and not self.done:
 
99
            self.timeEst = activity
 
100
        if downRate is not None:
 
101
            self.downRate = '%.1f kB/s' % (float(downRate) / (1 << 10))
 
102
        if upRate is not None:
 
103
            self.upRate = '%.1f kB/s' % (float(upRate) / (1 << 10))
 
104
        if statistics is not None:
 
105
           if (statistics.shareRating < 0) or (statistics.shareRating > 100):
 
106
               self.shareRating = 'oo  (%.1f MB up / %.1f MB down)' % (float(statistics.upTotal) / (1<<20), float(statistics.downTotal) / (1<<20))
 
107
           else:
 
108
               self.shareRating = '%.3f  (%.1f MB up / %.1f MB down)' % (statistics.shareRating, float(statistics.upTotal) / (1<<20), float(statistics.downTotal) / (1<<20))
 
109
           if not self.done:
 
110
              self.seedStatus = '%d seen now, plus %.3f distributed copies' % (statistics.numSeeds,0.001*int(1000*statistics.numCopies))
 
111
           else:
 
112
              self.seedStatus = '%d seen recently, plus %.3f distributed copies' % (statistics.numOldSeeds,0.001*int(1000*statistics.numCopies))
 
113
           self.peerStatus = '%d seen now, %.1f%% done at %.1f kB/s' % (statistics.numPeers,statistics.percentDone,float(statistics.torrentRate) / (1 << 10))
 
114
        print '\n\n\n\n'
 
115
        for err in self.errors:
 
116
            print 'ERROR:\n' + err + '\n'
 
117
        print 'saving:        ', self.file
 
118
        print 'percent done:  ', self.percentDone
 
119
        print 'time left:     ', self.timeEst
 
120
        print 'download to:   ', self.downloadTo
 
121
        print 'download rate: ', self.downRate
 
122
        print 'upload rate:   ', self.upRate
 
123
        print 'share rating:  ', self.shareRating
 
124
        print 'seed status:   ', self.seedStatus
 
125
        print 'peer status:   ', self.peerStatus
 
126
        stdout.flush()
 
127
        dpflag.set()        
 
128
 
 
129
    def chooseFile(self, default, size, saveas, dir):
 
130
        self.file = '%s (%.1f MB)' % (default, float(size) / (1 << 20))
 
131
        if saveas != '':
 
132
            default = saveas
 
133
        self.downloadTo = abspath(default)
 
134
        return default
 
135
 
 
136
    def newpath(self, path):
 
137
        self.downloadTo = path
 
138
 
 
139
def run(params):
 
140
    try:
 
141
        import curses
 
142
        curses.initscr()
 
143
        cols = curses.COLS
 
144
        curses.endwin()
 
145
    except:
 
146
        cols = 80
 
147
 
 
148
    h = HeadlessDisplayer()
 
149
    while 1:
 
150
        configdir = ConfigDir('downloadheadless')
 
151
        defaultsToIgnore = ['responsefile', 'url', 'priority']
 
152
        configdir.setDefaults(defaults,defaultsToIgnore)
 
153
        configdefaults = configdir.loadConfig()
 
154
        defaults.append(('save_options',0,
 
155
         "whether to save the current options as the new default configuration " +
 
156
         "(only for btdownloadheadless.py)"))
 
157
        try:
 
158
            config = parse_params(params, configdefaults)
 
159
        except ValueError, e:
 
160
            print 'error: ' + str(e) + '\nrun with no args for parameter explanations'
 
161
            break
 
162
        if not config:
 
163
            print get_usage(defaults, 80, configdefaults)
 
164
            break
 
165
        if config['save_options']:
 
166
            configdir.saveConfig(config)
 
167
        configdir.deleteOldCacheData(config['expire_cache_data'])
 
168
 
 
169
        myid = createPeerID()
 
170
        seed(myid)
 
171
        
 
172
        doneflag = Event()
 
173
        def disp_exception(text):
 
174
            print text
 
175
        rawserver = RawServer(doneflag, config['timeout_check_interval'],
 
176
                              config['timeout'], ipv6_enable = config['ipv6_enabled'],
 
177
                              failfunc = h.failed, errorfunc = disp_exception)
 
178
        upnp_type = 0
 
179
        while True:
 
180
            try:
 
181
                listen_port = rawserver.find_and_bind(config['minport'], config['maxport'],
 
182
                                config['bind'], ipv6_socket_style = config['ipv6_binds_v4'],
 
183
                                upnp = upnp_type, randomizer = config['random_port'])
 
184
                break
 
185
            except socketerror, e:
 
186
                if upnp_type and e == UPnP_ERROR:
 
187
                    print 'WARNING: COULD NOT FORWARD VIA UPnP'
 
188
                    upnp_type = 0
 
189
                    continue
 
190
                print "error: Couldn't listen - " + str(e)
 
191
                h.failed()
 
192
                return
 
193
 
 
194
        response = get_response(config['responsefile'], config['url'], h.error)
 
195
        if not response:
 
196
            break
 
197
 
 
198
        infohash = sha(bencode(response['info'])).digest()
 
199
 
 
200
        dow = BT1Download(h.display, h.finished, h.error, disp_exception, doneflag,
 
201
                        config, response, infohash, myid, rawserver, listen_port,
 
202
                        configdir)
 
203
        
 
204
        if not dow.saveAs(h.chooseFile, h.newpath):
 
205
            break
 
206
 
 
207
        if not dow.initFiles(old_style = True):
 
208
            break
 
209
        if not dow.startEngine():
 
210
            dow.shutdown()
 
211
            break
 
212
        dow.startRerequester()
 
213
        dow.autoStats()
 
214
 
 
215
        if not dow.am_I_finished():
 
216
            h.display(activity = 'connecting to peers')
 
217
        rawserver.listen_forever(dow.getPortHandler())
 
218
        h.display(activity = 'shutting down')
 
219
        dow.shutdown()
 
220
        break
 
221
    try:
 
222
        rawserver.shutdown()
 
223
    except:
 
224
        pass
 
225
    if not h.done:
 
226
        h.failed()
 
227
 
 
228
if __name__ == '__main__':
 
229
    if argv[1:] == ['--version']:
 
230
        print version
 
231
        sys.exit(0)
 
232
 
 
233
    if PROFILER:
 
234
        import profile, pstats
 
235
        p = profile.Profile()
 
236
        p.runcall(run, argv[1:])
 
237
        log = open('profile_data.'+strftime('%y%m%d%H%M%S')+'.txt','a')
 
238
        normalstdout = sys.stdout
 
239
        sys.stdout = log
 
240
#        pstats.Stats(p).strip_dirs().sort_stats('cumulative').print_stats()
 
241
        pstats.Stats(p).strip_dirs().sort_stats('time').print_stats()
 
242
        sys.stdout = normalstdout
 
243
    else:
 
244
        run(argv[1:])