package Node::Connection;

=head1 Node::Connection

Abstract super class for writing connection handlers, extends
Node::Socket.  This provides read and write buffers, and calls an
abstract

TODO: let CHUNK_SIZE be configurable per object - so that the Node can
deal with multiple connections more fairly, if need be.

=cut

use strict;
use Node::Socket;
use constant CHUNK_SIZE => 1024*1024;
use vars qw/@ISA/;

@ISA = qw/Node::Socket/;

=head1 new

Creates a new connection handler, on the specified IO::Handle.

=cut

sub new {
    my ($package, $handle) = @_;

    my $self = $package->SUPER::new($handle);
    $self->{read_buf} = $self->{write_buf} = '';

    return $self;
}

=head1 socket_read

Handle a can_read event - sysreads into a buffer, then calls the
sub-class's 'receive' method repeatedly until it returns false, to
receive any complete messages which might have arrived.

=cut

sub socket_read {
    my ($self) = @_;

    my $n_read = $self->{handle}->sysread($self->{read_buf}, CHUNK_SIZE, length $self->{read_buf});

    unless (defined $n_read) {
	$self->socket_error;
    } elsif ($n_read == 0) {
	$self->closed;
    } else {
	while ($self->receive) {}
    }
}

=head1 socket_write

Handle a can_write event - syswrites as much of the write buffer as it
can.

=cut

sub socket_write {
    my ($self) = @_;

    my $n_to_write = length $self->{write_buf};
    my $n_written = $self->{handle}->syswrite($self->{write_buf});
    
    unless (defined $n_written) {
	$self->socket_error;
    } elsif ($n_written == $n_to_write) {
	$self->{write_buf} = '';
	Node->remove_write($self->{handle});
    } else {
	substr $self->{write_buf}, 0, $n_written, '';
    }
}

=head1 write

Write a message to the socket - this buffers the message, and
registers for can_write if not already.

=cut

sub write {
    my ($self, $data) = @_;
    return unless length $data;
    Node->add_write($self) unless length $self->{write_buf};
    $self->{write_buf} .= $data;
}

1
