user/dev discussion of public-inbox itself
 help / color / mirror / code / Atom feed
a7c7cbc1239e6025e6594524a68ed803263dfcb1 blob 3324 bytes (raw)

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
 
# Copyright (C) 2019-2020 all contributors <meta@public-inbox.org>
# License: AGPL-3.0+ <https://www.gnu.org/licenses/agpl-3.0.txt>

# Provide an HTTP-accessible listing of inboxes.
# Used by PublicInbox::WWW
package PublicInbox::WwwListing;
use strict;
use PublicInbox::Hval qw(ascii_html prurl fmt_ts);
use PublicInbox::Linkify;
use PublicInbox::GzipFilter qw(gzf_maybe);
use PublicInbox::ManifestJsGz;
use bytes (); # bytes::length

sub list_all_i {
	my ($ibx, $list, $hide_key) = @_;
	push @$list, $ibx unless $ibx->{-hide}->{$hide_key};
}

sub list_all ($$$) {
	my ($self, $env, $hide_key) = @_;
	my $list = [];
	$self->{pi_config}->each_inbox(\&list_all_i, $list, $hide_key);
	$list;
}

sub list_match_domain_i {
	my ($ibx, $list, $hide_key, $re) = @_;
	if (!$ibx->{-hide}->{$hide_key} && grep(/$re/, @{$ibx->{url}})) {
		push @$list, $ibx;
	}
}

sub list_match_domain ($$$) {
	my ($self, $env, $hide_key) = @_;
	my $list = [];
	my $host = $env->{HTTP_HOST} // $env->{SERVER_NAME};
	$host =~ s/:[0-9]+\z//;
	$self->{pi_config}->each_inbox(\&list_match_domain_i, $list, $hide_key,
				qr!\A(?:https?:)?//\Q$host\E(?::[0-9]+)?/!i);
	$list;
}

sub list_404 ($$) { [] }

# TODO: +cgit
my %VALID = (
	all => \&list_all,
	'match=domain' => \&list_match_domain,
	404 => \&list_404,
);

sub set_cb ($$$) {
	my ($pi_config, $k, $default) = @_;
	my $v = $pi_config->{lc $k} // $default;
	$VALID{$v} || do {
		warn <<"";
`$v' is not a valid value for `$k'
$k be one of `all', `match=domain', or `404'

		$VALID{$default};
	};
}

sub new {
	my ($class, $www) = @_;
	my $pi_config = $www->{pi_config};
	bless {
		pi_config => $pi_config,
		style => $www->style("\0"),
		www_cb => set_cb($pi_config, 'publicInbox.wwwListing', 404),
		manifest_cb => set_cb($pi_config, 'publicInbox.grokManifest',
					'match=domain'),
	}, $class;
}

sub ibx_entry {
	my ($mtime, $ibx, $env) = @_;
	my $ts = fmt_ts($mtime);
	my $url = prurl($env, $ibx->{url});
	my $tmp = <<"";
* $ts - $url
  ${\$ibx->description}

	if (defined(my $info_url = $ibx->{infourl})) {
		$tmp .= '  ' . prurl($env, $info_url) . "\n";
	}
	$tmp;
}

sub html ($$) {
	my ($env, $list) = @_;
	my $h = [ 'Content-Type', 'text/html; charset=UTF-8',
			'Content-Length', undef ];
	my $gzf = gzf_maybe($h, $env);
	$gzf->zmore('<html><head><title>' .
				'public-inbox listing</title>' .
				'</head><body><pre>');
	my $code = 404;
	if (@$list) {
		$code = 200;
		# Schwartzian transform since Inbox->modified is expensive
		@$list = sort {
			$b->[0] <=> $a->[0]
		} map { [ $_->modified, $_ ] } @$list;

		my $tmp = join("\n", map { ibx_entry(@$_, $env) } @$list);
		my $l = PublicInbox::Linkify->new;
		$gzf->zmore($l->to_html($tmp));
	} else {
		$gzf->zmore('no inboxes, yet');
	}
	my $out = $gzf->zflush('</pre><hr><pre>'.
				PublicInbox::WwwStream::code_footer($env) .
				'</pre></body></html>');
	$h->[3] = bytes::length($out);
	[ $code, $h, [ $out ] ];
}

# not really a stand-alone PSGI app, but maybe it could be...
sub call {
	my ($self, $env) = @_;

	if ($env->{PATH_INFO} eq '/manifest.js.gz') {
		# grokmirror uses relative paths, so it's domain-dependent
		my $list = $self->{manifest_cb}->($self, $env, 'manifest');
		PublicInbox::ManifestJsGz::response($env, $list);
	} else { # /
		my $list = $self->{www_cb}->($self, $env, 'www');
		html($env, $list);
	}
}

1;
debug log:

solving a7c7cbc1 ...
found a7c7cbc1 in https://80x24.org/public-inbox.git

Code repositories for project(s) associated with this inbox:

	https://80x24.org/public-inbox.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).