📄 fileselector.py
字号:
# Written by John Hoffman# see LICENSE.txt for license informationfrom random import shufflefrom traceback import print_exctry: Trueexcept: True = 1 False = 0class FileSelector: def __init__(self, files, piece_length, bufferdir, storage, storagewrapper, sched, failfunc): self.files = files self.storage = storage self.storagewrapper = storagewrapper self.sched = sched self.failfunc = failfunc self.downloader = None self.picker = None storage.set_bufferdir(bufferdir) self.numfiles = len(files) self.priority = [1] * self.numfiles self.new_priority = None self.new_partials = None self.filepieces = [] total = 0L for file, length in files: if not length: self.filepieces.append(()) else: pieces = range( int(total/piece_length), int((total+length-1)/piece_length)+1 ) self.filepieces.append(tuple(pieces)) total += length self.numpieces = int((total+piece_length-1)/piece_length) self.piece_priority = [1] * self.numpieces def init_priority(self, new_priority): try: assert len(new_priority) == self.numfiles for v in new_priority: assert type(v) in (type(0),type(0L)) assert v >= -1 assert v <= 2 except:# print_exc() return False try: files_updated = False for f in xrange(self.numfiles): if new_priority[f] < 0: self.storage.disable_file(f) files_updated = True if files_updated: self.storage.reset_file_status() self.new_priority = new_priority except (IOError, OSError), e: self.failfunc("can't open partial file for " + self.files[f][0] + ': ' + str(e)) return False return True ''' d['priority'] = [file #1 priority [,file #2 priority...] ] a list of download priorities for each file. Priority may be -1, 0, 1, 2. -1 = download disabled, 0 = highest, 1 = normal, 2 = lowest. Also see Storage.pickle and StorageWrapper.pickle for additional keys. ''' def unpickle(self, d): if d.has_key('priority'): if not self.init_priority(d['priority']): return pieces = self.storage.unpickle(d) if not pieces: # don't bother, nothing restoreable return new_piece_priority = self._get_piece_priority_list(self.new_priority) self.storagewrapper.reblock([i == -1 for i in new_piece_priority]) self.new_partials = self.storagewrapper.unpickle(d, pieces) def tie_in(self, picker, cancelfunc, requestmorefunc, rerequestfunc): self.picker = picker self.cancelfunc = cancelfunc self.requestmorefunc = requestmorefunc self.rerequestfunc = rerequestfunc if self.new_priority: self.priority = self.new_priority self.new_priority = None self.new_piece_priority = self._set_piece_priority(self.priority) if self.new_partials: shuffle(self.new_partials) for p in self.new_partials: self.picker.requested(p) self.new_partials = None def _set_files_disabled(self, old_priority, new_priority): old_disabled = [p == -1 for p in old_priority] new_disabled = [p == -1 for p in new_priority] data_to_update = [] for f in xrange(self.numfiles): if new_disabled[f] != old_disabled[f]: data_to_update.extend(self.storage.get_piece_update_list(f)) buffer = [] for piece, start, length in data_to_update: if self.storagewrapper.has_data(piece): data = self.storagewrapper.read_raw(piece, start, length) if data is None: return False buffer.append((piece, start, data)) files_updated = False try: for f in xrange(self.numfiles): if new_disabled[f] and not old_disabled[f]: self.storage.disable_file(f) files_updated = True if old_disabled[f] and not new_disabled[f]: self.storage.enable_file(f) files_updated = True except (IOError, OSError), e: if new_disabled[f]: msg = "can't open partial file for " else: msg = 'unable to open ' self.failfunc(msg + self.files[f][0] + ': ' + str(e)) return False if files_updated: self.storage.reset_file_status() changed_pieces = {} for piece, start, data in buffer: if not self.storagewrapper.write_raw(piece, start, data): return False data.release() changed_pieces[piece] = 1 if not self.storagewrapper.doublecheck_data(changed_pieces): return False return True def _get_piece_priority_list(self, file_priority_list): l = [-1] * self.numpieces for f in xrange(self.numfiles): if file_priority_list[f] == -1: continue for i in self.filepieces[f]: if l[i] == -1: l[i] = file_priority_list[f] continue l[i] = min(l[i],file_priority_list[f]) return l def _set_piece_priority(self, new_priority): was_complete = self.storagewrapper.am_I_complete() new_piece_priority = self._get_piece_priority_list(new_priority) pieces = range(self.numpieces) shuffle(pieces) new_blocked = [] new_unblocked = [] for piece in pieces: self.picker.set_priority(piece,new_piece_priority[piece]) o = self.piece_priority[piece] == -1 n = new_piece_priority[piece] == -1 if n and not o: new_blocked.append(piece) if o and not n: new_unblocked.append(piece) if new_blocked: self.cancelfunc(new_blocked) self.storagewrapper.reblock([i == -1 for i in new_piece_priority]) if new_unblocked: self.requestmorefunc(new_unblocked) if was_complete and not self.storagewrapper.am_I_complete(): self.rerequestfunc() return new_piece_priority def set_priorities_now(self, new_priority = None): if not new_priority: new_priority = self.new_priority self.new_priority = None # potential race condition if not new_priority: return old_priority = self.priority self.priority = new_priority if not self._set_files_disabled(old_priority, new_priority): return self.piece_priority = self._set_piece_priority(new_priority) def set_priorities(self, new_priority): self.new_priority = new_priority self.sched(self.set_priorities_now) def set_priority(self, f, p): new_priority = self.get_priorities() new_priority[f] = p self.set_priorities(new_priority) def get_priorities(self): priority = self.new_priority if not priority: priority = self.priority # potential race condition return [i for i in priority] def __setitem__(self, index, val): self.set_priority(index, val) def __getitem__(self, index): try: return self.new_priority[index] except: return self.priority[index] def finish(self): for f in xrange(self.numfiles): if self.priority[f] == -1: self.storage.delete_file(f) def pickle(self): d = {'priority': self.priority} try: s = self.storage.pickle() sw = self.storagewrapper.pickle() for k in s.keys(): d[k] = s[k] for k in sw.keys(): d[k] = sw[k] except (IOError, OSError): pass return d
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -