From: <sir...@us...> - 2003-03-02 16:32:19
|
Update of /cvsroot/btplusplus/BT++/src In directory sc8-pr-cvs1:/tmp/cvs-serv15671/src Added Files: LoaderManager.py Loader.py Log Message: Moved the Loader + Manager, they are not specific to TabTrans. --- NEW FILE: LoaderManager.py --- from os import listdir, path from ConfigFile import ConfigFile, Config from Loader import Loader from core.CurrentRateMeasure import GlobalMeasure from BTConstants import * class LoaderManager: Loaders = [] def __init__(self, refresh = None, log = None): self.Log = log self.Refresh = refresh self.UpMeasure = GlobalMeasure( 20.0, # MAX RATE PERIOD, 5.0 ) # UPLOAD RATE FUDGE def CreateNewLoader(self, torrent): try: loader = Loader(torrent, self.UpMeasure, self.Refresh, self.Log) self.Loaders.append( loader ) try: self.Log( 'Added torrent "' + torrent + '"...', loglevel = LOG_INFO ) except: pass except: try: self.Log( 'Error adding torrent "' + torrent + '"...', loglevel = LOG_ERROR ) except: pass ########################################################################################################### ########################################################################################################### def GetNumLoading(self): cnt = 0 for loader in self.Loaders: if loader.IsRunning(): cnt = cnt + 1 return cnt def GetNumHashing(self): cnt = 0 for loader in self.Loaders: if loader.IsHashing(): cnt = cnt + 1 return cnt def GetUpSpeed(self): speed = 0 for loader in self.Loaders: speed += loader.Info['SpeedUp'] return speed def GetDownSpeed(self): speed = 0 for loader in self.Loaders: speed += loader.Info['SpeedDown'] return speed def GetNumLoaders(self): return len(self.Loaders) def GetNumConnections(self): con = 0 for loader in self.Loaders: con = con + loader.GetNumConnections() return con def GetDownloader(self, num): return self.Loaders[num] ########################################################################################################### ########################################################################################################### def Move(self, frm, to): if to < 0 or to > len(self.Loaders) - 1: return self.Loaders[to:to] = [self.Loaders[frm]] if frm > to: del self.Loaders[frm+1] else: del self.Loaders[frm] FilesConf = ConfigFile() FilesConf.Read('files.ini') FilesConf.DelSection('ActiveOrder') for num in range(len(self.Loaders)): FilesConf.Set('ActiveOrder', '%03d' % num, self.Loaders[num].Config['Tor']) FilesConf.Save() ########################################################################################################### ########################################################################################################### def GetInfo(self, num, name): try: return self.Loaders[num].Info[name] except: pass ########################################################################################################### ########################################################################################################### def Update(self): self.UpdateList() self.UpdateDownloads() self.UpdateHashing() ########################################################################################################### ########################################################################################################### def UpdateList(self): # UPDATE TORRENT LIST tors = listdir( Config.Get('Paths', 'Torrent') ) if len(tors) == 0: return FilesConf = ConfigFile() FilesConf.Read('files.ini') order = FilesConf.GetOptions('ActiveOrder') order.sort() new = [] for key in order: value = FilesConf.Get('ActiveOrder',key) con = false if value == '' or not path.exists( path.join(Config.Get('Paths', 'Torrent'), value) ): FilesConf.DelOption('ActiveOrder', key) for l in self.Loaders: if l.Config['Tor'] == value: l.PauseDownload() self.Loaders.remove(l) con = true for loader in self.Loaders: if loader.Config['Tor'] == value: con = true if con == true: continue new.append(key) for tor in tors: con = false for loader in self.Loaders: if loader.Config['Tor'] == tor: con = true for key in new: value = FilesConf.Get('ActiveOrder',key) if value == tor: con = true if con == true: continue if order == []: nid = 0 else: nid = int(order[len(order)-1]) + 1 FilesConf.Set('ActiveOrder', '%03d' % nid, tor) order.append('%03d' % nid) for num in new: tor = FilesConf.Get('ActiveOrder',num) self.CreateNewLoader(tor) FilesConf.Save() ########################################################################################################### ########################################################################################################### def UpdateDownloads(self): # START NEW DOWNLOADS dwcnt = self.GetNumLoading() dwsta = Config.Get('Download', 'AutoStart') dwmax = Config.Get('Download', 'MaxSimDown') if dwsta == 1 and dwcnt < dwmax: dwcnt = dwmax - dwcnt for loader in self.Loaders: if dwcnt <= 0: break if not loader.IsRunning() and not loader.IsFinished(): dwcnt = dwcnt - 1 loader.StartDownload() # PAUSE DOWNLOADS dwcnt = self.GetNumLoading() dwpau = Config.Get('Download', 'AutoPause') if dwpau == 1 and dwcnt > dwmax: dwcnt = dwcnt - dwmax tmp = self.self.Loaders tmp.reverse() for loader in tmp: if dwcnt <= 0: break if loader.IsRunning(): dwcnt = dwcnt - 1 loader.PauseDownload() ########################################################################################################### ########################################################################################################### def UpdateHashing(self): # START HASHING hscnt = self.GetNumHashing() hssta = Config.Get('Hash', 'Background') hsmax = Config.Get('Hash', 'NumSimHash') if hssta == 1 and hscnt < hsmax: hscnt = hsmax - hscnt for loader in self.Loaders: if hscnt <= 0: break if not loader.IsHashing() and not loader.HasHashed(): hscnt = hscnt - 1 loader.StartHashing() ########################################################################################################### ########################################################################################################### def Destroy(self): for loader in self.Loaders: loader.Destroy() --- NEW FILE: Loader.py --- from ConfigFile import Config, ConfigFile from BTConstants import * from os import remove, rename, path, getpid, path, makedirs from threading import Event, Thread from time import time, sleep from random import seed from sha import sha from socket import error as socketerror from core.Choker import Choker from core.Storage import Storage from core.StorageWrapper import StorageWrapper from core.Uploader import Upload from core.Downloader import Downloader from core.Connecter import Connecter from core.Encrypter import Encrypter from core.RawServer import RawServer from core.Rerequester import Rerequester from core.DownloaderFeedback import DownloaderFeedback from core.RateMeasure import RateMeasure from core.CurrentRateMeasure import Measure, GlobalMeasure from core.EndgameDownloader import EndgameDownloader from core.PiecePicker import PiecePicker from core.bencode import bencode, bdecode ########################################################################################################### ########################################################################################################### class Loader: def __init__(self, torrent, globup, refresh = None, log = None): self.Refresh = refresh self.Log = log self.FlagEnd = Event() self.FlagHash = Event() self.Hashed = false self.Paused = true self.Finished = false self.FlagEnd.clear() self.FlagHash.clear() self.Info = {} self.Config = {} self.Obj = {} self.Obj['GlobalUpMeasure'] = globup if self.Init(torrent) == false: raise self.ThrHashing = Thread( target = self.ProcessFiles ) self.ThrHashing.setDaemon(false) ########################################################################################################### ########################################################################################################### def Init(self, tor): self.UpdateStatus( fractionDone = -1, timeEst = -1, downRate = 0, upRate = 0, activity = 'Paused' ) self.Config['Tor'] = tor self.Config['TorFull'] = path.join(Config.Get('Paths', 'Torrent'), tor) try: h = open(self.Config['TorFull'], 'rb') torrent = h.read() torrent = bdecode(torrent) torinfo = torrent['info'] h.close() except: return false self.Config['Tracker'] = torrent['announce'] self.Config['File'] = torinfo['name'] self.Config['Filename'] = path.join(Config.Get('Paths', 'Temp'), torinfo['name']) self.Config['Pieces'] = torinfo['pieces'] self.Config['PiecesLen'] = torinfo['piece length'] self.Config['InfoHash'] = sha(bencode(torinfo)).digest() self.Config['MyId'] = sha(repr(time()) + ' ' + str(getpid())).digest() seed(self.Config['MyId']) if torinfo.has_key('length'): self.Config['NumFiles'] = 1 self.Config['Size'] = torinfo['length'] else: self.Config['Files'] = [] self.Config['Size'] = 0 self.Config['NumFiles'] = 0 for item in torinfo['files']: self.Config['NumFiles'] += 1 self.Config['Size'] += item['length'] file = path.join(Config.Get('Paths', 'Temp'), self.Config['File']) for p in item['path']: file = path.join(file, p) self.Config['Files'].append( { 'File': item['path'][len(item['path'])-1], 'Filename': file, 'Size': item['length'] } ) self.Info['Size'] = self.Config['Size'] self.Info['File'] = self.Config['File'] return true ########################################################################################################### ########################################################################################################### def StartHashing(self): self.ThrHashing.start() self.OnTrivialInfo('Hashing started') def StartDownload( self ): if self.Hashed == false: self.StartHashing() self.FlagEnd.clear() self.Paused = false self.ThrDownload = Thread( target = self.Download ) self.ThrDownload.setDaemon(false) self.ThrDownload.start() self.OnTrivialInfo('Download started') def PauseDownload( self ): if self.ThrHashing.isAlive(): self.FlagHash.clear() self.Hashed = false self.FlagEnd.set() self.Paused = true self.UpdateStatus( timeEst = -1, downRate = 0, upRate = 0, activity = 'Paused' ) self.OnTrivialInfo('Download Paused') ########################################################################################################### ########################################################################################################### def Destroy(self): self.FlagEnd.set() ########################################################################################################### ########################################################################################################### def IsRunning(self): return not self.Paused def IsFinished(self): return self.Finished def IsHashing(self): return self.ThrHashing.isAlive() def HasHashed(self): return self.Hashed ########################################################################################################### ########################################################################################################### def GetNumConnections(self): try: return self.Obj['Connecter'].how_many_connections() except: return 0 ########################################################################################################### ########################################################################################################### def UpdateStatus(self, fractionDone = None, timeEst = None, downRate = None, upRate = None, activity = None): if fractionDone != None: if fractionDone == -1: self.Info['FractionDone'] = -1 self.Info['FractionRemain'] = -1 else: self.Info['FractionDone'] = fractionDone self.Info['FractionRemain'] = 1 - fractionDone if timeEst != None: self.Info['TimeEst'] = timeEst self.Info['ETA'] = self.ETA(timeEst) if activity != None: self.Info['Status'] = activity if downRate != None: self.Info['SpeedDown'] = float(downRate) / (1 << 10) if upRate != None: self.Info['SpeedUp'] = float(upRate) / (1 << 10) try: self.Refresh() except: pass ########################################################################################################### ########################################################################################################### def ETA( self, n ): if n == -1: return '?' if n == 0: return '' n = int(n) d, r = divmod(n, 60 * 60 * 24) h, r = divmod(r, 60 * 60) m, s = divmod(r, 60) if h > 1000000: return '?' if d > 0: return '%d d %02d h %02d min' % (d, h, m) if h > 0: return '%02d h %02d min' % (h, m) else: return '%d min %02d sec' % (m, s) ########################################################################################################### ########################################################################################################### def OnFinish(self, finfunc = None, finflag = None, ann = None, storage = None, errorfunc = None): self.PauseDownload() self.Finished = true self.Hashed = true self.UpdateStatus( fractionDone = 1, timeEst = 0, downRate = 0, upRate = 0, activity = 'Done' ) try: self.Obj['Storage'].close() rename( self.Config['Filename'], path.join(Config.Get('Paths','Incoming'), self.Config['File']) ) except: self.OnError('Could not move downloaded file.') try: rename( self.Config['TorFull'], path.join(Config.Get('Paths','History'), self.Config['Tor']) ) self.OnInfo( 'Download complete' ) except: self.OnError('Could not move torrent.') def OnFail(self, reason, errorfunc = None, doneflag = None): try: self.Log( 'Failed [' + self.Config['File'] + ']: ' + reason, loglevel = LOG_CRITICAL) except: pass def OnError(self, ErrorMsg): try: self.Log( 'Error [' + self.Config['File'] + ']: ' + ErrorMsg, loglevel = LOG_ERROR) except: pass def OnInfo(self, Info): try: self.Log( '[' + self.Config['File'] + ']: ' + Info, loglevel = LOG_INFO) except: pass def OnTrivialInfo(self, Info): try: self.Log( '[' + self.Config['File'] + ']: ' + Info, loglevel = LOG_TRIVIAL) except: pass ########################################################################################################### ########################################################################################################### def ProcessFiles(self): try: def make(f, forcedir = false): if not forcedir: f = path.split(f)[0] if f != '' and not path.exists(f): makedirs(f) if self.Config['NumFiles'] == 1: file = self.Config['Filename'] size = self.Config['Size'] make(file) files = [(file, size)] else: size = self.Config['Size'] file = self.Config['Filename'] if not path.exists(file): make(file, true) files = [] for f in self.Config['Files']: files.append((f['Filename'], f['Size'])) make( f['Filename'] ) except: self.OnError("Couldn't allocate.") return self.Config['Pieces'] = [self.Config['Pieces'][x:x+20] for x in xrange(0, len(self.Config['Pieces']), 20)] try: self.Obj['Storage'] = \ Storage( files, open, path.exists, path.getsize, self.UpdateStatus, 0.0 ) except: self.OnError("Trouble creating Storage.") return # Not sure why it won't work without that sleep(2.0) if self.FlagEnd.isSet(): return try: self.Obj['StorageWrapper'] = \ StorageWrapper( self.Obj['Storage'], (2 ** 14), # DOWNLOAD SLICE SIZE self.Config['Pieces'], self.Config['PiecesLen'], self.OnFinish, self.OnFail, self.UpdateStatus, self.FlagEnd, 1 ) # HASHING except: self.OnError('Trouble creating StorageWrapper.') return if not self.FlagEnd.isSet(): done = 1.0 - float(self.Obj['StorageWrapper'].get_amount_left()) / float(self.Config['Size']) self.UpdateStatus( fractionDone = done, activity = 'Paused' ) self.FlagHash.set() self.Hashed = true self.OnTrivialInfo('Hashing complete') ########################################################################################################### ########################################################################################################### def Download(self): while 1: self.FlagHash.wait(2.0) if not self.ThrHashing.isAlive(): break if self.FlagEnd.isSet() or self.Hashed == false or self.Finished == true: return self.Obj['RawServer'] = \ RawServer( self.FlagEnd, 60.0, # TIMEOUT CHECK INTERVAL 300.0 ) # TIMEOUT minport = Config.Get('Bind', 'PortMin') maxport = Config.Get('Bind', 'PortMax') for listen_port in xrange(minport, maxport + 1): try: self.Obj['RawServer'].bind(listen_port, Config.Get('Bind','Ip')) break except socketerror, e: pass else: self.FlagEnd.set() self.Paused = true self.OnError("Couldn't bind to - " + str(e)) return self.Obj['Choker'] = \ Choker( 4, # MAX UPLOADS, self.Obj['RawServer'].add_task ) self.Obj['UpMeasure'] = \ Measure( 20.0, # MAX RATE PERIOD, 5.0 ) # UPLOAD RATE FUDGE self.Obj['DownMeasure'] = \ Measure( 20.0 ) # MAX RATE PERIOD def make_upload( connection, choker = self.Obj['Choker'], storagewrapper = self.Obj['StorageWrapper'], max_slice_length = (2 ** 17), # MAX SLICE LENGTH max_rate_period = 20.0, # MAX RATE PERIOD fudge = 5.0 ): # UPLOAD RATE FUDGE return Upload( connection, choker, storagewrapper, max_slice_length, max_rate_period, fudge ) self.Obj['RateMeasure'] = \ RateMeasure( self.Obj['StorageWrapper'].get_amount_left() ) self.Obj['Downloader'] = \ Downloader( self.Obj['StorageWrapper'], PiecePicker( len(self.Config['Pieces']) ), 5, # REQUEST BACKLOG, 20.0, # MAX RATE PERIOD len(self.Config['Pieces']), self.Obj['DownMeasure'], 60.0, # SNUB TIME self.Obj['RateMeasure'].data_came_in ) self.Obj['Connecter'] = \ Connecter( make_upload, self.Obj['Downloader'], self.Obj['Choker'], len(self.Config['Pieces']), self.Obj['StorageWrapper'].is_everything_pending, EndgameDownloader, self.Obj['GlobalUpMeasure'], self.Obj['UpMeasure'], (Config.Get('Download','MaxSpeedUp') * 1024), # MAX UPLOAD RATE self.Obj['RawServer'].add_task ) self.Obj['Encrypter'] = \ Encrypter( self.Obj['Connecter'], self.Obj['RawServer'], self.Config['MyId'], (2 ** 23), # MAX MESSAGE LENGTH self.Obj['RawServer'].add_task, 120.0, # KEEPALIVE INTERVAL self.Config['InfoHash'], 40 ) # MAX INITIATE self.Obj['Rerequester'] = \ Rerequester( self.Config['Tracker'], (5 * 60), # REREQUEST INTERVAL self.Obj['RawServer'].add_task, self.Obj['Connecter'].how_many_connections, 20, # MIN PEERS self.Obj['Encrypter'].start_connection, self.Obj['RawServer'].external_add_task, self.Obj['StorageWrapper'].get_amount_left, self.Obj['UpMeasure'].get_total, self.Obj['DownMeasure'].get_total, listen_port, '', # IP self.Config['MyId'], self.Config['InfoHash'], 60, # HTTP TIMEOUT, self.OnError ) self.Obj['DownloaderFeedback'] = \ DownloaderFeedback( self.Obj['Choker'], self.Obj['RawServer'].add_task, self.UpdateStatus, self.Obj['UpMeasure'].get_rate, self.Obj['DownMeasure'].get_rate, self.Obj['RateMeasure'].get_time_left, self.Obj['RateMeasure'].get_size_left, self.Config['Size'], self.FlagEnd, 2.0 ) # DISPLAY INTERVAL self.UpdateStatus(activity = 'Downloading') self.Obj['Rerequester'].d(0) self.Obj['RawServer'].listen_forever( self.Obj['Encrypter'] ) self.Obj['Rerequester'].announce(2) |