From ddfca4d828fd46e1ad060e619ec9ad847008d1e7 Mon Sep 17 00:00:00 2001 From: sergiotarxz Date: Thu, 23 May 2024 10:15:46 +0200 Subject: [PATCH] Adding better logging of what is being done for the user. --- lib/TgMagicPdf/PdfBuilder.pm | 142 +++++++++++++++++++++-------------- lib/TgMagicPdf/Telegram.pm | 113 +++++++++++++++++----------- 2 files changed, 152 insertions(+), 103 deletions(-) diff --git a/lib/TgMagicPdf/PdfBuilder.pm b/lib/TgMagicPdf/PdfBuilder.pm index b63d411..138aa4f 100644 --- a/lib/TgMagicPdf/PdfBuilder.pm +++ b/lib/TgMagicPdf/PdfBuilder.pm @@ -28,20 +28,23 @@ sub _build__ua { return Mojo::UserAgent->new; } -our $ERR_TOO_MUCH_CARDS = 'TOO_MUCH_CARDS'; +our $ERR_TOO_MANY_CARDS = 'TOO_MANY_CARDS'; our $ERR_INVALID_CARD = 'INVALID_CARD'; our $ERR_UNABLE_TO_FIND_IMAGE = 'UNABLE_TO_FIND_IMAGE'; our $MAX_CARDS = 9 * 50; -sub _build__db_all_printings($self) { +sub _build__db_all_printings ($self) { return DBI->connect('dbi:SQLite:AllPrintings.sqlite'); } -sub from_text( $self, $text ) { +sub from_text ( $self, $text ) { + my $promise = Mojo::Promise->new; + { my @lines = split /\n+/, $text; @lines = grep { $self->_filter_lines($_); } @lines; if ( scalar @lines > $MAX_CARDS ) { - die $ERR_TOO_MUCH_CARDS; + $promise->reject($ERR_TOO_MANY_CARDS); + next; } my @cards = map { s/^\s*(.*?)\s*$/$1/; $self->_parse_card($_) } @lines; my $n_cards = 0; @@ -49,54 +52,71 @@ sub from_text( $self, $text ) { $n_cards += $card->{quantity}; } if ( $n_cards > $MAX_CARDS ) { - die $ERR_TOO_MUCH_CARDS; + $promise->reject($ERR_TOO_MANY_CARDS); + next; } - @cards = map { $self->_fill_scryfall_id($_) } @cards; - my $promise = Mojo::Promise->new; - $self->_get_cards_images(\@cards)->then(sub ($images) { - my $real_number_of_cards = 0; - for my $card (@cards) { - $real_number_of_cards += $card->{quantity} * scalar keys $images->{$card->{scryfallId}}->%*; + eval { + @cards = map { $self->_fill_scryfall_id($_) } @cards; + }; + if ($@) { + $promise->reject($@); + next; + } + $self->_get_cards_images( \@cards )->then( + sub ($images) { + my $real_number_of_cards = 0; + for my $card (@cards) { + $real_number_of_cards += $card->{quantity} * scalar + keys $images->{ $card->{scryfallId} }->%*; + } + if ( $real_number_of_cards > $MAX_CARDS ) { + $promise->reject($ERR_TOO_MANY_CARDS); + } + my $pdf = $self->_generate_pdf( \@cards, $images ); + $promise->resolve($pdf); } - if ($real_number_of_cards > $MAX_CARDS) { - $promise->reject($ERR_TOO_MUCH_CARDS); + )->catch( + sub ($err) { + $promise->reject($err); } - my $pdf = $self->_generate_pdf(\@cards, $images); - $promise->resolve($pdf); - })->catch(sub ($err) { - $promise->reject($err); - }); + ); + } return $promise; } -sub _generate_pdf($self, $cards, $images) { +sub _generate_pdf ( $self, $cards, $images ) { my $number_image = 0; - my $pdf = PDF::API2->new; - my $page = $pdf->page; + my $pdf = PDF::API2->new; + my $page = $pdf->page; $page->size('A4'); - my @rectangle = $page->size; - my $n_pixels_per_cm = $rectangle[2] / 21.0; + my @rectangle = $page->size; + my $n_pixels_per_cm = $rectangle[2] / 21.0; for my $card (@$cards) { - my $images_card = $images->{$card->{scryfallId}}; - for my $image_kind (keys %$images_card) { - for (my $i = 0; $i < $card->{quantity}; $i++) { - if ($number_image > 8) { + my $images_card = $images->{ $card->{scryfallId} }; + for my $image_kind ( keys %$images_card ) { + for ( my $i = 0 ; $i < $card->{quantity} ; $i++ ) { + if ( $number_image > 8 ) { $number_image = 0; - $page = $pdf->page; + $page = $pdf->page; $page->size('A4'); } - my $margin_left = 25; - my $margin_bottom = 25; - my $mtg_card_width = 6.3; - my $mtg_card_height = 8.8; + my $margin_left = 25; + my $margin_bottom = 25; + my $mtg_card_width = 6.3; + my $mtg_card_height = 8.8; my $small_line_to_cut_better_size = 0.5; open my $fh, '<', \$images_card->{$image_kind}; - my $image = $pdf->image($fh, format => 'jpeg'); + my $image = $pdf->image( $fh, format => 'jpeg' ); my $page_position_x = $number_image % 3; - my $page_position_y = abs(int($number_image / 3) - 2); - $page->object($image, - $margin_bottom + $page_position_x * $mtg_card_width * $n_pixels_per_cm + $small_line_to_cut_better_size * $page_position_x, - $margin_bottom + $page_position_y * $mtg_card_height * $n_pixels_per_cm + $small_line_to_cut_better_size * $page_position_x, + my $page_position_y = abs( int( $number_image / 3 ) - 2 ); + $page->object( + $image, + $margin_bottom + + $page_position_x * $mtg_card_width * $n_pixels_per_cm + + $small_line_to_cut_better_size * $page_position_x, + $margin_bottom + + $page_position_y * $mtg_card_height * $n_pixels_per_cm + + $small_line_to_cut_better_size * $page_position_x, $n_pixels_per_cm * $mtg_card_width, ); $number_image++; @@ -106,7 +126,7 @@ sub _generate_pdf($self, $cards, $images) { return $pdf->to_string; } -sub _get_cards_images( $self, $cards ) { +sub _get_cards_images ( $self, $cards ) { my %card_images; my @promises; my $ua = $self->_ua; @@ -114,11 +134,11 @@ sub _get_cards_images( $self, $cards ) { my $scryfallId = $card->{scryfallId}; my ( $first, $second ) = $scryfallId =~ /^(.)(.)/; my $url_front = - "https://cards.scryfall.io/normal/front/$first/$second/$scryfallId.jpg"; +"https://cards.scryfall.io/normal/front/$first/$second/$scryfallId.jpg"; my $url_back = - "https://cards.scryfall.io/normal/back/$first/$second/$scryfallId.jpg"; +"https://cards.scryfall.io/normal/back/$first/$second/$scryfallId.jpg"; my $promise_front = Mojo::Promise->new; - my $promise_back = Mojo::Promise->new; + my $promise_back = Mojo::Promise->new; $ua->get_p($url_front)->then( sub ($res) { my $content_type = $res->result->headers->content_type; @@ -157,22 +177,26 @@ sub _get_cards_images( $self, $cards ) { push @promises, $promise_back; } my $final_promise = Mojo::Promise->new; - Mojo::Promise->all(@promises)->then(sub { - $final_promise->resolve(\%card_images); - })->catch(sub ($err) { - $final_promise->reject($err); - }); + Mojo::Promise->all(@promises)->then( + sub { + $final_promise->resolve( \%card_images ); + } + )->catch( + sub ($err) { + $final_promise->reject($err); + } + ); return $final_promise; } -sub _fill_scryfall_id( $self, $card ) { +sub _fill_scryfall_id ( $self, $card ) { if ( $card->{type} eq 'token' ) { return $self->_fill_scryfall_id_token($card); } return $self->_fill_scryfall_id_card($card); } -sub _fill_scryfall_id_card( $self, $card ) { +sub _fill_scryfall_id_card ( $self, $card ) { my $db = $self->_db_all_printings; my $query = <<'EOF'; select scryfallId @@ -194,7 +218,7 @@ EOF return { %$card, }; } -sub _fill_scryfall_id_token( $self, $token ) { +sub _fill_scryfall_id_token ( $self, $token ) { my $db = $self->_db_all_printings; my $query = <<'EOF'; SELECT scryfallId @@ -203,28 +227,30 @@ FROM tokens ON tokens.uuid = tokenIdentifiers.uuid WHERE tokens.name = ? EOF - my @args = ($token->{name}); - $query .= ' AND LOWER(tokens.setCode) = LOWER(?)' if defined $token->{set_code}; + my @args = ( $token->{name} ); + $query .= ' AND LOWER(tokens.setCode) = LOWER(?)' + if defined $token->{set_code}; push @args, $token->{set_code} if defined $token->{set_code}; $query .= ' LIMIT 1'; - my $result = $db->selectrow_hashref( $query, undef, @args); + my $result = $db->selectrow_hashref( $query, undef, @args ); if ( !defined $result ) { - $self->last_invalid_card( -"@{[$token->{quantity}]} @{[$token->{name}]} @{[$token->{set_code}]}" - ); + my $last_invalid_card = "@{[$token->{quantity}]} @{[$token->{name}]}"; + $last_invalid_card .= " @{[$token->{set_code}]}" + if defined $token->{set_code}; + $self->last_invalid_card($last_invalid_card); die $ERR_INVALID_CARD; } $token->{scryfallId} = $result->{scryfallId}; return {%$token}; } -sub _filter_lines( $self, $arg ) { +sub _filter_lines ( $self, $arg ) { return 0 if $arg =~ /^\w+:\s*$/; return 0 if $arg =~ /^\s*$/; return 1; } -sub _parse_token( $self, $line ) { +sub _parse_token ( $self, $line ) { my ( $quantity, $name, $set_code ); if ( !( @@ -245,7 +271,7 @@ sub _parse_token( $self, $line ) { }; } -sub _parse_card( $self, $line ) { +sub _parse_card ( $self, $line ) { if ( $line !~ /\(/ ) { return $self->_parse_token($line); } diff --git a/lib/TgMagicPdf/Telegram.pm b/lib/TgMagicPdf/Telegram.pm index ff494ec..5b10906 100644 --- a/lib/TgMagicPdf/Telegram.pm +++ b/lib/TgMagicPdf/Telegram.pm @@ -20,12 +20,12 @@ has _ua => ( is => 'lazy', ); has _last_offset_update => ( is => 'rw', ); -sub _build__token($self) { +sub _build__token ($self) { require TgMagicPdf; return TgMagicPdf->new->config->{telegram}{token}; } -sub run($self) { +sub run ($self) { $self->_dispatch_updates; Mojo::IOLoop->recurring( 5 => sub { @@ -34,7 +34,7 @@ sub run($self) { ); } -sub _dispatch_updates($self) { +sub _dispatch_updates ($self) { my $updates_p = $self->_get_updates; $updates_p->then( sub ($res) { @@ -45,12 +45,12 @@ sub _dispatch_updates($self) { } )->catch( sub ($err) { - say $err; + warn $err; } ); } -sub _dispatch_update( $self, $update ) { +sub _dispatch_update ( $self, $update ) { if ( !defined $self->_last_offset_update || $self->_last_offset_update < $update->{update_id} ) { @@ -61,68 +61,91 @@ sub _dispatch_update( $self, $update ) { } } -sub _handle_message( $self, $message ) { +sub sendMessage ( $self, $chat_id, $text ) { + my $url = "@{[$self->_tg_root]}/sendMessage"; + my $ua = $self->_ua; + $ua->post_p( $url, json => { chat_id => $chat_id, text => $text } ); +} + +sub _handle_message ( $self, $message ) { my $chat_type = $message->{chat}{type}; if ( $chat_type ne 'private' ) { return; } - my $chat_id = $message->{chat}{id}; - my $text = $message->{text}; - if (!defined $text) { + my $chat_id = $message->{chat}{id}; + my $text = $message->{text}; + if ( !defined $text ) { return; } + $self->sendMessage( $chat_id, + 'Got your message, attempting to generate a pdf.' ); my $pdf_builder = TgMagicPdf::PdfBuilder->new; - my $pdf_p; - eval { - $pdf_p = $pdf_builder->from_text($text); - $pdf_p->then(sub ($pdf) { - $self->sendDocument($chat_id, 'mtgprint.pdf', $pdf); - })->catch(sub ($err) { - if ($err eq $TgMagicPdf::PdfBuilder::ERR_INVALID_CARD) { - warn $pdf_builder->last_invalid_card; - } - if ($err eq $TgMagicPdf::PdfBuilder::ERR_UNABLE_TO_FIND_IMAGE) { - warn $pdf_builder->last_invalid_card; - } - warn $err - }); - }; - if ($@) { - if ($@ eq $TgMagicPdf::PdfBuilder::ERR_INVALID_CARD) { - warn $pdf_builder->last_invalid_card; + $pdf_builder->from_text($text)->then( + sub ($pdf) { + $self->sendDocument( $chat_id, 'mtgprint.pdf', $pdf ); } - if ($@ eq $TgMagicPdf::PdfBuilder::ERR_UNABLE_TO_FIND_IMAGE) { - warn $pdf_builder->last_invalid_card; + )->catch( + sub ($err) { + 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/ at.*$//r; + 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; + } + $self->sendMessage( $chat_id, +'I could not process your deck take a look to this details: ' + . $error_to_user ); + return; + } + warn $err; + $self->sendMessage( $chat_id, + 'I could not process your deck because of a server error' ); } - warn $@; - return; - } + ); } -sub sendDocument($self, $chat_id, $filename, $file_contents) { +sub sendDocument ( $self, $chat_id, $filename, $file_contents ) { my $url = "@{[$self->_tg_root]}/sendDocument"; - my $ua = $self->_ua; - my $res = $ua->post($url, form => { - chat_id => $chat_id, - document => { - content => $file_contents, - 'Content-Type' => 'application/pdf', - filename => $filename, - }, - }); + my $ua = $self->_ua; + my $res = $ua->post_p( + $url, + form => { + chat_id => $chat_id, + document => { + content => $file_contents, + 'Content-Type' => 'application/pdf', + filename => $filename, + }, + } + ); } sub _pdf_builder { return TgMagicPdf::PdfBuilder->new; } -sub _build__ua($self) { +sub _build__ua ($self) { my $ua = Mojo::UserAgent->new; $ua->inactivity_timeout(30); return $ua; } -sub _get_updates($self) { +sub _get_updates ($self) { my $ua = $self->_ua; my $url = "@{[$self->_tg_root]}/getUpdates"; my %params; @@ -132,7 +155,7 @@ sub _get_updates($self) { return $ua->post_p( $url, json => {%params} ); } -sub _build__tg_root($self) { +sub _build__tg_root ($self) { return "https://api.telegram.org/bot@{[$self->_token]}"; } 1;