0
Files
meow-irc-bot/lib/BotLib/Command.pm
2022-11-01 01:02:53 +03:00

259 lines
8.3 KiB
Perl

package BotLib::Command;
# Парсит команды
use 5.030; ## no critic (ProhibitImplicitImport)
use strict;
use warnings;
use utf8;
use open qw (:std :utf8);
use English qw ( -no_match_vars );
use JSON::XS qw (encode_json);
use Log::Any qw ($log);
use BotLib::Conf qw (LoadConf);
use BotLib::Util qw (storedata rakedata deletedata timems utf2md5hex utf2sha1hex utf2sha224hex utf2sha256hex
utf2sha384hex utf2sha512hex utf2crc32hex utf2murmurhash utf2b64 urlencode irandom);
use version; our $VERSION = qw (1.0);
use Exporter qw (import);
our @EXPORT_OK = qw (Help Notify DelayedNotify PrintMsg Todo B64Str Md5Str Sha1Str Sha224Str Sha256Str Sha384Str
Sha512Str Crc32Str MurmurhashStr UrlencodeStr IrandNum);
local $OUTPUT_AUTOFLUSH = 1;
my $c = LoadConf();
# Возвращает список возможных команд
# $text Help()
sub Help {
my $text = '';
my $csign = $c->{csign};
$text .= "${csign}help - это сообщение\n";
$text .= "${csign}ping - попинговать бота\n";
$text .= "${csign}ver - написать что-то про версию ПО\n";
$text .= "${csign}cal - календарик\n";
$text .= "${csign}exit - завершить работу бота\n";
$text .= "${csign}quit - завершить работу бота\n";
$text .= "${csign}notify me after N [s|m|h] - одноразовая напоминалка через desktop notification\n";
$text .= "${csign}n N[s|m|h] message - одноразовая напоминалка через desktop notification\n";
$text .= "${csign}todo - выводит списк запланированных дел\n";
$text .= "${csign}todo -d N - удаляет из списка запланированных дел дело N\n";
$text .= "${csign}todo ДЕЛО - добавляет в списк запланированных дел ДЕЛО\n";
$text .= "${csign}sha1 STR - выводит sha1sum для STR\n";
$text .= "${csign}sha224 STR - выводит sha224sum для STR\n";
$text .= "${csign}sha256 STR - выводит sha256sum для STR\n";
$text .= "${csign}sha384 STR - выводит sha384sum для STR\n";
$text .= "${csign}sha512 STR - выводит sha512sum для STR\n";
$text .= "${csign}crc32 STR - выводит crc32 для STR\n";
$text .= "${csign}md5 STR - выводит md5sum для STR\n";
$text .= "${csign}murmurhash STR - выводит murmur hash для STR\n";
$text .= "${csign}b64 STR - выводит base64 для STR\n";
$text .= "${csign}urlencode STR - кодирует STR по urlencode\n";
$text .= "${csign}rand N - выдаёт рандомное целое число от 0 до указанного\n";
$text .= "${csign}unixtime - выдаёт текущее время в формате unix timestamp (секунды с 1 янв 1970)\n";
return $text;
}
# Одноразовая напоминалка. Сохраняет сообщение в базу notifications и отправляет его в delayed notifications.
# Возвращает либо строку-подтверждение, либо подсказку как пользоваться командой.
# $string Notify($chatid, $amount, $units, $message)
sub Notify {
my $chatid = shift;
my $amount = shift;
my $units = shift;
my $message = shift;
if (defined $units) {
if ($units eq 'm' || $units eq 'minute' || $units eq 'minutes') {
$amount = eval { $amount * 60 };
unless (defined $units) {
return sprintf ('Usage: %s NUM [s|seconds|m|minutes|h|hours]', $units);
}
} elsif ($units eq 'h' || $units eq 'hour' || $units eq 'hours') {
$amount = eval { $amount * 60 * 60 };
unless (defined $units) {
return sprintf ('Usage: %s NUM [s|seconds|m|minutes|h|hours]', $units);
}
} elsif ($units eq 's' || $units eq 'second' || $units eq 'seconds') {
$amount = eval { $amount + 0 };
unless (defined $units) {
return sprintf ('Usage: %s NUM [s|seconds|m|minutes|h|hours]', $units);
}
}
} else {
$amount = eval { $amount + 0 };
unless (defined $units) {
return sprintf ('Usage: %s NUM [s|seconds|m|minutes|h|hours]', $units);
}
}
my $timestamp = time () + $amount;
my $msg->{title} = 'Meow-bot notification';
my $json;
if (defined $message && $message ne '') {
$msg->{text} = $message;
} else {
$msg->{text} = 'Напоминалка!';
}
$json = encode_json $msg;
storedata ('notifications', $timestamp, $json, $c->{notifications}->{retention_days});
DelayedNotify ($c->{channels}->{notify}, $msg->{text});
return sprintf 'Notification will be sent after %d seconds', $amount;
}
# Пишет сообщение в чятик и складывает в БД, чтобы позже показать юзеру, когда он появится в чятике
# undef PrinfMsgForUser($userid, $chatid, $message)
sub DelayedNotify {
my $channel = shift;
my $message = shift;
my $timestamp = timems ();
my $data;
$data->{message} = $message;
$data->{channel} = $channel;
$data->{timestamp} = $timestamp;
$data->{expiration_time} = $c->{delayed_notifications}->{retention_days} * 24 * 60 * 60 * 1000 + $timestamp;
$data->{retention_days} = $c->{delayed_notifications}->{retention_days} ;
# Достанем список тех, кто есть в канальчике notify, им на джоине показывать сообщение не надо
my @users = keys %{$MAIN::IRC->channel_list->{$c->{channels}->{notify}}}; ## no critic (Modules::RequireExplicitInclusion)
$data->{users_shown} = \@users;
# TODO: Pretty jsonl
my $json = encode_json $data;
storedata ('delayed_notifications', timems (), $json, $c->{delayed_notifications}->{retention_days});
return;
}
# Пишет сообщение в чятик или юзеру
# undef PrintMsg($chatid, $text)
sub PrintMsg {
my $channel = shift;
my $message = shift;
$MAIN::IRC->send_long_message ('utf8', 0, 'PRIVMSG', $channel, $message); ## no critic (Modules::RequireExplicitInclusion)
$log->debug ("[DEBUG] message '$message' sent to $channel");
return;
}
# Выгребает список todo-шек из базы
# $msg = _todoPrint()
sub _todoPrint {
$log->debug ('[DEBUG] raking data from todo db');
my $todo = rakedata ('todo');
my $msg = '';
foreach (sort keys (%{$todo})) {
$msg .= sprintf "%d. %s\n", $_, $todo->{$_};
}
return $msg;
}
# Парсит запрос команды .todo
# $reply Todo($message)
sub Todo {
my $message = shift;
$log->debug ("$message");
my $reply;
if (($message eq 'todo') || ($message =~ /^todo\s+$/)) {
$log->debug ('[DEBUG] got todo command without arguments');
$reply = _todoPrint ();
} elsif ($message =~ /^todo\s+\-d\s+(\d+)\s*$/) {
$log->debug ('[DEBUG] got todo command with -d argument');
deletedata('todo', $1);
$reply = _todoPrint ();
} else {
if ($message =~ /^todo\s+(.*)/) {
my $data = $1;
$log->debug("[DEBUG] got todo command message: $message");
my $todo = rakedata ('todo');
my $num = int (keys %{$todo}) + 1;
storedata ('todo', $num, $data, 'never');
$reply = _todoPrint ();
} else {
$log->debug ('[DEBUG] got todo command with garbage');
}
}
return $reply;
}
sub B64Str {
my $str = shift;
return utf2b64 ($str);
}
sub Md5Str {
my $str = shift;
return utf2md5hex ($str);
}
sub Sha1Str {
my $str = shift;
return utf2sha1hex($str);
}
sub Sha224Str {
my $str = shift;
return utf2sha224hex($str);
}
sub Sha256Str {
my $str = shift;
return utf2sha256hex($str);
}
sub Sha384Str {
my $str = shift;
return utf2sha384hex($str);
}
sub Sha512Str {
my $str = shift;
return utf2sha512hex($str);
}
sub Crc32Str {
my $str = shift;
return utf2crc32hex($str);
}
sub MurmurhashStr {
my $str = shift;
return utf2murmurhash($str);
}
sub UrlencodeStr {
my $str = shift;
return urlencode ($str);
}
sub IrandNum {
my $num = shift;
$num = eval {$num + 0};
if (defined $num) {
return irandom($num);
} else {
return;
}
}
1;
# vim: set ft=perl noet ai ts=4 sw=4 sts=4: