From 152ef2a1ad5efca10eb3c274d02dcd4901782ec0 Mon Sep 17 00:00:00 2001 From: "Brian S. Stephan" Date: Mon, 20 Jun 2011 21:18:55 -0500 Subject: [PATCH] Module: remove the timer stuff, since individual modules can do this better themselves Markov, Twitter: switch to forking a thread ourselves, and check every second whether or not to quit. this is the "better" part above, as now we can instantly quit the thread rather than waiting for all the timers to fire and expire --- Module.py | 29 --------------------- modules/Markov.py | 43 +++++++++++++++++-------------- modules/Twitter.py | 63 +++++++++++++++++++++++++--------------------- 3 files changed, 58 insertions(+), 77 deletions(-) diff --git a/Module.py b/Module.py index 16070d8..e2bccff 100644 --- a/Module.py +++ b/Module.py @@ -32,11 +32,6 @@ class Module(object): def priority(self): return 50 - def timer_interval(self): - """Run a timer-based event every N seconds (0 to disable).""" - - return 0 - def __init__(self, irc, config, server): """Construct a feature module. Inheritors can do special things here, but should be sure to call Module.__init__. @@ -62,10 +57,6 @@ class Module(object): # set up database for this module self.db_init() - # register the timer, if the implementing module has one - if self.timer_interval() > 0: - Timer(self.timer_interval(), self.timer_bootstrap, ()).start() - # print what was loaded, for debugging print("loaded " + self.__class__.__name__) @@ -242,26 +233,6 @@ class Module(object): print("looks like someone forgot to implement do!") - def timer_bootstrap(self): - """Run a thread that does something periodically. - - This only has real functionality if timer_interval() is - defined to return non-zero. - """ - - # don't actually do stuff if, since the last timer registration, - # the interval was set to 0 - if self.timer_interval() > 0 and self.is_shutdown == False: - self.timer_do() - - if self.timer_interval() > 0 and self.is_shutdown == False: - Timer(self.timer_interval(), self.timer_bootstrap, ()).start() - - def timer_do(self): - """If we're invoking the timer, do something (that you should implement).""" - - print("looks like someone forgot to implement timer_do!") - def help_description(self): """Return a quick list of commands or other summary, should be less than two lines. If you want the module hidden from "!help", diff --git a/modules/Markov.py b/modules/Markov.py index 7187b35..a0fa7c1 100644 --- a/modules/Markov.py +++ b/modules/Markov.py @@ -23,6 +23,8 @@ import random import re import sqlite3 import sys +import thread +import time from dateutil.parser import * from dateutil.relativedelta import * @@ -42,10 +44,6 @@ class Markov(Module): http://code.activestate.com/recipes/194364-the-markov-chain-algorithm/ """ - def timer_interval(self): - """Do various conversation scoring and infinite reply checks.""" - return 30 - def __init__(self, irc, config, server): """Create the Markov chainer, and learn text from a file if available.""" @@ -69,6 +67,9 @@ class Markov(Module): Module.__init__(self, irc, config, server) + self.next_shut_up_check = 0 + thread.start_new_thread(self.thread_do, ()) + def db_init(self): """Create the markov chain table.""" @@ -280,30 +281,34 @@ class Markov(Module): self.lines_seen.append(('.self.said.', datetime.now())) return self._generate_line(target, min_size=min_size, max_size=max_size) - def timer_do(self): + def thread_do(self): """Do various things.""" - self._do_shut_up_checks() + while not self.is_shutdown: + self._do_shut_up_checks() + time.sleep(1) def _do_shut_up_checks(self): """Check to see if we've been talking too much, and shut up if so.""" - self.shut_up = False + if self.next_shut_up_check < time.time(): + self.shut_up = False + self.next_shut_up_check = time.time() + 30 - last_30_sec_lines = [] + last_30_sec_lines = [] - for (nick,then) in self.lines_seen: - rdelta = relativedelta(datetime.now(), then) - if rdelta.years == 0 and rdelta.months == 0 and rdelta.days == 0 and rdelta.hours == 0 and rdelta.minutes == 0 and rdelta.seconds <= 29: - last_30_sec_lines.append((nick,then)) + for (nick,then) in self.lines_seen: + rdelta = relativedelta(datetime.now(), then) + if rdelta.years == 0 and rdelta.months == 0 and rdelta.days == 0 and rdelta.hours == 0 and rdelta.minutes == 0 and rdelta.seconds <= 29: + last_30_sec_lines.append((nick,then)) - if len(last_30_sec_lines) >= 15: - lines_i_said = len(filter(lambda (a,b): a == '.self.said.', last_30_sec_lines)) - if lines_i_said >= 8: - self.shut_up = True - targets = self._get_chatter_targets() - for t in targets: - self.sendmsg(self.connection, t, 'shutting up for 30 seconds due to last 30 seconds of activity') + if len(last_30_sec_lines) >= 15: + lines_i_said = len(filter(lambda (a,b): a == '.self.said.', last_30_sec_lines)) + if lines_i_said >= 8: + self.shut_up = True + targets = self._get_chatter_targets() + for t in targets: + self.sendmsg(self.connection, t, 'shutting up for 30 seconds due to last 30 seconds of activity') def _learn_line(self, line, target): """Create Markov chains from the provided line.""" diff --git a/modules/Twitter.py b/modules/Twitter.py index 38c204f..d80c1d5 100644 --- a/modules/Twitter.py +++ b/modules/Twitter.py @@ -20,7 +20,8 @@ from ConfigParser import NoSectionError, NoOptionError import oauth2 as oauth import re import sqlite3 -from threading import Timer +import thread +import time import urlparse from extlib import irclib @@ -32,11 +33,6 @@ class Twitter(Module): """Access Twitter via the bot as an authenticated client.""" - def timer_interval(self): - """Check for twitter updates every 300 seconds.""" - - return 300 - def __init__(self, irc, config, server): """Prepare for oauth stuff (but don't execute it yet).""" @@ -72,6 +68,9 @@ class Twitter(Module): self.twit = twitter.Api() self.authed = False + self.next_timeline_check = 0 + thread.start_new_thread(self.thread_do, ()) + def db_init(self): """Set up the settings table.""" @@ -239,39 +238,45 @@ class Twitter(Module): return 'The bot is now logged in.' - def timer_do(self): + def thread_do(self): """Check the timeline.""" - self._check_self_timeline() + + while not self.is_shutdown: + self._check_self_timeline() + time.sleep(1) def _check_self_timeline(self): """Check my timeline, and if there are entries, print them to the channel.""" - if self.authed: - # get the id of the last check we made - since_id = self._get_last_since_id() - output_channel = self._get_output_channel() + if self.next_timeline_check < time.time(): + self.next_timeline_check = time.time() + 300 - if since_id is not None and output_channel != '': - tweets = self.twit.GetFriendsTimeline(since_id=since_id) - tweets.reverse() - for tweet in tweets: - tweet_text = self._return_tweet_or_retweet_text(tweet=tweet, print_source=True) - self.sendmsg(self.connection, output_channel.encode('utf-8', 'ignore'), tweet_text) + if self.authed: + # get the id of the last check we made + since_id = self._get_last_since_id() + output_channel = self._get_output_channel() - # friends timeline printed, find the latest id - new_since_id = self._get_latest_tweet_id(tweets, since_id) + if since_id is not None and output_channel != '': + tweets = self.twit.GetFriendsTimeline(since_id=since_id) + tweets.reverse() + for tweet in tweets: + tweet_text = self._return_tweet_or_retweet_text(tweet=tweet, print_source=True) + self.sendmsg(self.connection, output_channel.encode('utf-8', 'ignore'), tweet_text) - tweets = self.twit.GetMentions(since_id=since_id) - tweets.reverse() - for tweet in tweets: - tweet_text = self._return_tweet_or_retweet_text(tweet=tweet, print_source=True) - self.sendmsg(self.connection, output_channel.encode('utf-8', 'ignore'), tweet_text) + # friends timeline printed, find the latest id + new_since_id = self._get_latest_tweet_id(tweets, since_id) - # mentions printed, find the latest id - new_since_id = self._get_latest_tweet_id(tweets, new_since_id) + tweets = self.twit.GetMentions(since_id=since_id) + tweets.reverse() + for tweet in tweets: + tweet_text = self._return_tweet_or_retweet_text(tweet=tweet, print_source=True) + self.sendmsg(self.connection, output_channel.encode('utf-8', 'ignore'), tweet_text) - # set since_id - self._set_last_since_id(new_since_id) + # mentions printed, find the latest id + new_since_id = self._get_latest_tweet_id(tweets, new_since_id) + + # set since_id + self._set_last_since_id(new_since_id) def _return_tweet_or_retweet_text(self, tweet, print_source=False): """