From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on dcvr.yhbt.net X-Spam-Level: X-Spam-Status: No, score=-4.0 required=3.0 tests=ALL_TRUSTED,BAYES_00 shortcircuit=no autolearn=ham autolearn_force=no version=3.4.2 Received: from localhost (dcvr.yhbt.net [127.0.0.1]) by dcvr.yhbt.net (Postfix) with ESMTP id 3E8FF1F92E for ; Sun, 5 Jul 2020 23:28:11 +0000 (UTC) From: Eric Wong To: meta@public-inbox.org Subject: [PATCH 28/43] view: make /$INBOX/$MSGID/ permalink async Date: Sun, 5 Jul 2020 23:27:44 +0000 Message-Id: <20200705232759.3161-29-e@yhbt.net> In-Reply-To: <20200705232759.3161-1-e@yhbt.net> References: <20200705232759.3161-1-e@yhbt.net> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit List-Id: This will allow -httpd to handle other requusts if waiting on an HDD seek or git to decode a blob. --- lib/PublicInbox/View.pm | 38 ++++++++++++++++------------------ lib/PublicInbox/WwwStream.pm | 40 +++++++++++++++++++++++++++++++----- 2 files changed, 53 insertions(+), 25 deletions(-) diff --git a/lib/PublicInbox/View.pm b/lib/PublicInbox/View.pm index 243528263..98445f0e0 100644 --- a/lib/PublicInbox/View.pm +++ b/lib/PublicInbox/View.pm @@ -27,24 +27,22 @@ use constant TCHILD => '` '; sub th_pfx ($) { $_[0] == 0 ? '' : TCHILD }; sub msg_page_i { - my ($ctx) = @_; - my $cur = delete $ctx->{smsg} or return; # undef: done - my $nxt; - if (my $over = $ctx->{-inbox}->over) { - $nxt = $ctx->{smsg} = $over->next_by_mid(@{$ctx->{next_arg}}); + my ($ctx, $eml) = @_; + if ($eml) { # called by WwwStream::async_eml or getline + my $smsg = $ctx->{smsg}; + $ctx->{smsg} = $ctx->{over}->next_by_mid(@{$ctx->{next_arg}}); + $ctx->{mhref} = ($ctx->{nr} || $ctx->{smsg}) ? + "../${\mid_href($smsg->{mid})}/" : ''; + my $hdr = $eml->header_obj; + my $obuf = $ctx->{obuf} = _msg_page_prepare_obuf($hdr, $ctx); + multipart_text_as_html($eml, $ctx); + delete $ctx->{obuf}; + $$obuf .= '
'; + $$obuf .= html_footer($ctx, $ctx->{first_hdr}) if !$ctx->{smsg}; + $$obuf; + } else { # called by WwwStream::async_next or getline + $ctx->{smsg}; # may be undef } - $ctx->{mhref} = ($ctx->{nr} || $nxt) ? - "../${\mid_href($cur->{mid})}/" : ''; - my $eml = $ctx->{-inbox}->smsg_eml($cur) or return; - my $hdr = $eml->header_obj; - my $obuf = $ctx->{obuf} = _msg_page_prepare_obuf($hdr, $ctx); - multipart_text_as_html($eml, $ctx); - delete $ctx->{obuf}; - $$obuf .= '
'; - # we want to at least show the message if something - # here crashes: - eval { $$obuf .= html_footer($ctx, $ctx->{first_hdr}) } if !$nxt; - $$obuf; } # /$INBOX/$MESSAGE_ID/ for unindexed v1 inboxes @@ -74,11 +72,11 @@ sub msg_page { my ($ctx) = @_; my $ibx = $ctx->{-inbox}; $ctx->{-obfs_ibx} = $ibx->{obfuscate} ? $ibx : undef; - my $over = $ibx->over or return no_over_html($ctx); + my $over = $ctx->{over} = $ibx->over or return no_over_html($ctx); my ($id, $prev); my $next_arg = $ctx->{next_arg} = [ $ctx->{mid}, \$id, \$prev ]; - $ctx->{smsg} = $over->next_by_mid(@$next_arg) or return; - PublicInbox::WwwStream::response($ctx, 200, \&msg_page_i); + $ctx->{smsg} = $over->next_by_mid(@$next_arg) or return; # undef == 404 + PublicInbox::WwwStream::aresponse($ctx, 200, \&msg_page_i); } # /$INBOX/$MESSAGE_ID/#R diff --git a/lib/PublicInbox/WwwStream.pm b/lib/PublicInbox/WwwStream.pm index 42fb183f4..eecc27019 100644 --- a/lib/PublicInbox/WwwStream.pm +++ b/lib/PublicInbox/WwwStream.pm @@ -15,9 +15,6 @@ use PublicInbox::Hval qw(ascii_html prurl); our $TOR_URL = 'https://www.torproject.org/'; our $CODE_URL = 'https://public-inbox.org/public-inbox.git'; -# noop for HTTP.pm (and any other PSGI servers) -sub close {} - sub base_url ($) { my $ctx = shift; my $base_url = $ctx->{-inbox}->base_url($ctx->{env}); @@ -40,6 +37,11 @@ sub response { [ $code, $res_hdr, $ctx ] } +sub async_eml { # ->{async_eml} for async_blob_cb + my ($ctx, $eml) = @_; + $ctx->{http_out}->write($ctx->translate($ctx->{cb}->($ctx, $eml))); +} + sub html_top ($) { my ($ctx) = @_; my $ibx = $ctx->{-inbox}; @@ -157,8 +159,14 @@ EOF sub getline { my ($ctx) = @_; my $cb = $ctx->{cb} or return; - if (defined(my $buf = $cb->($ctx))) { - return $ctx->translate($buf); + while (defined(my $x = $cb->($ctx))) { # x = smsg or scalar non-ref + if (ref($x)) { # smsg + my $eml = $ctx->{-inbox}->smsg_eml($x) or next; + $ctx->{smsg} = $x; + return $ctx->translate($cb->($ctx, $eml)); + } else { # scalar + return $ctx->translate($x); + } } delete $ctx->{cb}; $ctx->zflush(_html_end($ctx)); @@ -179,4 +187,26 @@ sub html_oneshot ($$;$) { [ $code, $res_hdr, \@bdy ] } +sub async_next ($) { + my ($http) = @_; # PublicInbox::HTTP + my $ctx = $http->{forward} or return; + eval { + if (my $smsg = $ctx->{smsg} = $ctx->{cb}->($ctx)) { + $ctx->smsg_blob($smsg); + } else { + $ctx->{http_out}->write( + $ctx->translate(_html_end($ctx))); + $ctx->close; # GzipFilter->close + } + }; + warn "E: $@" if $@; +} + +sub aresponse { + my ($ctx, $code, $cb) = @_; + my $res_hdr = [ 'Content-Type' => 'text/html; charset=UTF-8' ]; + init($ctx, $cb); + $ctx->psgi_response($code, $res_hdr, \&async_next, \&async_eml); +} + 1;