AnyEvent-Handle-Throttle

 view release on metacpan or  search on metacpan

README  view on Meta::CPAN

NAME
    AnyEvent::Handle::Throttle - AnyEvent::Handle subclass with user-defined
    up/down bandwidth cap

Synopsis
        use AnyEvent;
        use AnyEvent::Handle::Throttle;
        my $condvar = AnyEvent->condvar;
        my $handle;
        $handle = AnyEvent::Handle::Throttle->new(
            upload_limit   => 2,  # Very...
            download_limit => 50, # ...slow
            connect  => ['google.com', 'http'],
            on_error => sub {
                warn "error $_[2]\n";
                $_[0]->destroy;
                $condvar->send;
            },
            on_eof => sub {
                $handle->destroy;
                warn "done.\n";

README  view on Meta::CPAN


Methods
    In addition to AnyEvent::Handle's base methods, this subclass supports
    the following...

    $handle = AnyEvent::Handle::Throttle->new( key => value, ... )
        In addition to the arguments handled by "AnyEvent::Handle->new( ...
        )", this constructor supports these arguments (all as "key => value"
        pairs).

        upload_limit => <bytes>
            This is the maximum amount of data (in bytes) written to the
            filehandle per period. If "upload_limit" is not specified, the
            upload rate is not limited.

            Note that this value can/will override "read_size".

        download_limit => <bytes>
            This is the maximum amount of data (in bytes) read from the
            filehandle per period. If "download_limit" is not specified, the
            upload rate is not limited.

    $handle->upload_limit( $bytes )
        Sets/returns the current upload rate in bytes per period.

    $handle->download_limit( $bytes )
        Sets/returns the current download rate in bytes per period.

    $bytes = $handle->upload_speed( )
        Returns the amount of data written during the previous period.

    $bytes = $handle->download_speed( )
        Returns the amount of data read during the previous period.

    If you're using AnyEvent::Handle::Throttle to limit bandwidth and
    realize you'd rather set flat limits on the total bandwidth instead of
    per-handle, try these methods:

    AnyEvent::Handle::Throttle->global_upload_limit( $bytes )
        Sets/returns the current global upload rate in bytes per period.

    AnyEvent::Handle::Throttle->global_download_limit( $bytes )
        Sets/returns the current global download rate in bytes per period.

    $bytes = $handle->global_upload_speed( )
        Returns the amount of data written through all
        AnyEvent::Handle::Throttle objects during the previous period.

    $bytes = $handle->global_download_speed( )
        Returns the amount of data read through all
        AnyEvent::Handle::Throttle objects during the previous period.

    $bytes = $handle->download_total( )
        Returns the total amount of data read through the
        AnyEvent::Handle::Throttle object.

    $bytes = $handle->upload_total( )
        Returns the total amount of data written through the
        AnyEvent::Handle::Throttle object.

    $bytes = $handle->global_download_total( )
        Returns the total amount of data read through all
        AnyEvent::Handle::Throttle objects so far.

    $bytes = $handle->global_upload_total( )
        Returns the total amount of data sent through all
        AnyEvent::Handle::Throttle objects so far.

Notes
    *   The current default period is 1 second.

    *   On destruction, all remaining data is sent ASAP, ignoring the user
        defined upload limit. This may change in the future.

Bugs
    I'm sure this module is just burting with 'em. When you stumble upon
    one, please report it via the Issue Tracker
    <http://github.com/sanko/anyevent-handle-throttle/issues>.

Author
    Sanko Robinson <sanko@cpan.org> - http://sankorobinson.com/

    CPAN ID: SANKO

lib/AnyEvent/Handle/Throttle.pm  view on Meta::CPAN

