[ create a new paste ] login | about

Link: http://codepad.org/DaNBembL    [ raw code | fork ]

meigrafd - Python, pasted on Feb 12:
class Queue_Manager(threading.Thread):
    def __init__(self, connection, delay=network['announce_delay']):
        threading.Thread.__init__(self)
        self.setDaemon(1)
        self.connection = connection
        self.delay = delay
        self.event = threading.Event()
        self.queue = []
    
    def run(self):
        while 1:
            self.event.wait()
            while self.queue:
                (msg, target) = self.queue.pop(0)
                try:
                    self.connection.privmsg(target, msg)
                except irclib.ServerNotConnectedError as error:
                    print(error)
                    
                time.sleep(self.delay)
            self.event.clear()
    
    def send(self, msg, target):
        self.queue.append((msg.strip(), target))
        self.event.set()


class ReconnectStrategy(object):
    min_interval = 60
    max_interval = 300
    
    def __init__(self, **attrs):
        vars(self).update(attrs)
        assert 0 <= self.min_interval <= self.max_interval
        self._check_scheduled = False
        self.attempt_count = itertools.count(1)

    def run(self, bot):
        self.bot = bot
        
        if self._check_scheduled:
            return
        
        # calculate interval in seconds based on connection attempts
        intvl = 2**next(self.attempt_count) - 1
        
        # limit the max interval
        intvl = min(intvl, self.max_interval)
        
        # add jitter and truncate to integer seconds
        intvl = int(intvl * random.random())
        
        # limit the min interval
        intvl = max(intvl, self.min_interval)
        
        self.bot.reactor.scheduler.execute_after(intvl, self.check)
        self._check_scheduled = True
    
    def check(self):
        self._check_scheduled = False
        if not self.bot.connection.is_connected():
            self.run(self.bot)
            self.bot.jump_server()


