rewrite remind module

This commit is contained in:
iou1name 2020-01-13 13:12:36 -05:00
parent 7a17e50069
commit ba683bcdf6

View File

@ -4,193 +4,79 @@ Reminds of things.
"""
import os
import re
import time
import sqlite3
import threading
from datetime import datetime
from datetime import datetime, timedelta
import config
from module import commands, example
class MonitorThread(threading.Thread):
"""
A custom custom thread class for monitoring the time to announce
reminders. It allows itself to be stopped when there are no reminders
to look for.
"""
def __init__(self, bot):
threading.Thread.__init__(self)
self._bot = bot
self.stop = threading.Event()
def run(self):
while not self._bot.stillConnected():
time.sleep(1)
# don't try to say anything if we're not fully connected yet
while not self.stop.is_set():
now = int(time.time())
unixtimes = [int(key) for key in self._bot.memory["remind"].keys()]
oldtimes = [t for t in unixtimes if t <= now]
if oldtimes:
for oldtime in oldtimes:
for reminder in self._bot.memory["remind"][oldtime]:
channel, nick, message = reminder
if message:
self._bot.msg(channel, nick + ': ' + message)
else:
self._bot.msg(channel, nick + '!')
del self._bot.memory["remind"][oldtime]
delete_reminder(self._bot, oldtime)
if not self._bot.memory["remind"] or not self._bot.stillConnected():
self.stop.set()
self.stop.wait(2.5)
del self._bot.memory["remind_monitor"]
def start_monitor(bot):
"""
Starts the monitor thread. Does nothing if one is already running.
"""
if bot.memory.get("remind_monitor"):
return
t = MonitorThread(bot)
t.start()
bot.memory["remind_monitor"] = t
def load_database(bot):
"""
Loads all entries from the 'remind' table in the bot's database and
stores them in memory
"""
data = {}
reminds = bot.db.execute("SELECT * FROM remind").fetchall()
for remind in reminds:
unixtime, channel, nick, message = remind
reminder = (channel, nick, message)
try:
data[unixtime].append(reminder)
except KeyError:
data[unixtime] = [reminder]
return data
def insert_reminder(bot, unixtime, reminder):
"""
Inserts a new reminder into the 'remind' table in the bot's database.
reminder - a tuple containing (channel, nick, message)
"""
bot.db.execute("INSERT INTO remind (unixtime, channel, nick, message) "
"VALUES(?,?,?,?)", (unixtime,) + reminder)
def delete_reminder(bot, unixtime):
"""
Deletes a reminder from the 'remind' table in the bot's database, using
unixtime as the key.
"""
bot.db.execute("DELETE FROM remind WHERE unixtime = ?", (unixtime,))
def setup(bot):
con = bot.db.connect()
cur = con.cursor()
try:
cur.execute("SELECT * FROM remind").fetchone()
except sqlite3.OperationalError:
cur.execute("CREATE TABLE remind("
"unixtime INTEGER DEFAULT (STRFTIME('%s', 'now')),"
"channel TEXT,"
"nick TEXT,"
"message TEXT)")
con.commit()
con.close()
bot.memory["remind"] = load_database(bot)
start_monitor(bot)
import module
regex = (
"(?=\d+[ywdhms])"
"(?:(\d+)y)?"
"(?:(\d+)w)?"
"(?:(\d+)d)?"
"(?:(\d+)h)?"
"(?:(\d+)m)?"
"(?:(\d+)s)?"
"(\d+y)?"
"(\d+w)?"
"(\d+d)?"
"(\d+h)?"
"(\d+m)?"
"(\d+s)?"
)
multiplier = [
60*60*24*365,
60*60*24*7,
60*60*24,
60*60,
60,
1
]
shorthand = {
'y': 'years',
'w': 'weeks',
'd': 'days',
'h': 'hours',
'm': 'minutes',
's': 'seconds',
}
@commands('remind')
@example('.remind 3h45m Go to class')
@module.commands('remind')
@module.example('.remind 3h45m Go to class')
def remind(bot, trigger):
"""Gives you a reminder in the given amount of time."""
if len(trigger.args) == 1:
return bot.msg("Missing arguments for reminder command.")
if len(trigger.args) == 2:
reminder = ''
else:
reg = re.search(regex, trigger.args[1])
if not reg:
return bot.reply("I didn't understand that.")
args = {shorthand[g[-1]]: int(g[:-1]) for g in reg.groups() if g}
delta = timedelta(**args)
dt = datetime.now() + delta
reminder = ' '.join(trigger.args[2:])
duration = 0
for n, group in enumerate(re.search(regex, trigger.args[1]).groups()):
if not group:
continue
duration += int(group) * multiplier[n]
create_reminder(bot, trigger, duration, reminder)
args = (trigger.channel, trigger.nick, reminder)
bot.scheduler.add_task(announce_reminder, dt, args)
bot.reply("Okay, will remind at", dt.strftime('[%Y-%m-%d %H:%M:%S]'))
@commands('at')
@example('.at 2012-12-21 18:00:00 End the world.')
@module.commands('at')
@module.example('.at 2012-12-21 18:00:00 End the world.')
def at(bot, trigger):
"""
Gives you a reminder at the given time and date. Datetime must be in
YYYY-MM-DD HH:MM:SS format. Only the bot's timezone is used.
YYYY-MM-DD HH:MM:SS format. Only the bot's timezone is used. If
YYYY-MM-DD is excluded, it is assumed to be today's date.
"""
if len(trigger.args) < 3:
if len(trigger.args) < 2:
return bot.msg("Missing arguments for reminder command.")
if len(trigger.args) < 4:
reminder = ''
if ':' in trigger.args[1]:
at_time = datetime.now().strftime('%Y-%m-%d') + ' ' + trigger.args[1]
reminder = ' '.join(trigger.args[2:])
else:
at_time = ' '.join(trigger.args[1:3])
reminder = ' '.join(trigger.args[3:])
try:
at_time = datetime.strptime(' '.join(trigger.args[1:2]),
'%Y-%m-%d %H:%M:%S')
dt = datetime.strptime(at_time, '%Y-%m-%d %H:%M:%S')
except ValueError:
return bot.msg("Datetime improperly formatted.")
diff = at_time - datetime.now()
duration = diff.seconds
create_reminder(bot, trigger, duration, reminder)
args = (trigger.channel, trigger.nick, reminder)
bot.scheduler.add_task(announce_reminder, dt, args)
bot.reply("Okay, will remind at", dt.strftime('[%Y-%m-%d %H:%M:%S]'))
def create_reminder(bot, trigger, duration, message):
"""
Inserts the reminder into the bot's memory and database so it can
eventually announce for it.
"""
t = int(time.time()) + duration
reminder = (trigger.channel, trigger.nick, message)
try:
bot.memory["remind"][t].append(reminder)
except KeyError:
bot.memory["remind"][t] = [reminder]
start_monitor(bot)
insert_reminder(bot, t, reminder)
if duration >= 60:
remind_at = datetime.fromtimestamp(t)
t_format = config.default_time_format
timef = datetime.strftime(remind_at, t_format)
bot.reply('Okay, will remind at %s' % timef)
def announce_reminder(bot, channel, remindee, reminder):
"""Announce the reminder."""
if reminder:
msg = f"{remindee}: {reminder}"
else:
bot.reply('Okay, will remind in %s secs' % duration)
msg = f"{remindee}!"
bot.msg(channel, msg)