~tyil/raku-irc-client-plugin-reminders

e78ba1aed0b302d02171e41d5278dfd13bacb34e — Patrick Spek a month ago 1f80a13 master
Add reminder functionality
M lib/IRC/Client/Plugin/Reminders.rakumod => lib/IRC/Client/Plugin/Reminders.rakumod +90 -8
@@ 13,8 13,18 @@ constant ReminderActions = IRC::Client::Plugin::Reminders::Actions;

unit class IRC::Client::Plugin::Reminders is IRC::Client::Plugin;

#| The configuration object for the bot.
has Config $.config;

#| A hash of prepared statements held by this plugin.
has %!stmt;

#| A connection to the database held by this plugin.
has $!db;

#| The interval in minutes in which the bot is supposed to run.
has $!interval;

method reload-config (
	Config $config,
) {


@@ 37,22 47,94 @@ multi method irc-to-me (

	my %reminder = $result.made;

	dd %reminder<delay>.Str;

	# TODO: Record the reminder entry in the database
	%!stmt<create>.execute(
		%reminder<subject>,
		$event.usermask,
		$event.?channel // Any,
		%reminder<delay>.at,
	);

	"Reminding you to {%reminder<subject>} on {%reminder<delay>.at}"
	"Reminding you to {%reminder<subject>} on {%reminder<delay>.at} (UTC)"
}

multi method irc-started () {
	# TODO: Check for usable $*DATABASE
method irc-connected (
	$event,
) {
	.debug("Interval set to $!interval minute(s)") with $*LOG;

	# TODO: Check tables for reminders that were missed while the bot was
	# offline.

	# TODO: Check for things to remind for periodically
	# Check for reminders in a seperate thread, so we don't hang the bot.
	# TODO: Dynamic variable isn't set inside the start{}?
	start {
		react {
			whenever Supply.interval($!interval × 60) {
				CATCH {
					default {
						.crit('Error in reminder thread!') with $*LOG;
					}
				}

				.notice('Checking for reminders at ' ~ DateTime.now.utc) with $*LOG;

				my @results = %!stmt<read>.execute.hashes;

				for @results -> %result {
					# Send the reminder.
					my $text = "Reminder to {%result<subject>}";

					if (%result<created_in>) {
						$text = %result<created_by>.split('!', 2).first ~ ': ' ~ $text;
					}

					$event.irc.send(
						:$text,
						:where(%result<created_in> // %result<created_by>),
					);

					# And clean up the reminder from the
					# database.
					%!stmt<delete>.execute(%result<id>);
				}
			}
		}
	}
}

	.debug("IRC::Client::Plugin::Reminders.irc-started") with $*LOG;
submethod TWEAK
{
	$!interval = $!config.get('irc.plugins.reminders.interval', 1).?Int;

	if (!$!db) {
		if (!$*DB) {
			.emergency('No database connection in $*DB') with $*LOG;
			return;
		}
		.debug('Preparing database') with $*LOG;

		$!db = $*DB.db;

		%!stmt<create> = $!db.prepare(q:to/SQL/);
			INSERT INTO reminders (
				subject,
				created_by,
				created_in,
				trigger_at
			) VALUES ($1, $2, $3, $4)
			SQL

		%!stmt<read> = $!db.prepare(q:to/SQL/);
			SELECT *
			FROM reminders
			WHERE trigger_at <= (NOW() AT TIME ZONE 'utc')
			ORDER BY trigger_at ASC
			SQL
		%!stmt<delete> = $!db.prepare(q:to/SQL/);
			DELETE FROM reminders
			WHERE id = $1
			SQL
	}
}

=begin pod

M lib/IRC/Client/Plugin/Reminders/Grammar.rakumod => lib/IRC/Client/Plugin/Reminders/Grammar.rakumod +0 -1
@@ 1,7 1,6 @@
#! /usr/bin/env false

use v6.d;
use Grammar::Tracer;

unit grammar IRC::Client::Plugin::Reminders::Grammar;


A sql/init.sql => sql/init.sql +8 -0
@@ 0,0 1,8 @@
CREATE TABLE reminders (
	id SERIAL NOT NULL,
	subject VARCHAR NOT NULL,
	created_by VARCHAR NOT NULL,
	created_in VARCHAR,
	trigger_at TIMESTAMP NOT NULL,
	created_at TIMESTAMP NOT NULL DEFAULT (NOW() AT TIME ZONE 'utc')
);