class _feedie(SimpleIRCClient):
    def __init__(self):
        irclib.SimpleIRCClient.__init__(self)
        self.start_time = time.time()
        self.queue = Queue_Manager(self.connection)
        self.reconnection_interval = 10
        self.channels = utils.IrcDict()
        self.recon = ReconnectStrategy(min_interval=self.reconnection_interval)
        self.urlShorter = utils.URLShortener(feedie['shorten_service'])
        self.lastRequest = {}
        self.cachedFeeds = {}
    
    
    def on_welcome(self, serv, ev):
        if network['password']:
            serv.privmsg("nickserv", "IDENTIFY {}".format(network['password']))
            serv.privmsg("chanserv", "SET irc_auto_rejoin ON")
            serv.privmsg("chanserv", "SET irc_join_delay 0")
        
        for name in feeds[0]:
            if not feeds[0][name]['enabled']:
                continue
            try:
                serv.join(feeds[0][name]['channel'], key=feeds[0][name]['channel_key'])
            except:
                serv.join(feeds[0][name]['channel'])
        
        try:
            self.history_manager()
            time.sleep(2)
            self.queue.start()

            self.initFeedRefreshTimers()

        except (OSError, IOError) as error:
            serv.disconnect()
            print(error)
            sys.exit(1)
    
    
    def on_rss_entry(self, chan=None, text=''):
        if chan:
            self.queue.send(text, chan)
        else:
            for name in feeds[0]:
                self.queue.send(text, feeds[0][name]['channel'])
    
    
    def mircColor(self, s, fg=None, bg=None):
        """Returns s with the appropriate mIRC color codes applied."""
        if fg is None and bg is None:
            return s
        elif bg is None:
            fg = mircColors[str(fg)]
            return '\x03%s%s\x03' % (fg.zfill(2), s)
        elif fg is None:
            bg = mircColors[str(bg)]
            # According to the mirc color doc, a fg color MUST be specified if a
            # background color is specified.  So, we'll specify 00 (white) if the
            # user doesn't specify one.
            return '\x0300,%s%s\x03' % (bg.zfill(2), s)
        else:
            fg = mircColors[str(fg)]
            bg = mircColors[str(bg)]
            # No need to zfill fg because the comma delimits.
            return '\x03%s,%s%s\x03' % (fg, bg.zfill(2), s)
    
    
    def _getConverter(self, feed):
        toText = utils.htmlToText
        if 'encoding' in feed:
            return lambda s: toText(s).strip().encode(feed['encoding'], 'replace')
        else:
            return lambda s: toText(s).strip()
    
    
    def getHeadlines(self, feed):
        headlines = []
        conv = self._getConverter(feed)
        for d in feed['items']:
            if 'title' in d:
                title = conv(d['title'])
                link = d.get('link')
                if link:
                    headlines.append((title, link))
                else:
                    headlines.append((title, None))
        return headlines
    
    
    def getFeed(self, url):
        def error(s):
            return {'items': [{'title': s}]}
        try:
            #print('Downloading new feed from %u' % url)
            results = feedparser.parse(url)
            if 'bozo_exception' in results:
                raise results['bozo_exception']
        except sgmllib.SGMLParseError:
            return error('Invalid (unparsable) RSS feed.')
        except socket.timeout:
            return error('Timeout downloading feed.')
        except Exception, e:
            # These seem mostly harmless.  We'll need reports of a kind that isn't.
            print('Allowing bozo_exception "%r" through.' % e)
        if results.get('feed', {}):
            self.cachedFeeds[url] = results
            self.lastRequest[url] = time.time()
        else:
            print('Not caching results; feed is empty.')
        try:
            return self.cachedFeeds[url]
        except KeyError:
            # If there's a problem retrieving the feed, we should back off
            # for a little bit before retrying so that there is time for
            # the error to be resolved.
            self.lastRequest[url] = time.time() - .5 * 180
            return error('Unable to download feed.')
    
    
    def initFeedRefreshTimers(self):
        for feed in feeds:
            for name in feed:
                if not feed[name]['enabled']:
                    continue
                try:
                    refresh_time = feed[name]['refresh_delay']
                except KeyError:
                    refresh_time = network['default_refresh_delay']
                threading.Timer(refresh_time, self.feed_refresh, (feed,name,refresh_time,)).start()
    
    
    def feed_refresh(self, feed, name, refresh_time):
        url = feed[name]['url']
        try:
            oldresults = self.cachedFeeds[url]
            oldheadlines = self.getHeadlines(oldresults)
        except KeyError:
            oldheadlines = []
        
        if not network['startup_announces'] and not oldheadlines:
            newresults = self.getFeed(url)
            threading.Timer(refresh_time, self.feed_refresh, (feed,name,refresh_time,)).start()
            return
        else:
            newresults = self.getFeed(url)
            newheadlines = self.getHeadlines(newresults)
        
        if len(newheadlines) == 1:
            s = newheadlines[0][0]
            if s in ('Timeout downloading feed.', 'Unable to download feed.'):
                print('%s %u', s, url)
                threading.Timer(refresh_time, self.feed_refresh, (feed,name,refresh_time,)).start()
                return
        
        def canonize(headline):
            return (tuple(headline[0].lower().split()), headline[1])
        
        oldheadlines = set(map(canonize, oldheadlines))
        
        for (i, headline) in enumerate(newheadlines):
            if canonize(headline) in oldheadlines:
                newheadlines[i] = None
        newheadlines = filter(None, newheadlines) # Removes Nones.
        
        if newheadlines:
            for headline in newheadlines:
                if headline[1]:
                    title = headline[0]
                    short_url = self.urlShorter.shorten_url(headline[1])
                    if not short_url or short_url == 'Error': short_url = url
                    feedName = self.mircColor(name, feed[name]['color'])
                    feedTitle = self.mircColor(title, 'blue')
                    try:
                        chan = feed[name]['channel']
                    except KeyError:
                        # send to all channels
                        chan = None
                    self.on_rss_entry(chan=chan, text='{0} {1} {2}'.format(feedName, feedTitle, self.underline(short_url)))
        threading.Timer(refresh_time, self.feed_refresh, (feed,name,refresh_time,)).start()


Create a new paste based on this one


Comments: