Skip to content

Commit

Permalink
Implement p6lert IRC bot
Browse files Browse the repository at this point in the history
  • Loading branch information
zoffixznet committed Dec 28, 2017
1 parent 2a8298b commit 3244ce4
Show file tree
Hide file tree
Showing 5 changed files with 99 additions and 13 deletions.
1 change: 1 addition & 0 deletions META6.json
Expand Up @@ -10,6 +10,7 @@
"DateTime::Format",
"DBIish",
"HTML::Escape",
"IRC::Client",
"OO::Monitors",
"Subset::Helper",
"Twitter"
Expand Down
62 changes: 62 additions & 0 deletions bin/bot.p6
@@ -0,0 +1,62 @@
use lib <lib>;
use IRC::Client;
use P6lert;
use JSON::Fast;
my %conf := from-json slurp 'secret.json';

my SetHash $admin-list .= new: |%conf<admin-list>;
subset AdminMessage where {.host $admin-list};
my $alert-re = rx:i/
[ 'severity:' $<severity>=\S+ \s+]?
[ 'affects:[' $<affects>=<-[\]]>+ ']' \s+]?
$<alert>=.+
/;

.run with IRC::Client.new:
:nick<p6lert>,
:username<p6lert-zofbot>,
:host(%*ENV<P6LERT_IRC_HOST> // 'irc.freenode.net'),
:channels(
%*ENV<P6LERT_DEBUG> ?? '#zofbot' !! |<#perl6 #perl6-dev #moarvm #zofbot #perl6-toolchain>
),
:debug,
plugins =>
class P6Lert::IRC::Plugin {
has P6lert:D $!alerter = P6lert.new:
|(:alert-url<http://localhost:10000/alert> if %*ENV<P6LERT_DEBUG>),
|(:60public-delay if %*ENV<P6LERT_DEBUG>);

submethod TWEAK { $!alerter.retweet }

multi method irc-to-me ($ where /^ \s* 'help' \s* '?'? \s* $/) {
https://github.com/perl6/alerts P6lert commands: [insta]?add ALERT, update ID ALERT,
~ delete ID; ALERT format: ['severity:'\S+]? ['affects:['<-[\]]>+']']? ALERT_TEXT
}
multi method irc-to-me(AdminMessage $e where
rx:i/^\s* [$<insta>=insta]? add \s+ $<alert>=<$alert-re>/
) {
my $id = try $!alerter.add: ~$<alert><alert>, :tweet, :creator($e.nick.subst: /'_'+ $/, ''),
|(:affects(~$_) with $<alert><affects> ),
|(:severity(~$_) with $<alert><severity>),
|(:time(time - 62*10) if $<insta>);
$id ?? "Added alert ID $id: $!alerter.alert-url()/$id"
!! "Error: $!";
}
multi method irc-to-me(AdminMessage $e where
rx:i/^\s* update \s+ $<id>=\d+ \s+ $<alert>=<$alert-re>/
) {
my $alert = $!alerter.get: +$<id> or return "No alert with ID $<id>";
(try $!alerter.update:
+$<id>, ~$<alert><alert>, :tweet, :creator($e.nick.subst: /'_'+ $/, ''),
|(:affects(~$_) with $<alert><affects> ),
|(:severity(~$_) with $<alert><severity>)
) or return "Error: $!";
"Updated alert ID $alert.id(): $!alerter.alert-url()/$alert.id()"
~ (" Note: this alert was already tweeted pre-update" if $alert.tweeted);
}
multi method irc-to-me(AdminMessage $ where rx:i/^\s* delete \s+ $<id>=\d+ \s* $/) {
my $alert = $!alerter.get: +$<id> or return "No alert with ID $<id>";
(try $!alerter.delete: $alert.id) or return "Error: $!";
"Deleted alert ID $<id>" ~ (" Note: this already was already tweeted." if $alert.tweeted);
}
}.new;
29 changes: 23 additions & 6 deletions lib/P6lert.pm6
Expand Up @@ -6,7 +6,10 @@ use P6lert::Model::Alerts;
use Twitter;

has IO::Path:D $.db-file = 'alerts.sqlite.db'.IO;
has P6lert::Model::Alerts:D $.alerts = P6lert::Model::Alerts.new: :$!db-file;
has UInt $.public-delay;
has P6lert::Model::Alerts:D $.alerts handles <get update delete>
= P6lert::Model::Alerts.new: :$!db-file, |(:$!public-delay with $!public-delay);

has Str:D $.alert-url = 'https://alerts.perl6.org/alert';
has Str:D $.consumer-key is required;
has Str:D $.consumer-secret is required;
Expand All @@ -23,9 +26,27 @@ END {
}
};

method retweet {
# tweet out now-public alerts and re-schedule to-be public alerts
start {
for $!alerts.public.grep: *.tweeted.not {
say "Retweeting ID {.id}";
self!tweet: .id;
sleep 2; # throttle tweets
}
# public ones now got tweeted; schedule tweets of everything that remains
for $!alerts.all.grep: *.tweeted.not -> $alert {
say "Re-scheduling tweet for ID {$alert.id}";
Promise.at($alert.time+3).then: { self!tweet: $alert.id };
}
CATCH { default { ".retweet: ERROR: $_".say } }
}
}

method new {
my %conf := from-json slurp $*PROGRAM.sibling: '../secret.json';
%_{$_} //= %conf{$_} for <consumer-key consumer-secret access-token access-token-secret>;
%_<db-file> //= .IO with %conf<db-file>;
self.bless: |%_
}

Expand All @@ -42,10 +63,6 @@ method add (
$id
}

method update ($alert-text) {
$!alerts.update: $alert-text, |%_;
}

method !tweet($id) {
my $alert := $!alerts.get: $id;
return if not $alert or $alert.tweeted;
Expand All @@ -58,7 +75,7 @@ method !tweet($id) {
($info ~ $alert.alert).chars < 280 ?? $alert.alert
!! "$alert.alert-short() See: $!alert-url/$alert.id()"
);

$!alerts.update: $alert.id, :tweeted;
self!clean-proms;
}

Expand Down
14 changes: 7 additions & 7 deletions lib/P6lert/Model/Alerts.pm6
Expand Up @@ -47,14 +47,14 @@ method add (
}

method update (UInt:D $id,
Str $alert-text,
Str $alert-text?,
Str :$creator,
Str :$affects,
P6lert::Alert::Severity :$severity,
UInt :$time,
Bool :$tweeted,
) {
my $alert = self.get: $id or return;
my $alert = self.get: $id or die "No alert with ID $id";

my %values = $alert.Capture.Hash;
%values<alert> = $_ with $alert-text;
Expand All @@ -66,11 +66,11 @@ method update (UInt:D $id,
$alert .= clone: |%values;

given $!dbh.prepare:
UPDATE INTO alerts (alert, severity, affects, creator, time, tweeted)
VALUES(?, ?, ?, ?, ?, ?)
{
LEAVE .finish;
.execute: .alert, .severity, .affects, .creator, .time, .tweeted with $alert;
UPDATE alerts SET alert = ?, severity = ?, affects = ?, creator = ?, time = ?, tweeted = ?
WHERE id = ?
-> $sth {
LEAVE $sth.finish;
$sth.execute: .alert, .severity, .affects, .creator, .time, .tweeted, .id with $alert;
}
$alert
}
Expand Down
6 changes: 6 additions & 0 deletions secret.json.template
@@ -1,4 +1,10 @@
{
"db-file": "alerts.sqlite.db",

"admin-list": [
"perl6/zoffix", "perl6.party", "localhost", "127.0.0.1"
],

"consumer-key": "...",
"consumer-secret": "...",
"access-token": "...",
Expand Down

0 comments on commit 3244ce4

Please sign in to comment.