package AnyEvent::Handle::Throttle;
{
    use strict;
    use warnings;
    use AnyEvent;
    use Errno qw[EAGAIN EINTR];
    use AnyEvent::Util qw[WSAEWOULDBLOCK];
    use parent 'AnyEvent::Handle';
    our $MAJOR = 0.00; our $MINOR = 2; our $DEV = -5; our $VERSION = sprintf('%1.3f%03d' . ($DEV ? (($DEV < 0 ? '' : '_') . '%03d') : ('')), $MAJOR, $MINOR, abs $DEV);

    sub upload_limit {
        $_[1] ? $_[0]->{upload_limit} = $_[1] : $_[0]->{upload_limit};
    }

    sub download_limit {
        $_[1] ? $_[0]->{download_limit} = $_[1] : $_[0]->{download_limit};
    }
    sub upload_total   { $_[0]->{upload_total} }
    sub download_total { $_[0]->{download_total} }
    sub upload_speed   { $_[0]->{upload_speed} }
    sub download_speed { $_[0]->{download_speed} }
    my ($global_upload_total, $global_download_total,
        $global_upload_limit, $global_download_limit,
        $global_upload_speed, $global_download_speed
    );
    my $global_period = 1;

    sub global_upload_limit {
        $_[1] ? $global_upload_limit = $_[1] : $global_upload_limit;
    }

    sub global_download_limit {
        $_[1] ? $global_download_limit = $_[1] : $global_download_limit;
    }
    sub global_upload_total   {$global_upload_total}
    sub global_download_total {$global_download_total}
    sub global_upload_speed   {$global_upload_speed}
    sub global_download_speed {$global_download_speed}
    my ($global_read_size,     $global_write_size,
        $global__upload_speed, $global__download_speed);
    my $global_reset_cb = sub {
        $global_read_size      = $global_download_limit;
        $global_write_size     = $global_upload_limit || 8 * 1024;
        $global_upload_speed   = $global__upload_speed;
        $global_download_speed = $global__download_speed;
        $global__upload_speed  = $global__download_speed = 0;
    };
    $global_reset_cb->();
    our $global_reset = AE::timer(0, $global_period, $global_reset_cb);

    sub _start {
        my $self  = shift;
        my $reset = sub {
            $self->{read_size}      = $self->{download_limit};
            $self->{write_size}     = $self->{upload_limit} || 8 * 1024;
            $self->{upload_speed}   = $self->{_upload_speed};
            $self->{download_speed} = $self->{_download_speed};
            $self->{_upload_speed}  = $self->{_download_speed} = 0;
        };
        $self->{_period} ||= 1;
        $self->{_reset} = AE::timer(0, $self->{_period}, $reset);
        $reset->();
        $self->SUPER::_start(@_);
    }

    sub start_read {
        my ($self) = @_;
        unless ($self->{_rw} || $self->{_eof} || !$self->{fh}) {

lib/AnyEvent/Handle/Throttle.pm  view on Meta::CPAN

                                $poll->();
                            }
                        );
                    }
                    return 1;
                }
                my $len = syswrite $self->{fh}, $self->{wbuf}, $write;
                if (defined $len) {
                    $self->{write_size} -= $len;
                    $global_write_size  -= $len;
                    $self->{upload_total}  += $len;
                    $global_upload_total   += $len;
                    $self->{_upload_speed} += $len;
                    $global__upload_speed  += $len;
                    substr $self->{wbuf}, 0, $len, "";
                    $self->{_activity} = $self->{_wactivity} = AE::now;
                    $self->{on_drain}($self)
                        if $self->{low_water_mark}
                            || 0 >= length($self->{wbuf} || '')
                            + length($self->{_tls_wbuf}  || '')
                            && $self->{on_drain};
                    delete $self->{_ww} unless length $self->{wbuf};
                }
                elsif (   $! != EAGAIN

lib/AnyEvent/Handle/Throttle.pm  view on Meta::CPAN


AnyEvent::Handle::Throttle - AnyEvent::Handle subclass with user-defined up/down bandwidth cap

=head1 Synopsis

    use AnyEvent;
    use AnyEvent::Handle::Throttle;
    my $condvar = AnyEvent->condvar;
    my $handle;
    $handle = AnyEvent::Handle::Throttle->new(
        upload_limit   => 2,  # Very...
        download_limit => 50, # ...slow
        connect  => ['google.com', 'http'],
        on_error => sub {
            warn "error $_[2]\n";
            $_[0]->destroy;
            $condvar->send;
        },
        on_eof => sub {
            $handle->destroy;
            warn "done.\n";

lib/AnyEvent/Handle/Throttle.pm  view on Meta::CPAN

=over

=item $handle = AnyEvent::Handle::Throttle->B<new>( key => value, ... )

In addition to the arguments handled by
L<< C<<< AnyEvent::Handle->new( ... ) >>>|AnyEvent::Handle >>, this
constructor supports these arguments (all as C<< key => value >> pairs).

=over

=item upload_limit => <bytes>

This is the maximum amount of data (in bytes) written to the filehandle per
period. If C<upload_limit> is not specified, the upload rate is not limited.

Note that this value can/will override C<read_size>.

=item download_limit => <bytes>

This is the maximum amount of data (in bytes) read from the filehandle per
period. If C<download_limit> is not specified, the upload rate is not limited.

=back

=item $handle->B<upload_limit>( $bytes )

Sets/returns the current upload rate in bytes per period.

=item $handle->B<download_limit>( $bytes )

Sets/returns the current download rate in bytes per period.

=item $bytes = $handle->B<upload_speed>( )

Returns the amount of data written during the previous period.

=item $bytes = $handle->B<download_speed>( )

Returns the amount of data read during the previous period.

=back

If you're using L<AnyEvent::Handle::Throttle|AnyEvent::Handle::Throttle> to
limit bandwidth and realize you'd rather set flat limits on the B<total>
bandwidth instead of per-handle, try these methods:

=over

=item AnyEvent::Handle::Throttle->B<global_upload_limit>( $bytes )

Sets/returns the current global upload rate in bytes per period.

=item AnyEvent::Handle::Throttle->B<global_download_limit>( $bytes )

Sets/returns the current global download rate in bytes per period.

=item $bytes = $handle->B<global_upload_speed>( )

Returns the amount of data written through all
L<AnyEvent::Handle::Throttle|AnyEvent::Handle::Throttle> objects during the
previous period.

=item $bytes = $handle->B<global_download_speed>( )

Returns the amount of data read through all
L<AnyEvent::Handle::Throttle|AnyEvent::Handle::Throttle> objects during the
previous period.

=item $bytes = $handle->B<download_total>( )

Returns the total amount of data read through the
L<AnyEvent::Handle::Throttle|AnyEvent::Handle::Throttle> object.

=item $bytes = $handle->B<upload_total>( )

Returns the total amount of data written through the
L<AnyEvent::Handle::Throttle|AnyEvent::Handle::Throttle> object.

=item $bytes = $handle->B<global_download_total>( )

Returns the total amount of data read through all
L<AnyEvent::Handle::Throttle|AnyEvent::Handle::Throttle> objects so far.

=item $bytes = $handle->B<global_upload_total>( )

Returns the total amount of data sent through all
L<AnyEvent::Handle::Throttle|AnyEvent::Handle::Throttle> objects so far.

=back

=head1 Notes

=over

=item *

The current default period is C<1> second.

=item *

On destruction, all remaining data is sent ASAP, ignoring the user defined
upload limit. This may change in the future.

=back

=head1 Bugs

I'm sure this module is just burting with 'em. When you stumble upon one,
please report it via the
L<Issue Tracker|http://github.com/sanko/anyevent-handle-throttle/issues>.

=head1 Author

t/http.t  view on Meta::CPAN

use lib '../lib';
use AnyEvent::Handle::Throttle;
$|++;
my $condvar = AnyEvent->condvar;
my ($handle, $rbuf, $prev, $chunks);
my $req = "GET / HTTP/1.0\015\012\015\012";
TODO: {
    local $TODO = 'May fail blah blah blah';
    $handle = new_ok(
        'AnyEvent::Handle::Throttle',
        [upload_limit   => 2,
         download_limit => 1024,
         connect        => ['cpan.org', 80],
         on_prepare     => sub {15},
         on_connect     => sub { $prev = AE::now; },
         on_error       => sub {
             note 'error ' . $_[2];
             $_[0]->destroy;
             $condvar->send;
         },
         on_eof => sub {
             $handle->destroy;
             note 'done';
             $condvar->send;
         },
         on_drain => sub {
             my $now = AE::now;
             my $expected
                 = (int(length($req) / $handle->upload_limit)
                        * $handle->{_period});
             note
                 sprintf 'Write queue is empty after %f seconds',
                 $now - $prev;
             $prev = $now;
         },
         on_read => sub {
             my $now = AE::now;
             ok length $handle->rbuf <= $handle->download_limit,
                 sprintf 'Chunk %d was %d bytes long...', ++$chunks,
                 length $handle->rbuf;
             note sprintf ' ...and came %f seconds later', $now - $prev
                 if $chunks > 1;
             $handle->rbuf() = '';
             $prev = $now;
             }
        ],
        '::Throttle->new( upload_limit => 20, download_limit => 50, ... )'
    );
    $handle->push_write($req);
    $condvar->recv;
}
done_testing();

=pod

=head1 Author

t/http_global.t  view on Meta::CPAN

use warnings;
use Test::More;
use AnyEvent::Impl::Perl;
use AnyEvent;
use lib '../lib';
use AnyEvent::Handle::Throttle;
$|++;
my $condvar = AnyEvent->condvar;
my ($prev, $chunks, $handle, $rbuf) = (AE::now, 0, undef, undef);
my $req = "GET / HTTP/1.0\015\012\015\012";
AnyEvent::Handle::Throttle->global_upload_limit(5);
AnyEvent::Handle::Throttle->global_download_limit(200);
TODO: {
    local $TODO = 'May fail blah blah blah';
    $handle = new_ok(
        'AnyEvent::Handle::Throttle',
        [connect    => ['cpan.org', 80],
         on_prepare => sub          {15},
         on_connect => sub { $prev = AE::now; },
         on_error => sub {
             note 'error ' . $_[2];

t/http_global.t  view on Meta::CPAN

         },
         on_eof => sub {
             $handle->destroy;
             note 'done';
             $condvar->send;
         },
         on_drain => sub {
             my $now = AE::now;
             my $expected = (
                     int(length($req)
                             / AnyEvent::Handle::Throttle->global_upload_limit
                     )
             );
             note sprintf 'Write queue is empty after %f seconds',
                 $now - $prev;
             $prev = $now;
         },
         on_read => sub {
             my $now = AE::now;
             ok length $handle->rbuf
                 <= AnyEvent::Handle::Throttle->global_download_limit,

t/loopback.t  view on Meta::CPAN

$wr_ae->push_write('X' x 130);
$wr_ae->on_drain(
    sub {
        my ($wr_ae) = @_;
        $wr_ae->on_drain;
        is(++$write, 1, 'first write');
        $wr_ae->push_write('Y');
        $wr_ae->on_drain(
            sub {
                my ($wr_ae) = @_;
                $wr_ae->upload_limit(512);
                $wr_ae->on_drain;
                is(++$write, 2, 'second write');
                $wr_ae->push_write('Z');
                $wr_ae->on_drain(
                    sub {
                        my ($wr_ae) = @_;
                        $wr_ae->on_drain;
                        is(++$write, 3, 'third write');
                    }
                );
            }
        );
    }
);
$cv->recv;
ok($dat eq 'AAXXXYZ', 'received data') || note '$dat was: ' . $dat;

#
ok !$rd_ae->upload_total, 'reader uploaded nothing';
is $rd_ae->global_upload_total, 10132, 'reader says uploaded is 10132 bytes';
is $rd_ae->download_total, 10132,
    'reader claims to have downloaded 10132 bytes';
is $rd_ae->global_download_total, 10132,
    'reader claims global download was 10132 bytes';
is $wr_ae->upload_total,        10132, 'writer says it uploaded 10132 bytes';
is $wr_ae->global_upload_total, 10132, 'writer says uploaded is 10132 bytes';
ok !$wr_ae->download_total, 'writer claims to have downloaded nothing';
is $wr_ae->global_download_total, 10132,
    'writer claims global download was 10132 bytes';

#
done_testing;



( run in 0.959 second using v1.01-cache-2.11-cpan-b16cb0d3907 )