The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
package Amon2::Plugin::Web::Streaming;
use strict;
use warnings;
use utf8;

use Amon2::Util;
use Amon2::Web::Response::Callback;

sub init {
    my ($class, $c, $conf) = @_;

    Amon2::Util::add_method(ref $c || $c, 'streaming', \&_streaming);
    Amon2::Util::add_method(ref $c || $c, 'streaming_json', \&_streaming_json);
}

sub _streaming {
    my ($self, $code) = @_;
    
    return Amon2::Web::Response::Callback->new(
        code => sub {
            $code->(@_);
        }
    );
}

sub _streaming_json {
    my ($self, $code) = @_;

    return Amon2::Web::Response::Callback->new(
        code => sub {
            my $respond = shift;
            my $writer = $respond->([200, ['Content-Type' => 'application/json;charset=utf-8']]);

            my $longpoll_ctx = Amon2::Plugin::Web::Streaming::Writer->new(
                $self,
                $writer
            );
            $code->($longpoll_ctx);
        }
    );
}

package Amon2::Plugin::Web::Streaming::Writer;

sub new {
    my ($class, $c, $writer) = @_;
    bless {ctx => $c, writer => $writer}, $class;
}

sub write_json {
    my ($self, $data) = @_;
    my $json = $self->{ctx}->render_json($data)->content;
    $self->{writer}->write($json);
}

sub close {
    my ($self) = @_;
    $self->{writer}->close();
}

1;
__END__

=head1 NAME

Amon2::Plugin::Web::Streaming - streaming support for Amon2

=head1 SYNOPSIS

    use Amon2::Lite;

    __PACKAGE__->load_plugin(qw/Web::Streaming/);

    any '/poll' => sub {
        my $c = shift;
        return $c->streaming(sub {
            my $respond = shift;
            ...;
            $respond->write([200, [], ['OK']]);
        });
    };

    any '/poll_json' => sub {
        my $c = shift;
        return $c->streaming_json(sub {
            my $writer = shift;
            ...;
            $writer->write_json(+{ });
            $writer->close;
        });
    };


=head1 DESCRIPTION

This is an Amon2 plugin to support streaming.

You MUST use the HTTP server supporting psgi.streaming.

=head1 EXPORTED METHODS

=over 4

=item $c->streaming($code);

You can return delayed response for PSGI spec.

Argument for $code is C<< $respond >>. It's same as a argument for PSGI callback.

=item $c->streaming_json($code);

It's a short hand utility to publish streaming JSON.

The argument is instance of Amon2::Plugin::Web::Streaming::Writer.

=back

=head1 Amon2::Plugin::Streaming::Writer METHODS

=over 4

=item new

Do not create the instance directly.

=item $writer->write_json($data)

Write a $data as JSON for the socket.

=item $writer->close()

Close the socket.

=back


=head1 SEE ALSO

L<PSGI>