bittorrent-curses.py

来自「bittorrent source by python. please enj」· Python 代码 · 共 629 行 · 第 1/2 页

PY
629
字号
            if self.spew_scroll_pos > len(spew):                self.spew_scroll_pos = 0            for i in range(len(spew)):                spew[i]['lineno'] = i+1            spew.append({'lineno': None})            spew = spew[self.spew_scroll_pos:] + spew[:self.spew_scroll_pos]            for i in range(min(self.spewh - 5, len(spew))):                if not spew[i]['lineno']:                    continue                self.spewwin.addnstr(i+3, 0, '%3d' % spew[i]['lineno'], 3)                self.spewwin.addnstr(i+3, 4, spew[i]['ip'], 15)                ul = spew[i]['upload']                if ul[1] > 100:                    self.spewwin.addnstr(i+3, 20, '%6.0f KB/s' % (                        ul[1] / 1000), 11)                self.spewwin.addnstr(i+3, 32, '-----', 5)                if ul[2]:                    self.spewwin.addnstr(i+3, 33, 'I', 1)                if ul[3]:                    self.spewwin.addnstr(i+3, 35, 'C', 1)                dl = spew[i]['download']                if dl[1] > 100:                    self.spewwin.addnstr(i+3, 38, '%6.0f KB/s' % (                        dl[1] / 1000), 11)                self.spewwin.addnstr(i+3, 50, '-------', 7)                if dl[2]:                    self.spewwin.addnstr(i+3, 51, 'I', 1)                if dl[3]:                    self.spewwin.addnstr(i+3, 53, 'C', 1)                if dl[4]:                    self.spewwin.addnstr(i+3, 55, 'S', 1)                self.spewwin.addnstr(i+3, 58,                    '%5.1f%%' % (int(spew[i]['completed']*1000)/10), 6)                if spew[i]['speed'] is not None:                    self.spewwin.addnstr(i+3, 64,                        '%5.0f KB/s' % (spew[i]['speed']/1000), 10)            """            self.spewwin.addnstr(self.spewh-1, 0,                    _("downloading %d pieces, have %d fragments, "                      "%d of %d pieces completed") %                    (statistics['storage_active'], statistics['storage_dirty'],                     statistics['storage_numcomplete'], self.numpieces),                    self.speww-1)            """        curses.panel.update_panels()        curses.doupdate()class CursesTorrentApp(object):    class LogHandler(logging.Handler):        def __init__(self, app, level=logging.NOTSET):            logging.Handler.__init__(self,level)            self.app = app              def emit(self, record):            if len(record.getMessage()) > 0:                self.app.display_error(record.getMessage() )             if record.exc_info is not None:                self.app.display_error(                    "Traceback (most recent call last):" )                tb = record.exc_info[2]                stack = traceback.extract_tb(tb)                l = traceback.format_list(stack)                for s in l:                    self.app.display_error( " %s" % s )                self.app.display_error( " %s: %s" %                    ( str(record.exc_info[0]),str(record.exc_info[1])))    class LogFilter(logging.Filter):        def filter( self, record):            if record.name == "NatTraversal":                return 0            return 1  # allow.            def __init__(self, metainfo, config, errlist):        assert isinstance(metainfo, ConvertedMetainfo )        self.metainfo = metainfo        self.config = Preferences().initWithDict(config)        self.errlist = errlist        self.torrent = None        self.multitorrent = None        self.d = None    # displayer (i.e., curses UI)        self.logger = logging.getLogger("bittorrent-curses")        log_handler = CursesTorrentApp.LogHandler(self)        log_handler.setLevel(WARNING)        #log_handler.setLevel(0)        logger = logging.getLogger()        logger.addHandler(log_handler)        # disable stdout and stderr error reporting.        global stderr_console        logging.getLogger().removeHandler(console)        if stderr_console is not None:          logging.getLogger().removeHandler(stderr_console)                                                   # We log everything.  If we want to omit certain errors then        # either raise the level or install a logging.Filter:        log_handler.addFilter(CursesTorrentApp.LogFilter())        logging.getLogger().setLevel(WARNING)        #logging.getLogger().setLevel(0)    def start_torrent(self,metainfo,save_incomplete_as,save_as):        """Tells the MultiTorrent to begin downloading."""        try:            self.d.display({'activity':_("initializing"),                                'fractionDone':0})            multitorrent = self.multitorrent            df = multitorrent.create_torrent(metainfo, save_incomplete_as,                                             save_as)            df.addErrback( wrap_log('Failed to start torrent', self.logger))            def create_finished(*args, **argv):                self.torrent = multitorrent.get_torrent(metainfo.infohash)                if self.torrent.is_initialized():                   multitorrent.start_torrent(metainfo.infohash)                else:                   self.d.display({'activity':_("already being downloaded"),                                'fractionDone':0})                   self.core_doneflag.set()  # e.g., if already downloading...            df.addCallback( create_finished )        except KeyboardInterrupt:            raise        except UserFailure, e:            self.logger.error( "Failed to create torrent: " + unicode(e.args[0]) )        except Exception, e:            self.logger.error( "Failed to create torrent", exc_info = e )            def run(self, scrwin):        self.core_doneflag = DeferredEvent()        rawserver = RawServer(self.config)        # set up shut-down procedure before we begin doing things that        # can throw exceptions.        def shutdown():            if self.d:                self.d.display({'activity':_("shutting down"),                             'fractionDone':0})            if self.multitorrent:                df = self.multitorrent.shutdown()                set_flag = lambda *a : rawserver.stop()                df.addCallbacks(set_flag, set_flag)            else:                rawserver.stop()                                # It is safe to addCallback here, because there is only one thread,        # but even if the code were multi-threaded, core_doneflag has not        # been passed to anyone.  There is no chance of a race condition        # between the DeferredEvent'scallback and addCallback.        self.core_doneflag.addCallback(            lambda r: rawserver.external_add_task(0, shutdown))                def reread():            if self.multitorrent is not None:                rawserver.external_add_task(0,self.reread_config)        def ulrate(value):            if self.multitorrent is not None:                self.multitorrent.set_option('max_upload_rate', value)            if self.torrent != None:                self.torrent.set_option('max_upload_rate', value)        self.d = CursesDisplayer(scrwin, self.errlist, self.core_doneflag,                                  reread, ulrate)        rawserver.install_sigint_handler(self.core_doneflag)        # semantics for --save_in vs --save_as:        #   save_in specifies the directory in which torrent is written.        #      If the torrent is a batch torrent then the files in the batch        #      go in save_in/metainfo.name_fs/.        #   save_as specifies the filename for the torrent in the case of        #      a non-batch torrent, and specifies the directory name        #      in the case of a batch torrent.  Thus the files in a batch        #      torrent go in save_as/.        metainfo = self.metainfo        torrent_name = metainfo.name_fs  # if batch then this contains                                         # directory name.        if config['save_as']:            if config['save_in']:                raise BTFailure(_("You cannot specify both --save_as and "                                  "--save_in."))            saveas,bad = platform.encode_for_filesystem(config['save_as'])            if bad:                raise BTFailure(_("Invalid path encoding."))            savein = os.path.dirname(os.path.abspath(saveas))        elif config['save_in']:            savein,bad = platform.encode_for_filesystem(config['save_in'])            if bad:                raise BTFailure(_("Invalid path encoding."))            saveas = os.path.join(savein,torrent_name)        else:            saveas = torrent_name        if config['save_incomplete_in']:            save_incomplete_in,bad = \                platform.encode_for_filesystem(config['save_incomplete_in'])            if bad:                raise BTFailure(_("Invalid path encoding."))            save_incomplete_as = os.path.join(save_incomplete_in,torrent_name)        else:            save_incomplete_as = os.path.join(savein,torrent_name)            data_dir,bad = platform.encode_for_filesystem(config['data_dir'])        if bad:            raise BTFailure(_("Invalid path encoding."))        try:            self.multitorrent = \                MultiTorrent(self.config, rawserver, data_dir,                             is_single_torrent = True,                             resume_from_torrent_config = False)                           self.d.set_torrent_values(metainfo.name, os.path.abspath(saveas),                                metainfo.total_bytes, len(metainfo.hashes))            self.start_torrent(self.metainfo, save_incomplete_as, saveas)                    self.get_status()        except UserFailure, e:            self.logger.error( unicode(e.args[0]) )            rawserver.add_task(0,core_doneflag.set())        except Exception, e:            self.logger.error( "", exc_info = e )            rawserver.add_task(0,core_doneflag.set())                # always make sure events get processed even if only for        # shutting down.        rawserver.listen_forever()    def reread_config(self):        try:            newvalues = configfile.get_config(self.config, 'bittorrent-curses')        except Exception, e:            self.d.error(_("Error reading config: ") + unicode(e.args[0]))            return        self.config.update(newvalues)        # The set_option call can potentially trigger something that kills        # the torrent (when writing this the only possibility is a change in        # max_files_open causing an IOError while closing files), and so        # the self.failed() callback can run during this loop.        for option, value in newvalues.iteritems():            self.multitorrent.set_option(option, value)        if self.torrent is not None:            for option, value in newvalues.iteritems():                self.torrent.set_option(option, value)    def get_status(self):        self.multitorrent.rawserver.add_task(self.config['display_interval'],                                             self.get_status)        if self.torrent is not None:            status = self.torrent.get_status(self.config['spew'])            self.d.display(status)        def display_error(self, text):        """Called by the logger via LogHandler to display error messages in the           curses window."""        self.d.error(text)if __name__ == '__main__':    uiname = 'bittorrent-curses'    defaults = get_defaults(uiname)    metainfo = None    if len(sys.argv) <= 1:        printHelp(uiname, defaults)        sys.exit(1)    try:        # Modifying default values from get_defaults is annoying...        # Implementing specific default values for each uiname in        # defaultargs.py is even more annoying.  --Dave        data_dir = [[name, value,doc] for (name, value, doc) in defaults                        if name == "data_dir"][0]        defaults = [(name, value,doc) for (name, value, doc) in defaults                        if not name == "data_dir"]                ddir = os.path.join( platform.get_dot_dir(), "curses" )        data_dir[1] = decode_from_filesystem(ddir)        defaults.append( tuple(data_dir) )        config, args = configfile.parse_configuration_and_args(defaults,                                       uiname, sys.argv[1:], 0, 1)        torrentfile = None        if len(args):            torrentfile = args[0]        if torrentfile is not None:            try:                metainfo = GetTorrent.get(torrentfile)            except GetTorrent.GetTorrentException, e:                raise UserFailure(_("Error reading .torrent file: ") + '\n' + \                                unicode(e.args[0]))        else:            raise UserFailure(_("you must specify a .torrent file"))    except BTFailure, e:        print unicode(e.args[0])        sys.exit(1)    errlist = []    app = CursesTorrentApp(metainfo, config, errlist)    curses_wrapper(app.run)    if errlist:        print _("These errors occurred during execution:")        for error in errlist:            print error        sys.stdout.flush()            # if after a reasonable amount of time there are still    # non-daemon threads hanging around then print them.    nondaemons = [d for d in threading.enumerate() if not d.isDaemon()]    if len(nondaemons) > 1:       sleep(4)       nondaemons = [d for d in threading.enumerate() if not d.isDaemon()]       if len(nondaemons) > 1:           print "non-daemon threads not shutting down:"           for th in nondaemons:               print " ", th

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?