class FancyDownloadGauge(SimpleDownloadGauge): def __init__(self, *args, **kwargs): self.resolution = 1000 self.grouped = DictWithLists() self.missing_known = False self.last_time = bttime() self.last_update = -1 SimpleDownloadGauge.__init__(self, *args, **kwargs) self.transfering_color = self.gauge_theme["transferring color"] self.missing_color = self.gauge_theme["missing color"] self.SetValue(None, redraw=False) def gradient(self, v): if v == 0: if self.missing_known: c = self.missing_color else: c = self.gauge_theme["rare colors"][0] else: v = min(v, len(self.gauge_theme["rare colors"])) c = self.gauge_theme["rare colors"][v - 1] return c def invalidate(self): self.last_time = 0 def SetValue(self, percent, state=None, data=None, redraw=True): # only draw if progress moved .01% or it's been REFRESH_MAX_SEC seconds if self.percent != None: if (percent < (self.percent + 0.0001) and bttime() < (self.last_time + REFRESH_MAX_SEC)): return self.last_time = bttime() if not redraw: return p_dirty = False if self.percent != percent: p_dirty = True self.percent = percent missing_known = state == "running" if self.missing_known != missing_known: p_dirty = True self.missing_known = missing_known if not data: # no data. allow future SetValues to continue passing # until we get something self.last_time = 0 - REFRESH_MAX_SEC # draw an empty bar data = (0, -1, {}) length, update, piece_states = data self.resolution = length if p_dirty or update != self.last_update: self.grouped = piece_states self.redraw() self.last_update = update def draw_bar(self, dc, rect): # size events can catch this if self.percent is None: return y1 = rect.y w = rect.width h = rect.height if self.resolution <= 0: return # sort, so we get 0...N, h, t keys = self.grouped.keys() keys.sort() for k in keys: v = self.grouped[k] if k == 'h': c = self.completed_color elif k == 't': c = self.transfering_color else: c = self.gradient(k) dc.SetPen(wx.TRANSPARENT_PEN) dc.SetBrush(wx.Brush(c)) def draw(b, e): b = float(b) e = float(e) r = float(self.resolution) x1 = (b / r) * w x2 = (e / r) * w # stupid floats x1 = int(rect.x + x1) x2 = int(rect.x + x2) dc.DrawRectangle(x1, y1, x2 - x1, h) if isinstance(v, SparseSet): for (b, e) in v.iterrange(): draw(b, e) elif isinstance(v, dict): for b in v.iterkeys(): draw(b, b + 1) elif isinstance(v, set): #for b in v: # draw(b, b + 1) # maybe this is better? (fewer rectangles) l = list(v) l.sort() for (b, e) in collapse(l): draw(b, e) else: # assumes sorted! for (b, e) in collapse(v): draw(b, e)
class FilePool(object): def __init__(self, doneflag, add_task, external_add_task, max_files_open, num_disk_threads): self.add_task = add_task self.file_to_torrent = {} self.waiting_ops = [] self.active_file_to_handles = DictWithSets() self.open_file_to_handles = DictWithLists() self.set_max_files_open(max_files_open) def close_all(self): df = Deferred() self._close_all(df) return df def _close_all(self, df): failures = {} while len(self.open_file_to_handles) > 0: filename, handle = self.open_file_to_handles.popitem() try: handle.close() except: failures[self.file_to_torrent[filename]] = Failure() for torrent, failure in failures.iteritems(): torrent.got_exception(failure) if self.get_open_file_count() > 0: # it would be nice to wait on the deferred for the outstanding ops self.add_task(0.5, self._close_all, df) else: df.callback(True) def close_files(self, file_set): df = Deferred() self._close_files(df, file_set) return df def _close_files(self, df, file_set): failure = None done = False filenames = self.open_file_to_handles.keys() for filename in filenames: if filename not in file_set: continue handles = self.open_file_to_handles.poprow(filename) for handle in handles: try: handle.close() except: failure = Failure() done = True for filename in file_set.iterkeys(): if filename in self.active_file_to_handles: done = False break if failure is not None: df.errback(failure) if not done: # it would be nice to wait on the deferred for the outstanding ops self.add_task(0.5, self._close_files, df, file_set) else: df.callback(True) def set_max_files_open(self, max_files_open): if max_files_open <= 0: max_files_open = 1e100 self.max_files_open = max_files_open self.close_all() def add_files(self, files, torrent): for filename in files: if filename in self.file_to_torrent: raise BTFailure(_("File %s belongs to another running torrent") % filename) for filename in files: self.file_to_torrent[filename] = torrent def remove_files(self, files): for filename in files: del self.file_to_torrent[filename] def _ensure_exists(self, filename, length=0): if not os.path.exists(filename): f = os.path.split(filename)[0] if f != '' and not os.path.exists(f): os.makedirs(f) f = file(filename, 'wb') make_file_sparse(filename, f, length) f.close() def get_open_file_count(self): t = self.open_file_to_handles.total_length() t += self.active_file_to_handles.total_length() return t def free_handle_notify(self): if self.waiting_ops: args = self.waiting_ops.pop(0) self._produce_handle(*args) def acquire_handle(self, filename, for_write, length=0): df = Deferred() if filename not in self.file_to_torrent: raise UnregisteredFileException() if self.active_file_to_handles.total_length() == self.max_files_open: self.waiting_ops.append((df, filename, for_write, length)) else: self._produce_handle(df, filename, for_write, length) return df def _produce_handle(self, df, filename, for_write, length): if filename in self.open_file_to_handles: handle = self.open_file_to_handles.pop_from_row(filename) if for_write and not is_open_for_write(handle.mode): handle.close() handle = open_sparse_file(filename, 'rb+', length=length) #elif not for_write and is_open_for_write(handle.mode): # handle.close() # handle = file(filename, 'rb', 0) else: if self.get_open_file_count() == self.max_files_open: oldfname, oldhandle = self.open_file_to_handles.popitem() oldhandle.close() self._ensure_exists(filename, length) if for_write: handle = open_sparse_file(filename, 'rb+', length=length) else: handle = open_sparse_file(filename, 'rb', length=length) self.active_file_to_handles.push_to_row(filename, handle) df.callback(handle) def release_handle(self, filename, handle): self.active_file_to_handles.remove_fom_row(filename, handle) self.open_file_to_handles.push_to_row(filename, handle) self.free_handle_notify()
class FancyDownloadGauge(SimpleDownloadGauge): def __init__(self, *args, **kwargs): self.resolution = 1000 self.grouped = DictWithLists() self.missing_known = False self.last_time = bttime() self.last_update = -1 SimpleDownloadGauge.__init__(self, *args, **kwargs) self.transfering_color = self.gauge_theme["transferring color"] self.missing_color = self.gauge_theme["missing color"] self.SetValue(None, redraw=False) def gradient(self, v): if v == 0: if self.missing_known: c = self.missing_color else: c = self.gauge_theme["rare colors"][0] else: v = min(v, len(self.gauge_theme["rare colors"])) c = self.gauge_theme["rare colors"][v - 1] return c def invalidate(self): self.last_time = 0 def SetValue(self, percent, state = None, data = None, redraw=True): # only draw if progress moved .01% or it's been REFRESH_MAX_SEC seconds if self.percent != None: if (percent < (self.percent + 0.0001) and bttime() < (self.last_time + REFRESH_MAX_SEC)): return self.last_time = bttime() if not redraw: return p_dirty = False if self.percent != percent: p_dirty = True self.percent = percent missing_known = state == "running" if self.missing_known != missing_known: p_dirty = True self.missing_known = missing_known if not data: # no data. allow future SetValues to continue passing # until we get something self.last_time = 0 - REFRESH_MAX_SEC # draw an empty bar data = (0, -1, {}) length, update, piece_states = data self.resolution = length if p_dirty or update != self.last_update: self.grouped = piece_states self.redraw() self.last_update = update def draw_bar(self, dc, rect): # size events can catch this if self.percent is None: return y1 = rect.y w = rect.width h = rect.height if self.resolution <= 0: return # sort, so we get 0...N, h, t keys = self.grouped.keys() keys.sort() for k in keys: v = self.grouped[k] if k == 'h': c = self.completed_color elif k == 't': c = self.transfering_color else: c = self.gradient(k) dc.SetPen(wx.TRANSPARENT_PEN) dc.SetBrush(wx.Brush(c)) def draw(b, e): b = float(b) e = float(e) r = float(self.resolution) x1 = (b / r) * w x2 = (e / r) * w # stupid floats x1 = int(rect.x + x1) x2 = int(rect.x + x2) dc.DrawRectangle(x1, y1, x2 - x1, h) if isinstance(v, SparseSet): for (b, e) in v.iterrange(): draw(b, e) elif isinstance(v, dict): for b in v.iterkeys(): draw(b, b + 1) elif isinstance(v, set): #for b in v: # draw(b, b + 1) # maybe this is better? (fewer rectangles) l = list(v) l.sort() for (b, e) in collapse(l): draw(b, e) else: # assumes sorted! for (b, e) in collapse(v): draw(b, e)