App-Phoebe
view release on metacpan or search on metacpan
lib/App/Phoebe/Oracle.pm view on Meta::CPAN
my $stream = shift;
my $url = shift;
my $hosts = oracle_regex();
my $port = port($stream);
my ($host, $question, $answer, $number, @numbers);
if (($host) = $url =~ m!^gemini://($hosts)(?::$port)?/$oracle_space/?$!) {
return serve_main_menu($stream, $host);
} elsif (($host) = $url =~ m!^gemini://($hosts)(?::$port)?/$oracle_space/questions$!) {
return serve_questions($stream, $host);
} elsif (($host, $question) = $url =~ m!^gemini://($hosts)(?::$port)?/$oracle_space/ask(?:\?([^#]+))?$!) {
return ask_question($stream, $host, decode_query($question));
} elsif (($host, $number) = $url =~ m!^gemini://($hosts)(?::$port)?/$oracle_space/question/(\d+)$!) {
return serve_question($stream, $host, $number);
} elsif (($host, $number, $answer) =
$url =~ m!^gemini://($hosts)(?::$port)?/$oracle_space/question/(\d+)/answer(?:\?([^#]+))?$!) {
return answer_question($stream, $host, $number, decode_query($answer));
} elsif (($host, $number) = $url =~ m!^gemini://($hosts)(?::$port)?/$oracle_space/question/(\d+)/publish$!) {
return publish_question($stream, $host, $number);
} elsif (($host, $number) = $url =~ m!^gemini://($hosts)(?::$port)?/$oracle_space/question/(\d+)/delete$!) {
return delete_question($stream, $host, $number);
} elsif (($host, @numbers) = $url =~ m!^gemini://($hosts)(?::$port)?/$oracle_space/question/(\d+)/(\d+)/delete$!) {
return delete_answer($stream, $host, @numbers);
} elsif (($host) = $url =~ m!^gemini://($hosts)(?::$port)?/$oracle_space/log$!) {
return serve_log($stream, $host);
}
return;
}
sub oracle_regex {
return join("|", map { quotemeta domain_to_ascii $_ } @oracle_hosts) || host_regex();
}
sub load_data {
my $host = shift;
my $dir = wiki_dir($host, $oracle_space);
return [] unless -f "$dir/oracle.json";
return decode_json read_binary("$dir/oracle.json");
}
sub save_data {
my ($stream, $host, $data) = @_;
my $dir = wiki_dir($host, $oracle_space);
my $bytes = encode_json $data;
# We don't close the stream on a successful call.
with_lock($stream, $host, $oracle_space, sub {
write_binary("$dir/oracle.json", $bytes)});
}
sub new_number {
my $data = shift;
while (1) {
my $n = int(rand(10000));
return $n unless any { $n eq $_->{number} } @$data;
}
}
sub decode_query {
my $text = shift;
return '' unless $text;
$text =~ s/\+/ /g;
return decode_utf8(uri_unescape($text));
}
sub serve_main_menu {
my ($stream, $host) = @_;
my $data = load_data($host);
my $fingerprint = $stream->handle->get_fingerprint();
success($stream);
$log->info("Serving oracles");
$stream->write("# Oracle\n");
if ($fingerprint) {
$stream->write("You have an identity or a client certificate picked, so you can ask a question or answer questions by others.\n");
} else {
$stream->write("You need to use an identity or pick a client certificate if you want to ask a question or give an answer.\n");
}
$stream->write("=> /$oracle_space/ask Ask a question\n");
$stream->write("=> /$oracle_space/log Check the log\n");
# skipping answered and unpublished questions, unless you asked the question
my @questions = grep {
$_->{status} ne 'answered'
or $fingerprint and $fingerprint eq $_->{fingerprint}
} @$data;
for my $question (@questions) {
$stream->write("\n\n");
$stream->write("## Question #$question->{number}\n");
$stream->write("> " . encode_utf8 $question->{text});
$stream->write("\n");
if ($fingerprint and $fingerprint eq $question->{fingerprint}) {
$stream->write("This is your question.");
$stream->write(" You need to publish or delete it before you can ask another one.")
if $question->{status} ne 'published';
$stream->write("\n");
$stream->write("=> /$oracle_space/question/$question->{number} Manage\n");
} elsif ($question->{status} eq 'asked') {
if ($fingerprint and any { $fingerprint eq $_->{fingerprint} } @{$question->{answers}}) {
$stream->write("This question is still looking for answers, but you already gave your answer.\n");
$stream->write("=> /$oracle_space/question/$question->{number} Take a look\n");
} else {
$stream->write("This question is still looking for answers.\n");
$stream->write("=> /$oracle_space/question/$question->{number} Answer\n");
}
} else {
# it's published
my $n = grep { $_->{text} } @{$question->{answers}};
if ($n == 1) {
$stream->write("This question has one answer.\n");
} else {
$stream->write("This question has $n answers.\n");
}
$stream->write("=> /$oracle_space/question/$question->{number} Show\n");
}
}
return 1;
}
sub serve_log {
my ($stream, $host) = @_;
my $data = load_data($host);
success($stream);
$log->info("Serving oracle log");
$stream->write("# Oracle Log\n");
( run in 0.934 second using v1.01-cache-2.11-cpan-39bf76dae61 )