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
This commit is contained in:
Brian S. Stephan 2011-06-20 21:18:55 -05:00
parent c7846e415a
commit 152ef2a1ad
3 changed files with 58 additions and 77 deletions

View File

@ -32,11 +32,6 @@ class Module(object):
def priority(self): def priority(self):
return 50 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): def __init__(self, irc, config, server):
"""Construct a feature module. Inheritors can do special things here, but """Construct a feature module. Inheritors can do special things here, but
should be sure to call Module.__init__. should be sure to call Module.__init__.
@ -62,10 +57,6 @@ class Module(object):
# set up database for this module # set up database for this module
self.db_init() 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 what was loaded, for debugging
print("loaded " + self.__class__.__name__) print("loaded " + self.__class__.__name__)
@ -242,26 +233,6 @@ class Module(object):
print("looks like someone forgot to implement do!") 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): def help_description(self):
"""Return a quick list of commands or other summary, should be """Return a quick list of commands or other summary, should be
less than two lines. If you want the module hidden from "!help", less than two lines. If you want the module hidden from "!help",

View File

@ -23,6 +23,8 @@ import random
import re import re
import sqlite3 import sqlite3
import sys import sys
import thread
import time
from dateutil.parser import * from dateutil.parser import *
from dateutil.relativedelta import * from dateutil.relativedelta import *
@ -42,10 +44,6 @@ class Markov(Module):
http://code.activestate.com/recipes/194364-the-markov-chain-algorithm/ 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): def __init__(self, irc, config, server):
"""Create the Markov chainer, and learn text from a file if available.""" """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) Module.__init__(self, irc, config, server)
self.next_shut_up_check = 0
thread.start_new_thread(self.thread_do, ())
def db_init(self): def db_init(self):
"""Create the markov chain table.""" """Create the markov chain table."""
@ -280,30 +281,34 @@ class Markov(Module):
self.lines_seen.append(('.self.said.', datetime.now())) self.lines_seen.append(('.self.said.', datetime.now()))
return self._generate_line(target, min_size=min_size, max_size=max_size) return self._generate_line(target, min_size=min_size, max_size=max_size)
def timer_do(self): def thread_do(self):
"""Do various things.""" """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): def _do_shut_up_checks(self):
"""Check to see if we've been talking too much, and shut up if so.""" """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: for (nick,then) in self.lines_seen:
rdelta = relativedelta(datetime.now(), then) 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: 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)) last_30_sec_lines.append((nick,then))
if len(last_30_sec_lines) >= 15: if len(last_30_sec_lines) >= 15:
lines_i_said = len(filter(lambda (a,b): a == '.self.said.', last_30_sec_lines)) lines_i_said = len(filter(lambda (a,b): a == '.self.said.', last_30_sec_lines))
if lines_i_said >= 8: if lines_i_said >= 8:
self.shut_up = True self.shut_up = True
targets = self._get_chatter_targets() targets = self._get_chatter_targets()
for t in targets: for t in targets:
self.sendmsg(self.connection, t, 'shutting up for 30 seconds due to last 30 seconds of activity') self.sendmsg(self.connection, t, 'shutting up for 30 seconds due to last 30 seconds of activity')
def _learn_line(self, line, target): def _learn_line(self, line, target):
"""Create Markov chains from the provided line.""" """Create Markov chains from the provided line."""

View File

@ -20,7 +20,8 @@ from ConfigParser import NoSectionError, NoOptionError
import oauth2 as oauth import oauth2 as oauth
import re import re
import sqlite3 import sqlite3
from threading import Timer import thread
import time
import urlparse import urlparse
from extlib import irclib from extlib import irclib
@ -32,11 +33,6 @@ class Twitter(Module):
"""Access Twitter via the bot as an authenticated client.""" """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): def __init__(self, irc, config, server):
"""Prepare for oauth stuff (but don't execute it yet).""" """Prepare for oauth stuff (but don't execute it yet)."""
@ -72,6 +68,9 @@ class Twitter(Module):
self.twit = twitter.Api() self.twit = twitter.Api()
self.authed = False self.authed = False
self.next_timeline_check = 0
thread.start_new_thread(self.thread_do, ())
def db_init(self): def db_init(self):
"""Set up the settings table.""" """Set up the settings table."""
@ -239,39 +238,45 @@ class Twitter(Module):
return 'The bot is now logged in.' return 'The bot is now logged in.'
def timer_do(self): def thread_do(self):
"""Check the timeline.""" """Check the timeline."""
self._check_self_timeline()
while not self.is_shutdown:
self._check_self_timeline()
time.sleep(1)
def _check_self_timeline(self): def _check_self_timeline(self):
"""Check my timeline, and if there are entries, print them to the channel.""" """Check my timeline, and if there are entries, print them to the channel."""
if self.authed: if self.next_timeline_check < time.time():
# get the id of the last check we made self.next_timeline_check = time.time() + 300
since_id = self._get_last_since_id()
output_channel = self._get_output_channel()
if since_id is not None and output_channel != '': if self.authed:
tweets = self.twit.GetFriendsTimeline(since_id=since_id) # get the id of the last check we made
tweets.reverse() since_id = self._get_last_since_id()
for tweet in tweets: output_channel = self._get_output_channel()
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 if since_id is not None and output_channel != '':
new_since_id = self._get_latest_tweet_id(tweets, since_id) 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) # friends timeline printed, find the latest id
tweets.reverse() new_since_id = self._get_latest_tweet_id(tweets, since_id)
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)
# mentions printed, find the latest id tweets = self.twit.GetMentions(since_id=since_id)
new_since_id = self._get_latest_tweet_id(tweets, new_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 # mentions printed, find the latest id
self._set_last_since_id(new_since_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): def _return_tweet_or_retweet_text(self, tweet, print_source=False):
""" """