diff --git a/.perlcriticrc b/.perlcriticrc index d43b43b..2b3a696 100644 --- a/.perlcriticrc +++ b/.perlcriticrc @@ -92,3 +92,7 @@ lib_sections = NAME | VERSION | DESCRIPTION | AUTHOR | LICENSE AND COPYRIGHT [-ControlStructures::ProhibitDeepNests] # Have to use it, so fuckoff + +[-ControlStructures::ProhibitUntilBlocks] +# Until is really useful if condition is simple, so let's assume condition is +# always simple to read \ No newline at end of file diff --git a/README.md b/README.md index 66279b8..4c9d949 100644 --- a/README.md +++ b/README.md @@ -13,17 +13,18 @@ mature enough, maybe I release it separately. Bot config located in **data/config.json**, sample config provided as **data/sample_config.json**. -Bot can be run via **bin/aleesa-telegram-bot** and acts as daemon (double fork() -and detaches stdio). +Bot can be run via **bin/aleesa-telegram-bot** and acts as daemon (double +fork() and detaches stdio). ## Installation -In order to run this application, you need to "bootstrap" it - download and build -all required dependencies and libraries. +In order to run this application, you need to "bootstrap" it - download and +build all required dependencies and libraries. You'll need perl-5.18 or newer, "Development Tools" or similar group of packages, perl, perl-devel, perl-local-lib, perl-app-cpanm, sqlite-devel, -zlib-devel, openssl-devel, libdb4-devel (Berkeley DB devel), make. +zlib-devel, openssl-devel, libdb4-devel (Berkeley DB devel), make, +hiredis-devel. After installing required dependencies it is possible to run: diff --git a/README_RU.md b/README_RU.md index 43017da..a523126 100644 --- a/README_RU.md +++ b/README_RU.md @@ -24,7 +24,7 @@ metacpan.org Понадобится perl-5.18, а желательно новее, "Development Tools" или подобная группа пакетов , perl, perl-devel, perl-local-lib, perl-app-cpanm, sqlite-devel, -zlib-devel, openssl-devel, libdb4-devel (Berkeley DB devel), make. +zlib-devel, openssl-devel, libdb4-devel (Berkeley DB devel), make, hiredis-devel. После установки этих пакетов, можно будет запустить: diff --git a/cpanfile b/cpanfile index 8d7c0e3..aca9c4d 100644 --- a/cpanfile +++ b/cpanfile @@ -26,9 +26,10 @@ requires 'Log::Any::For::Std'; requires 'Math::Random::Secure'; requires 'Mojo::Base'; requires 'Mojo::IOLoop'; -requires 'Mojo::Redis' +requires 'Mojo::Redis'; requires 'Mojo::UserAgent'; requires 'Mojo::UserAgent::Cached'; +requires 'Protocol::Redis::XS'; requires 'String::Random'; requires 'Text::Fuzzy'; requires 'URI::Encode::XS'; diff --git a/lib/BotLib.pm b/lib/BotLib.pm index ab705bf..14f341f 100644 --- a/lib/BotLib.pm +++ b/lib/BotLib.pm @@ -9,6 +9,8 @@ use open qw (:std :utf8); use English qw ( -no_match_vars ); use Carp qw (carp); use Math::Random::Secure qw (irand); +use Data::Dumper; +use Log::Any qw ($log); use BotLib::Conf qw (LoadConf); use BotLib::Admin qw (@ForbiddenMessageTypes GetForbiddenTypes AddForbiddenType @@ -60,11 +62,35 @@ sub Command { my $msg = shift; my $text = shift; my $chatid = shift; + my $reply; my ($userid, $username, $fullname, $highlight, $visavi) = Highlight ($msg); + my $rmsg->{from} = 'telegram'; + $rmsg->{userid} = $userid; + $rmsg->{chatid} = $chatid; + $rmsg->{plugin} = 'telegram'; + + if ($chatid >= 0) { + $rmsg->{mode} = 'private'; + } else { + $rmsg->{mode} = 'public'; + } + if (substr ($text, 1) eq 'ping') { - $reply = 'Pong.'; + $rmsg->{message} = $text; + $self->log->debug ('[DEBUG] Sending message to redis ' . Dumper ($rmsg)); + + until (eval { Mojo::Redis::Connection->is_connected ($main::REDIS); }) { + $log->info ('[INFO] Not yet connected to redis'); + sleep 1; + } + + my $pubsub = $main::REDIS->pubsub; + + $pubsub->json ($c->{'redis_router_channel'})->notify ( + $c->{'redis_router_channel'} => $rmsg + ); } elsif (substr ($text, 1) eq 'пинг') { $reply = 'Понг.'; } elsif (substr ($text, 1) eq 'pong') { diff --git a/lib/RedisLib.pm b/lib/RedisLib.pm index 1bdd373..2fbe062 100644 --- a/lib/RedisLib.pm +++ b/lib/RedisLib.pm @@ -15,11 +15,24 @@ our @EXPORT_OK = qw (redis_parse_message); sub redis_parse_message { my $self = shift; my $m = shift; - my $answer = $m; - my $send_to = $answer->{from}; $log->error (Dumper $self); + # We cannot send message if we're not connected to telegram + # TODO: Queue messages properly. + + until (defined $main::TGM) { + sleep 1; + } + + # TODO: add some checks, at least that the bot is not muted in chat + $main::TGM->sendMessage ( + { + chat_id => $m->{chatid}, + text => $m->{message} + } + ); + return; }; diff --git a/lib/TelegramBot.pm b/lib/TelegramBot.pm index d5fb470..0eac493 100644 --- a/lib/TelegramBot.pm +++ b/lib/TelegramBot.pm @@ -13,6 +13,8 @@ use Hailo; use Log::Any qw ($log); use Math::Random::Secure qw (irand); use Mojo::Base 'Teapot::Bot::Brain'; +# Чтобы "уж точно" использовать hiredis-биндинги, загрузим этот модуль перед Mojo::Redis +use Protocol::Redis::XS; use Mojo::Redis; use Mojo::Redis::Connection; use BotLib::Admin qw (FortuneToggleList); @@ -21,7 +23,7 @@ use BotLib::Conf qw (LoadConf); use BotLib::Fortune qw (Fortune); use BotLib::Karma qw (KarmaSet); use BotLib::Util qw (trim fmatch); -use RedisLib qw (redisListener); +use RedisLib qw (redis_parse_message); use version; our $VERSION = qw (1.0); use Exporter qw (import); @@ -372,13 +374,16 @@ sub __on_msg { } sub __redisListener { + $log->error ('Run redis listener'); # If we already connected there is no point to disconnect - if (defined $main::REDIS) { + if (defined $main::REDIS) { my $connected = eval { Mojo::Redis::Connection->is_connected ($main::REDIS); }; if ($connected) { + $log->notice ('[NOTICE] Redis client already running and connected'); return; } else { + $log->notice ('[NOTICE] Redis client registered, but looks like it is not connected, try to re-connect'); $main::REDIS = undef; } } @@ -387,45 +392,40 @@ sub __redisListener { sprintf 'redis://%s:%s/1', $c->{redis_server}, $c->{redis_port} ); + $log->notice ('[NOTICE] New redis client registered, registering callbacks'); # Don't forget to update global ref to our redis context $main::REDIS = $r; - $r->on ( - error => sub { - my ($conn, $error) = @_; - - $log->error ("Redis connection error: $error"); - - # TODO: maintain list of callbacks and clean them up? - - my $redis = Mojo::Redis->new ( - sprintf 'redis://%s:%s/1', $c->{redis_server}, $c->{redis_port} - ); - - # Don't forget to update global ref to our redis context - $main::REDIS = $redis; - return; - } - ); - $r->on ( connection => sub { my ($redis, $connection) = @_; - my $pubsub = $redis->pubsub; - my $sub; - foreach my $channel (@{$c->{redis_channels}}) { - $log->info ("Subscribing to $channel"); - - $sub->{$channel} = $pubsub->json ($channel)->listen ( - $channel => sub { \&redis_parse_message->(@_); } - ); - } + # Log error + $connection->on ( + error => sub { + my ($conn, $error) = @_; + $log->error ("[ERROR] Redis connection error: $error"); + return; + } + ); return; } ); + # Subscribe to channels + my $pubsub = $r->pubsub; + my $sub; + $log->notice ('[NOTICE] Subscribing to redis channels'); + + foreach my $channel (@{$c->{redis_channels}}) { + $log->info ("[INFO] Subscribing to $channel"); + + $sub->{$channel} = $pubsub->json ($channel)->listen ( + $channel => sub { \&redis_parse_message->(@_); } + ); + } + return; } @@ -445,8 +445,8 @@ sub init { } $self->add_listener (\&__on_msg); - $self->add_listener (\&__redisListener); $self->add_repeating_task (900, \&__cron); + __redisListener (); return; }