package SockJS::Connection; use strict; use warnings; sub new { my $class = shift; my (%params) = @_; my $self = {}; bless $self, $class; $self->{type} = $params{type} || ''; $self->{close_cb} = $params{close_cb} || sub { }; $self->{write_cb} = $params{write_cb} || sub { }; $self->{messages} = []; return $self; } sub type { $_[0]->{type} } sub write_cb { my $self = shift; if (@_) { $self->{write_cb} = $_[0]; } return $self->{write_cb}; } sub close_cb { my $self = shift; if (@_) { $self->{close_cb} = $_[0]; } return $self->{close_cb}; } sub is_connected { my $self = shift; return $self->{is_connected}; } sub connected { my $self = shift; $self->{is_connected} = 1; $self->{is_reconnecting} = 0; $self->{is_closed} = 0; $self->_send_staged_messages; $self->fire_event('connect'); return $self; } sub reconnecting { my $self = shift; $self->{is_reconnecting} = 1; return $self; } sub is_reconnecting { my $self = shift; return $self->{is_reconnecting}; } sub reconnected { my $self = shift; $self->{is_reconnecting} = 0; $self->_send_staged_messages; return $self; } sub closed { my $self = shift; return if $self->is_closed; $self->{is_connected} = 0; $self->{is_closed} = 1; $self->fire_event('close'); return $self; } sub aborted { my $self = shift; return if $self->is_closed; $self->{is_connected} = 0; $self->{is_closed} = 1; if (exists $self->{on_abort}) { $self->fire_event('abort'); } else { $self->fire_event('close'); } return $self; } sub is_closed { my $self = shift; return $self->{is_closed}; } sub on { my $self = shift; my ($event, $cb) = @_; push @{$self->{"on_$event"}}, $cb; return $self; } sub write { my $self = shift; my ($message) = @_; return $self unless defined $message && $message ne ''; if (($self->is_connected || $self->is_closed) && !$self->is_reconnecting) { $self->{write_cb}->($self, $message); } else { push @{$self->{messages}}, $message; } return $self; } sub close { my $self = shift; my ($code, $message) = @_; if ($self->type ne 'raw_websocket') { $self->{close_message} ||= do { $code ||= 3000; $message ||= 'Get away!'; [int $code, $message]; }; $self->write('c[' . $self->{close_message}->[0] . ',"' . $self->{close_message}->[1] . '"]'); } $self->{close_cb}->($self); $self->closed; return $self; } sub fire_event { my $self = shift; my $event = shift; if (exists $self->{"on_$event"}) { foreach my $ev (@{$self->{"on_$event"}}) { $ev->($self, @_); } } return $self; } sub _send_staged_messages { my $self = shift; while ($self->is_connected && !$self->is_reconnecting && @{$self->{messages}}) { my $message = shift @{$self->{messages}}; my $type = substr($message, 0, 1); if ($type eq 'a') { while ($self->{messages}->[0] && substr($self->{messages}->[0], 0, 1) eq $type) { my $next_message = shift @{$self->{messages}}; $next_message =~ s{^a\[}{}; $message =~ s{\]}{,$next_message}; } } $self->{write_cb}->($self, $message); } } 1;