From 1b8dc8d9e42f22862aaf6b6de151302be5b33438 Mon Sep 17 00:00:00 2001 From: Sergiotarxz Date: Fri, 24 May 2024 15:39:24 +0200 Subject: [PATCH] Refactor. --- lib/TgMagicPdf/PdfBuilder.pm | 60 +++++--- lib/TgMagicPdf/Telegram.pm | 285 ++++++++++++++++++++--------------- 2 files changed, 200 insertions(+), 145 deletions(-) diff --git a/lib/TgMagicPdf/PdfBuilder.pm b/lib/TgMagicPdf/PdfBuilder.pm index dd4ccea..4cc67ca 100644 --- a/lib/TgMagicPdf/PdfBuilder.pm +++ b/lib/TgMagicPdf/PdfBuilder.pm @@ -26,9 +26,7 @@ has last_invalid_card => ( has _ua => ( is => 'lazy', ); sub _build__ua { - my $ua = Mojo::UserAgent->new->with_roles('+Queued'); - $ua->max_active(20); - $ua->inactivity_timeout(60); + my $ua = Mojo::UserAgent->new; return $ua; } @@ -43,14 +41,21 @@ sub _build__db_all_printings ($self) { sub from_text ( $self, $text ) { my $promise = Mojo::Promise->new; - { + FUNCTION: { my @lines = split /\n+/, $text; @lines = grep { $self->_filter_lines($_); } @lines; if ( scalar @lines > $MAX_CARDS ) { $promise->reject($ERR_TOO_MANY_CARDS); next; } - my @cards = map { s/^\s*(.*?)\s*$/$1/; $self->_parse_card($_) } @lines; + my @cards; + eval { + @cards = map { s/^\s*(.*?)\s*$/$1/; $self->_parse_card($_) } @lines; + }; + if ($@) { + $promise->reject($@); + next; + } my $n_cards = 0; for my $card (@cards) { $n_cards += $card->{quantity}; @@ -59,13 +64,13 @@ sub from_text ( $self, $text ) { $promise->reject($ERR_TOO_MANY_CARDS); next; } - eval { - @cards = map { $self->_fill_scryfall_id($_) } @cards; - }; - if ($@) { - say $@; - $promise->reject($@); - next; + for my $card (@cards) { + my $err; + $self->_fill_scryfall_id($card, \$err); + if (defined $err) { + $promise->reject($err); + last FUNCTION; + } } $self->_get_cards_images( \@cards )->then( sub ($images) { @@ -76,6 +81,7 @@ sub from_text ( $self, $text ) { } if ( $real_number_of_cards > $MAX_CARDS ) { $promise->reject($ERR_TOO_MANY_CARDS); + return; } my $pdf = $self->_generate_pdf( \@cards, $images ); $promise->resolve($pdf); @@ -144,7 +150,7 @@ sub _generate_pdf ( $self, $cards, $images ) { for my $page (@pages) { my $font = $pdf->font('Courier'); my $content = $page->text; - $content->position(0, $height_paper - 5); + $content->position(25, $height_paper - 25); $content->font($font, 5); $content->text(decode 'utf-8', "The price of a colour printed page in Spain is around 0.50€, " . "your pdf has @{[scalar @pages]} pages, that would be " @@ -153,7 +159,7 @@ sub _generate_pdf ( $self, $cards, $images ) { $content = $page->text; - $content->position(0, $height_paper - 10); + $content->position(25, $height_paper - 30); $content->font($font, 5); $content->text(decode 'utf-8', "developed and the developer would be " . "very grateful. I encourage you to donate " @@ -162,7 +168,7 @@ sub _generate_pdf ( $self, $cards, $images ) { $content = $page->text; - $content->position(0, $height_paper - 15); + $content->position(25, $height_paper - 35); $content->font($font, 5); $content->text("https://paypal.me/sergiotarxz. Thank you very much for your support!!"); } @@ -232,14 +238,14 @@ sub _get_cards_images ( $self, $cards ) { return $final_promise; } -sub _fill_scryfall_id ( $self, $card ) { +sub _fill_scryfall_id ( $self, $card, $err) { if ( $card->{type} eq 'token' ) { - return $self->_fill_scryfall_id_token($card); + return $self->_fill_scryfall_id_token($card, $err); } - return $self->_fill_scryfall_id_card($card); + return $self->_fill_scryfall_id_card($card, $err); } -sub _fill_scryfall_id_card ( $self, $card ) { +sub _fill_scryfall_id_card ( $self, $card, $err ) { my $db = $self->_db_all_printings; my $query = <<'EOF'; select scryfallId @@ -255,13 +261,16 @@ EOF $self->last_invalid_card( "@{[$card->{quantity}]} @{[$card->{name}]} @{[$card->{set_code}]} @{[$card->{number}]}" ); - die $ERR_INVALID_CARD; + if (defined $err) { + $$err = $ERR_INVALID_CARD; + return; + } } $card->{scryfallId} = $result->{scryfallId}; - return { %$card, }; + return; } -sub _fill_scryfall_id_token ( $self, $token ) { +sub _fill_scryfall_id_token ( $self, $token, $err ) { my $db = $self->_db_all_printings; my $query = <<'EOF'; SELECT scryfallId @@ -281,10 +290,13 @@ EOF $last_invalid_card .= " @{[$token->{set_code}]}" if defined $token->{set_code}; $self->last_invalid_card($last_invalid_card); - die $ERR_INVALID_CARD; + if (defined $err) { + $$err = $ERR_INVALID_CARD; + return; + } } $token->{scryfallId} = $result->{scryfallId}; - return {%$token}; + return; } sub _filter_lines ( $self, $arg ) { diff --git a/lib/TgMagicPdf/Telegram.pm b/lib/TgMagicPdf/Telegram.pm index 206de32..1c2b22c 100644 --- a/lib/TgMagicPdf/Telegram.pm +++ b/lib/TgMagicPdf/Telegram.pm @@ -25,10 +25,11 @@ has _ua => ( is => 'lazy', ); has _last_offset_update => ( is => 'rw', ); has _used_cores => ( is => 'rw', default => sub { 0 } ); + # We try 10 request at once in the crappy hardware. -has _cores => ( is => 'rw', default => sub { 10 } ); -has _updates => ( is => 'rw' ); -has _ioloop => ( is => 'rw' ); +has _cores => ( is => 'rw', default => sub { 10 } ); +has _updates => ( is => 'rw' ); +has _ioloop => ( is => 'rw' ); sub _build__token ($self) { require TgMagicPdf; @@ -39,6 +40,67 @@ sub run ($self) { $self->_dispatch_updates; } +sub _are_cores_available($self) { + if ( $self->_used_cores >= $self->_cores ) { + return 0; + } + return 1; +} + +sub _core_start ( $self, $n_core, $update ) { + say "Process $n_core active"; + $self->_dispatch_update($update)->then( + sub { + my $message = $update->{message}; + say 'Generated pdf for ' + . ( Data::Dumper::Dumper $message->{from} ) . ' ' + . $message->{date}; + } + )->catch( + sub ($err) { + { + if ( !defined $err ) { + next; + } + my $message = $update->{message}; + say 'Could not generate anything for ' + . ( Data::Dumper::Dumper $message->{from} ) . ' ' + . $message->{date}; + } + } + )->wait; +} + +sub _get_next_update($self) { + if ( !defined $self->_updates + || scalar @{ $self->_updates } == 0 ) + { + my $res = $self->_get_updates; + my $updates = $res->json->{result}; + $self->_updates($updates); + } + my $update = shift $self->_updates->@*; + return $update; +} + +sub _attemp_core_start( $self, $n_core ) { + my $update = $self->_get_next_update; + if ( !defined $update ) { + return 0; + } + $self->_used_cores( $self->_used_cores + 1 ); + Mojo::IOLoop->subprocess->run( + sub { + $self->_core_start( $n_core, $update ); + }, + sub { + say "Process $n_core ended"; + $self->_used_cores( $self->_used_cores - 1 ); + } + ); + return 1; +} + sub _dispatch_updates ($self) { my $in_process = 0; Mojo::IOLoop->recurring( @@ -48,60 +110,14 @@ sub _dispatch_updates ($self) { return; } $in_process = 1; - if ( $self->_used_cores >= $self->_cores ) { + if ( !$self->_are_cores_available ) { $in_process = 0; return; } for ( my $i = $self->_used_cores ; $i <= $self->_cores ; $i++ ) { - if ( !defined $self->_updates - || scalar @{ $self->_updates } == 0 ) - { - my $res = $self->_get_updates; - my $updates = $res->json->{result}; - $self->_updates($updates); - } - my $update = shift $self->_updates->@*; - if ( !defined $update ) { + if ( $self->_attemp_core_start($i) == 0 ) { last; } - $self->_used_cores( $self->_used_cores + 1 ); - Mojo::IOLoop->subprocess->run( - sub { - say "Proccess $i active"; - $self->_dispatch_update($update)->then( - sub { - my $message = $update->{message}; - say 'Generated pdf for ' - . ( Data::Dumper::Dumper $message->{from} ) - . ' ' - . $message->{date}; - Mojo::IOLoop->stop; - } - )->catch( - sub ($err) { - { - if ( !defined $err ) { - next; - } - my $message = $update->{message}; - say 'Could not generate anything for ' - . ( - Data::Dumper::Dumper $message->{from} ) - . ' ' - . $message->{date}; - } - Mojo::IOLoop->stop; - } - ); - Mojo::IOLoop->start; - return; - }, - sub { - say "Proccess $i ended"; - $self->_used_cores( $self->_used_cores - 1 ); - } - ); - say $i; } $in_process = 0; } @@ -110,18 +126,22 @@ sub _dispatch_updates ($self) { sub _dispatch_update ( $self, $update ) { my $promise = Mojo::Promise->new; + my $handle_message_promise; { if ( !defined $update->{message} ) { $promise->reject; next; } - $self->_handle_message( $update->{message} )->then( + $handle_message_promise = $self->_handle_message( $update->{message} ); + $handle_message_promise->then( sub { $promise->resolve; } )->catch( - sub ($err) { + sub { + my $err = shift; $promise->reject($err); + return 1; } ); } @@ -136,82 +156,106 @@ sub sendMessage ( $self, $chat_id, $text ) { return $promise; } +sub _is_message_valid_for_bot( $self, $chat_type, $text ) { + if ( $chat_type ne 'private' ) { + return; + } + if ( !defined $text ) { + return; + } + return 1; +} + +sub _send_pdf( $self, $promise, $chat_id, $pdf ) { + $self->sendDocument( $chat_id, 'mtgprint.pdf', $pdf )->then( + sub { + $promise->resolve; + } + )->catch( + sub { + $promise->reject; + } + ); +} + +sub _on_pdf_generation_error( $self, $promise, $pdf_builder, $chat_id, $err ) { + my @error_promises; + { + my $match = 0; + for my $known_error ( + $TgMagicPdf::PdfBuilder::ERR_INVALID_CARD, + $TgMagicPdf::PdfBuilder::ERR_UNABLE_TO_FIND_IMAGE, + $TgMagicPdf::PdfBuilder::ERR_TOO_MANY_CARDS + ) + { + $match = 1 + if ( index( $err, $known_error ) != -1 ); + } + if ($match) { + my $error_to_user = $self->_remove_stack_trace($err); + if ( $error_to_user eq $TgMagicPdf::PdfBuilder::ERR_INVALID_CARD ) { + $error_to_user .= ' ' . $pdf_builder->last_invalid_card; + } + if ( $error_to_user eq $TgMagicPdf::PdfBuilder::ERR_UNABLE_TO_FIND_IMAGE ) + { + $error_to_user .= ' ' . $pdf_builder->last_invalid_card; + } + push @error_promises, + $self->sendMessage( $chat_id, + 'I could not process your deck take a look to this details: ' + . $error_to_user ); + next; + } + push @error_promises, + $self->sendMessage( $chat_id, + 'I could not process your deck because of a server error' ); + } + Mojo::Promise->all(@error_promises)->finally( sub { $promise->reject(1) } ); +} + +sub _remove_stack_trace($self, $err) { + my $new_error; + if(!(($new_error) = $err =~ /^(.*?)\s*at.*$/m)) { + return $err; + } + chomp $new_error; + return $new_error; +} + +sub _after_first_reply_to_user( $self, $promise, $chat_id, $text ) { + my $pdf_builder = TgMagicPdf::PdfBuilder->new; + $pdf_builder->from_text($text)->then( + sub ($pdf) { + $self->_send_pdf( $promise, $chat_id, $pdf ); + } + )->catch( + sub ($err) { + $self->_on_pdf_generation_error( $promise, $pdf_builder, $chat_id, + $err ); + } + ); +} + sub _handle_message ( $self, $message ) { my $promise = Mojo::Promise->new; { my $chat_type = $message->{chat}{type}; - if ( $chat_type ne 'private' ) { + my $chat_id = $message->{chat}{id}; + my $text = $message->{text}; + if ( !$self->_is_message_valid_for_bot( $chat_type, $text ) ) { $promise->reject; next; } - my $chat_id = $message->{chat}{id}; - my $text = $message->{text}; - if ( !defined $text ) { - $promise->reject; - next; - } - $self->sendMessage( $chat_id, - 'Got your message, attempting to generate a pdf.' )->then( + my $promise_send_message = $self->sendMessage( $chat_id, + 'Got your message, attempting to generate a pdf.' ); + $promise_send_message->then( sub { - my $pdf_builder = TgMagicPdf::PdfBuilder->new; - $pdf_builder->from_text($text)->then( - sub ($pdf) { - $self->sendDocument( $chat_id, 'mtgprint.pdf', $pdf ) - ->then( - sub { - $promise->resolve; - } - ); - } - )->catch( - sub ($err) { - my @error_promises; - { - my $match = 0; - for my $known_error ( - $TgMagicPdf::PdfBuilder::ERR_INVALID_CARD, - $TgMagicPdf::PdfBuilder::ERR_UNABLE_TO_FIND_IMAGE, - $TgMagicPdf::PdfBuilder::ERR_TOO_MANY_CARDS - ) - { - $match = 1 - if ( index( $err, $known_error ) != -1 ); - } - if ($match) { - my $error_to_user = $err =~ s/^(.*?)\s*at.*$/$1/mr; - chomp $error_to_user; - if ( -1 != index $err, - $TgMagicPdf::PdfBuilder::ERR_INVALID_CARD ) - { - $error_to_user .= - ' ' . $pdf_builder->last_invalid_card; - } - if ( -1 != index $err, - $TgMagicPdf::PdfBuilder::ERR_UNABLE_TO_FIND_IMAGE - ) - { - $error_to_user .= - ' ' . $pdf_builder->last_invalid_card; - } - push @error_promises, - $self->sendMessage( - $chat_id, -'I could not process your deck take a look to this details: ' - . $error_to_user - ); - next; - } - push @error_promises, - $self->sendMessage( $chat_id, -'I could not process your deck because of a server error' - ); - } - Mojo::Promise->all(@error_promises) - ->finally( sub { $promise->reject(1) } ); - } - ); + $self->_after_first_reply_to_user( $promise, $chat_id, $text ); } - )->catch( sub ($err) { warn $err } ); + )->catch(sub ($err) { + $promise->reject($err); + return 1; + }); } return $promise; } @@ -239,7 +283,6 @@ sub _pdf_builder { sub _build__ua ($self) { my $ua = Mojo::UserAgent->new; - $ua->inactivity_timeout(5); return $ua; }