Dancer2

 view release on metacpan or  search on metacpan

Changes  view on Meta::CPAN

    * GH #916: Fix test example. (Peter Mottram - @SysPete)
    * GH #912, #913: Fix documentation on when stacks are printed.
      (Andrew Solomon)

0.160001  2015-05-14 20:40:10+02:00 Europe/Amsterdam

    [ BUG FIXES ]
    * GH #893, #895: Catch config parse errors when Config::Any doesn't throw
      them. (Russell Jenkins)
    * GH #899: Minimum YAML version supported is v0.86 (Shlomi Fish)
    * GH #906: send_file - missing import and fix logic error for streaming
      by default (Russell Jenkins)

    [ DOCUMENTATION ]
    * GH #897: Remove docs for unimplemented 'load' keyword (Fayland Lam)

    [ ENHANCEMENT ]
    * GH #894, #898: Add status and headers methods to ::Response::Delayed
      (Yanick Champoux, Charlie Gonzalez)

0.160000  2015-04-27 00:12:55+02:00 Europe/Amsterdam

Changes  view on Meta::CPAN

    [ BUG FIXES ]
    * GH #856: Memory leak when throwing exception from a hook. (Sawyer X)

0.159001  2015-02-25 15:31:35+01:00 Europe/Amsterdam

    [ BUG FIXES ]
    * GH #855: Ensure Dancer2::Test is compatible with Pod::Simple 3.30.
      (Russell Jenkins)

    [ DOCUMENTATION ]
    * Add an example for delayed (async) streaming response. (Sawyer X)
    * Small link fix. (Sawyer X)

0.159000  2015-02-24 04:51:20+01:00 Europe/Amsterdam

    [ BUG FIXES ]
    * GH #762: Delay app cleanup until errors are rendered. (Russell Jenkins)
    * GH #835: Correct Logic error in Logger if no request exists.
               (Lennart Hengstmengel)
    * GH #839: Correct "no_server_tokens" definition in production.yml.
               (Nikita K)

lib/Dancer2/Core/App.pm  view on Meta::CPAN

    ( exists $options{'charset'} ) and $charset = $options{'charset'};
    $content_type .= "; charset=$charset" if $content_type and $charset;
    ( defined $content_type )
      and $self->response->header('Content-Type' => $content_type );

    # content disposition
    ( exists $options{filename} )
      and $self->response->header( 'Content-Disposition' =>
          ($options{content_disposition} || "attachment") . "; filename=\"$options{filename}\"" );

    # use a delayed response unless server does not support streaming
    my $use_streaming = exists $options{streaming} ? $options{streaming} : 1;
    my $response;
    my $env = $self->request->env;
    if ( $env->{'psgi.streaming'} && $use_streaming ) {
        my $cb = sub {
            my $responder = $Dancer2::Core::Route::RESPONDER;
            my $res = $Dancer2::Core::Route::RESPONSE;
            return $responder->(
                [ $res->status, $res->headers_to_array, $fh ]
            );
        };

        Scalar::Util::weaken( my $weak_self = $self );

lib/Dancer2/Core/DSL.pm  view on Meta::CPAN

        local $Dancer2::Core::Route::RESPONDER     = $responder;
        local $Dancer2::Core::Route::WRITER        = $writer;
        local $Dancer2::Core::Route::ERROR_HANDLER = $handler;

        $cb->(@_);
    };
}

sub flush {
    my $responder = $Dancer2::Core::Route::RESPONDER
        or croak 'flush() called outside streaming response';

    my $response = $Dancer2::Core::Route::RESPONSE;
    $Dancer2::Core::Route::WRITER = $responder->([
        $response->status, $response->headers_to_array,
    ]);
}

sub done {
    my $writer = $Dancer2::Core::Route::WRITER
        or croak 'done() called outside streaming response';

    $writer->close;
}

sub pass         { shift->app->pass }

#
# Route handler helpers
#

lib/Dancer2/Core/Response/Delayed.pm  view on Meta::CPAN

        error_cb  => sub {
            my ($error) = @_;
            ...
        },
    );

    # or in an app
    get '/' => sub {
        # delayed response:
        delayed {
            # streaming content
            content "data";
            content "more data";

            # close user connection
            done;
        } on_error => sub {
            my ($error) = @_;
            warning 'Failed to stream to user: ' . request->remote_address;
        };
    };

lib/Dancer2/Manual.pod  view on Meta::CPAN

=head2 Delayed responses (Async/Streaming)

L<Dancer2> can provide delayed (otherwise known as I<asynchronous>) responses
using the C<delayed> keyword. These responses are streamed, although you can
set the content all at once, if you prefer.

    get '/status' => sub {
        delayed {
            response_header 'X-Foo' => 'Bar';

            # flush headers (in case of streaming)
            flush;

            # send content to the user
            content 'Hello, world!';

            # you can write more content
            # all streaming
            content 'Hello, again!';

            # when done, close the connection
            done;

            # do whatever you want else, asynchronously
            # the user socket closed by now
            ...
        };
    };

If you are streaming (calling C<content> several times), you must call
C<flush> first. If you're sending only once, you don't need to call C<flush>.

