# Copyright (C) all contributors # License: AGPL-3.0+ # connects public-inbox processes to PublicInbox::Gcf2::loop() package PublicInbox::Gcf2Client; use v5.12; use parent qw(PublicInbox::DS); use PublicInbox::Git; use PublicInbox::Gcf2; # fails if Inline::C or libgit2-dev isn't available use PublicInbox::Spawn qw(spawn); use Socket qw(AF_UNIX SOCK_STREAM); use PublicInbox::Syscall qw(EPOLLIN); use PublicInbox::IO; use autodie qw(socketpair); # fields: # sock => socket to Gcf2::loop # The rest of these fields are compatible with what PublicInbox::Git # uses code-sharing # pid => PID of Gcf2::loop process # pid.owner => process which spawned {pid} # in => same as {sock}, for compatibility with PublicInbox::Git # inflight => array (see PublicInbox::Git) sub new { my ($opt) = @_; my $self = bless {}, __PACKAGE__; # ensure the child process has the same @INC we do: my $env = { PERL5LIB => join(':', @INC) }; socketpair(my $s1, my $s2, AF_UNIX, SOCK_STREAM, 0); $s1->blocking(0); $opt->{0} = $opt->{1} = $s2; my $cmd = [$^X, $^W ? ('-w') : (), qw[-MPublicInbox::Gcf2 -e PublicInbox::Gcf2::loop]]; $self->{inflight} = []; PublicInbox::IO::attach_pid($s1, spawn($cmd, $env, $opt), \&PublicInbox::Git::gcf_drain, $self->{inflight}); $self->{epwatch} = \undef; # for Git->cleanup $self->SUPER::new($s1, EPOLLIN); } sub gcf2_async ($$$;$) { my ($self, $req, $cb, $arg) = @_; my $inflight = $self->gcf_inflight or return; PublicInbox::Git::write_all($self, $req, \&cat_async_step, $inflight); push @$inflight, \$req, $cb, $arg; # ref prevents Git.pm retries } # ensure PublicInbox::Git::cat_async_step never calls cat_async_retry sub alternates_changed {} no warnings 'once'; *gcf_inflight = \&PublicInbox::Git::gcf_inflight; # for event_step *cat_async_step = \&PublicInbox::Git::cat_async_step; # for event_step *event_step = \&PublicInbox::Git::event_step; *fail = \&PublicInbox::Git::fail; *DESTROY = \&PublicInbox::Git::DESTROY; 1;