+ mark_found($self, $cur_want, $existing);
+ goto \&next_step; # onto patch application
+ } elsif ($existing > 0) {
+ goto \&retry_current;
+ } else { # $existing == 0: we may retry if inbox scan (below) fails
+ delete $want->{try_gits};
+ }
+
+ # scan through inboxes to look for emails which results in
+ # the oid we want:
+ my $ibx = shift(@{$want->{try_ibxs}}) or die 'BUG: {try_ibxs} empty';
+ if (my $msgs = find_smsgs($self, $ibx, $want)) {
+ $want->{try_smsgs} = $msgs;
+ $want->{cur_ibx} = $ibx;
+ $self->{tmp_diffs} = [];
+ goto \&retry_current;
+ }
+ goto \&try_harder;
+}
+
+# this API is designed to avoid creating self-referential structures;
+# so user_cb never references the SolverGit object
+sub new {
+ my ($class, $ibx, $user_cb, $uarg) = @_;
+
+ bless {
+ gits => $ibx->{-repo_objs},
+ user_cb => $user_cb,
+ uarg => $uarg,
+ # -cur_di, -qsp, -msg => temporary fields for Qspawn callbacks
+
+ # TODO: config option for searching related inboxes
+ inboxes => [ $ibx ],
+ }, $class;
+}
+
+# recreate $oid_want using $hints
+# hints keys: path_a, path_b, oid_a (note: `oid_b' is NOT a hint)
+# Calls {user_cb} with: [ ::Git object, oid_full, type, size, di (diff_info) ]
+# with found object, or undef if nothing was found
+# Calls {user_cb} with a string error on fatal errors
+sub solve ($$$$$) {
+ my ($self, $env, $out, $oid_want, $hints) = @_;
+
+ # should we even get here? Probably not, but somebody
+ # could be manually typing URLs:
+ return done($self, undef) if $oid_want =~ /\A0+\z/;
+
+ $self->{oid_want} = $oid_want;
+ $self->{out} = $out;
+ $self->{seen_oid} = {};
+ $self->{tot} = 0;
+ $self->{psgi_env} = $env;
+ $self->{todo} = [ { %$hints, oid_b => $oid_want } ];
+ $self->{patches} = []; # [ $di, $di, ... ]
+ $self->{found} = {}; # { abbr => [ ::Git, oid, type, size, $di ] }
+ $self->{tmp} = File::Temp->newdir("solver.$oid_want-XXXXXXXX", TMPDIR => 1);
+
+ dbg($self, "solving $oid_want ...");
+ if (my $async = $env->{'pi-httpd.async'}) {
+ # PublicInbox::HTTPD::Async->new
+ $async->(undef, undef, $self);
+ } else {
+ event_step($self) while $self->{user_cb};