Here is an example of using delayed responses with L<AnyEvent>:

    use Dancer2;
    use AnyEvent;

    my %timers;
    my $count = 5;
    get '/drums' => sub {
        delayed {
            print "Stretching...\n";
            flush; # necessary, since we're streaming

            $timers{'Snare'} = AE::timer 1, 1, delayed {
                $timers{'HiHat'} ||= AE::timer 0, 0.5, delayed {
                    content "Tss...\n";
                };

                content "Bap!\n";

                if ( $count-- == 0 ) {
                    %timers = ();

lib/Dancer2/Manual.pod  view on Meta::CPAN

    use Path::Tiny    qw< path >;
    use JSON::MaybeXS qw< encode_json >;
    # Create CSV parser
    my $csv = Text::CSV_XS->new({
        binary    => 1,
        auto_diag => 1,
    });
    get '/' => sub {
        # delayed response:
        delayed {
            # streaming content
            flush;
            # Read each row and stream it in JSON
            my $fh = path('filename.csv')->openr_utf8;
            while ( my $row = $csv->getline($fh) ) {
                content encode_json $row;
            }
            # close user connection
            done;
        } on_error => sub {
            my ($error) = @_;

lib/Dancer2/Manual/Keywords.pod  view on Meta::CPAN

Advent Calendar.

=head2 dirname

Returns the dirname of the path given:

    my $dir = dirname($some_path);

=head2 done

Close the streaming connection. Can only be called within a streaming 
response callback.

=head2 dsl

Allows access to the DSL within your plugin/application. Is an instance of
L<Dancer2::Core::DSL>.

=head2 encode_json ($structure)

Serializes a structure to a UTF-8 binary JSON string.

lib/Dancer2/Manual/Keywords.pod  view on Meta::CPAN


See L<Dancer2::Core::Role::Logger> for details on how to configure where log
messages go.

=head2 false

Constant that returns a false value (0).

=head2 flush

Flush headers when streaming a response. Necessary when L</content> is called
multiple times.

=head2 forward

Runs an "internal redirect" of the current route to another route. More
formally; when C<forward> is executed, the current dispatch of the route is
aborted, the request is modified (altering query params or request method),
and the modified request following a new route is dispatched again. Any
remaining code (route and hooks) from the current dispatch will never be run
and the modified route's dispatch will execute hooks for the new route normally.

lib/Dancer2/Manual/Keywords.pod  view on Meta::CPAN

    get '/some/route' => sub {
        if (...) {
            # OK, send her what she wants...
            send_file(...);

            # this code will be ignored
            do_stuff();
        }
    };

C<send_file> will use PSGI streaming if the server supports it (most, if
not all, do). You can explicitly disable streaming by passing
C<streaming =E<gt> 0> as an option to C<send_file>.

    get '/download/:file' => sub {
        send_file( route_parameters->get('file'), streaming => 0 );
    }

The content-type will be set depending on the current MIME types definition
(see C<mime> if you want to define your own).

If your filename does not have an extension, you are passing in a filehandle,
or you need to force a specific mime type, you can pass it to C<send_file>
as follows:

    send_file(route_parameters->get('file'), content_type => 'image/png');

t/dsl/send_file.t  view on Meta::CPAN

    };

    get '/check_content_type' => sub {
        my $temp = File::Temp->new();
        print $temp "hello";
        close $temp;
        send_file($temp->filename, content_type => 'image/png',
                                   system_path  => 1);
    };

    get '/no_streaming' => sub {
        my $file = File::Spec->rel2abs(__FILE__);
        send_file( $file, system_path => 1, streaming => 0 );
    };

    get '/options_streaming' => sub {
        my $file = File::Spec->rel2abs(__FILE__);
        send_file( $file, system_path => 1, streaming => 1 );
    };

    get '/content_disposition/attachment' => sub {
        send_file('1x1.png', filename => '1x1.png');
    };

    get '/content_disposition/inline' => sub {
        send_file('1x1.png', filename => '1x1.png', content_disposition => 'inline');
    };
}

t/dsl/send_file.t  view on Meta::CPAN


    subtest "filehandles" => sub {
        my $r = $cb->( GET '/filehandle' );

        is( $r->code, 200, 'send_file set status to 200 (filehandle)');
        is( $r->content_type, 'text/plain', 'expected content_type');
        is( $r->content_type_charset, 'UTF-8', 'expected charset');
        like( $r->content, qr{package StaticContent}, 'filehandle content' );
    };

    subtest "no streaming" => sub {
        my $r = $cb->( GET '/no_streaming' ); 
        is( $r->code, 200, 'send_file set status to 200 (no streaming)');
        like( $r->content, qr{package StaticContent}, 'no streaming - content' );
    };

    subtest "options streaming" => sub {
        my $r = $cb->( GET '/options_streaming' ); 
        is( $r->code, 200, 'send_file set status to 200 (options streaming)');
        like( $r->content, qr{package StaticContent}, 'options streaming - content' );
    };

    subtest 'send_file returns correct content type' => sub {
        my $r = $cb->( GET '/check_content_type' );

        ok($r->is_success, 'send_file returns success');
        is($r->content_type, 'image/png', 'send_file returns correct content_type');
    };

    subtest 'Content-Disposition defaults to "attachment"' => sub {



( run in 0.283 second using v1.01-cache-2.11-cpan-4d50c553e7e )