Dancer-Plugin-StreamData

 view release on metacpan or  search on metacpan

lib/Dancer/Plugin/StreamData.pm  view on Meta::CPAN

    # since. This gets around the problem of this routine (prepare_stream())
    # being called twice.
    
    if ( !defined $stream_status )
    {
	$stream_status = $status;
	@stream_headers = ();
	
	# We filter the headers to remove content-length, since we don't
	# necessarily know what the content length is going to be (that's one
	# of the advantages of using this module).
	
	for ( my $i = 0; $i < @$headers; $i = $i + 2 )
	{
	    if ( $headers->[$i] !~ /content-length/i )
	    {
		push @stream_headers, $headers->[$i];
		push @stream_headers, $headers->[$i+1];
	    }
	}
    }
    
    # Tell Dancer that it should call the function stream_callback() when
    # ready for streaming to begin.
    
    return \&stream_callback;
}

=pod

The writer object, as specified by L<PSGI>, implements two methods:

=head3 write

Sends its argument immediately to the client as the next piece of the response.
You can call this method as many times as necessary to send all of the data.

=head3 close

Closes the connection to the client, terminating the response.  It is
important to call C<close> at the end of processing, otherwise the client will
erroneously report that the connection was closed prematurely before all of
the data was sent.

=cut

# This subroutine is called at the proper time for data streaming to begin.
# It is passed a callback according to the PSGI standard that can be called to
# procure a writer object to which we can actually write the data a chunk at a
# time.  As each chunk is written, it is sent off to the client as part of the
# response body.

sub stream_callback {
    
    # Grab the callback, which is the first parameter.
    
    my $psgi_callback = shift;
    
    # Use the callback we were given to procure a writer object, and in the
    # process pass the status and headers stored by prepare_stream() above.
    # This will cause the HTTP response to be emitted, with a keep-alive
    # header so that the client will know to wait for more data to come.
    
    my $writer = $psgi_callback->( [ $stream_status, \@stream_headers ] );
    
    # Now we call the routine specified in the original call to stream_data.
    # If it was given as a code reference, we call it and pass in the "data"
    # object as the first parameter.  Otherwise, we use it as a method name
    # and invoke it on the "data" object.  In either case, we pass the writer
    # object as a parameter.
    
    if ( ref $stream_call eq 'CODE' )
    {
	$stream_call->($stream_object, $writer);
    }
    
    else
    {
	$stream_object->$stream_call($writer);
    }
}


=head2 server_supports_streaming

This function returns true if the server you are working with supports
PSGI-style streaming, false otherwise.

Here is an example of how you might use it:

    if ( server_supports_streaming ) {
	stream_data($query, 'streamResult');
    } else {
	return $query->generateResult();
    }

=cut

register 'server_supports_streaming' => sub {
    
    my $env = Dancer::SharedData->request->env;
    return 1 if $env->{'psgi.streaming'};
    return undef; # otherwise
};


register_plugin;
1;

__END__

=head1 AUTHOR

Michael McClennen, mmcclenn 'at' cpan.org

=head1 SEE ALSO

L<Dancer>

L<PSGI>



( run in 1.224 second using v1.01-cache-2.11-cpan-df04353d9ac )