view release on metacpan or search on metacpan
0.45_01 2018-04-04 17:01:03 -0400
- add env_proxy property to AnyEvent::WebSocket::Client (gh#36 gh#37 TOSHIOITO++)
0.44 2017-12-12 15:37:51 -0500
- Compatibility with 0.22.
0.43 2017-10-19 17:06:51 -0400
- Production version functionally identical to the 0.42_01 release.
0.42_01 2017-10-18 11:45:16 -0400
- You can now unregister event callbacks.
- The 'on' method for AnyEvent::WebSocket::Connection now returns a
code ref that can be used to unregister the callback.
- The 'each_message' event also gets a code ref that can be used to
unregister the callback.
[WARNING: change in behavior]
- The 'on' method for AnyEvent::WebSocket::Connection used to return
the connection object, the intent was to allow chaining of 'on' calls,
but this was never documented, and I don't believe it was ever used.
- The 'each_message' event has a different number of arguments, which
0.22 2014-06-19 15:33:56 -0400
- Mojo 5.x compat (testing only)
0.21 2014-04-08 12:52:51 -0400
- Perl 5.8 support
Only useful if you force install Protocol::WebSocket, since it
has a failing test on 5.8
0.20 2013-11-05 10:19:20 -0500
- prevent multiple finish callbacks in unusual cases (Toshio Ito gh#15)
0.19 2013-11-04 07:26:19 -0500
[AE::WS::Connection enhacements (thanks Toshio Ito)]
- Automatically respond to a close frame with a close frame (RFC6455 5.5.1)
- Make sure "finish" callbacks are called only once.
- Automatically shutdown the socket on "finish" event. This makes sure EOF signal is sent to the peer.
- Refuse to send/receive frames after it sends/receives a close frame. (RFC6455 1.4, 5.5.1)
- Abort the connection when it receives a too huge message. The size limit is imposed by Protocol::WebSocket::Frame (RFC6455 10.4)
- Automatically respond to a ping frame with a pong frame of the same payload (RFC6455 5.5.2, 5.5.3)
- Add "masked" attribute. If set, outgoing frames are masked.
- Client's Connection now sets masked => true (RFC6455 5.3, 6.1).
- documentation
0.18 2013-10-21 14:55:47 -0400
- documentation
perlcriticrc
t/00_diag.t
t/01_use.t
t/anyevent_websocket_client.t
t/anyevent_websocket_client__proxy.t
t/anyevent_websocket_client__scope.t
t/anyevent_websocket_client__server_initial_data_shutdown.t
t/anyevent_websocket_client__ssl.t
t/anyevent_websocket_connection.t
t/anyevent_websocket_connection__counter_shutdown.t
t/anyevent_websocket_connection__destroy_in_callbacks.t
t/anyevent_websocket_connection__finish_callback.t
t/anyevent_websocket_connection__payload_size.t
t/anyevent_websocket_message.t
t/lib/Test2/Plugin/AnyEvent/Timeout.pm
t/lib/Test2/Plugin/EV.pm
t/lib/Test2/Require/NotWindows.pm
t/lib/Test2/Require/SSL.pm
t/lib/Test2/Tools/WebSocket/Connection.pm
t/lib/Test2/Tools/WebSocket/Mojo.pm
t/lib/Test2/Tools/WebSocket/Server.pm
SYNOPSIS
use AnyEvent::WebSocket::Client 0.12;
my $client = AnyEvent::WebSocket::Client->new;
$client->connect("ws://localhost:1234/service")->cb(sub {
# make $connection an our variable rather than
# my so that it will stick around. Once the
# connection falls out of scope any callbacks
# tied to it will be destroyed.
our $connection = eval { shift->recv };
if($@) {
# handle error...
warn $@;
return;
}
# send a message through the websocket...
$connection->send('a message');
FAQ
My program exits before doing anything, what is up with that?
See this FAQ from AnyEvent:
AnyEvent::FAQ#My-program-exits-before-doing-anything-whats-going-on.
It is probably also a good idea to review the AnyEvent documentation if
you are new to AnyEvent or event-based programming.
My callbacks aren't being called!
Make sure that the connection object is still in scope. This often
happens if you use a my $connection variable and don't save it
somewhere. For example:
$client->connect("ws://foo/service")->cb(sub {
my $connection = eval { shift->recv };
if($@)
{
warn $@;
return;
}
...
});
Unless $connection is saved somewhere it will get deallocated along
with any associated message callbacks will also get deallocated once
the connect callback is executed. One way to make sure that the
connection doesn't get deallocated is to make it a our variable (as in
the synopsis above) instead.
CAVEATS
This is pretty simple minded and there are probably WebSocket features
that you might like to use that aren't supported by this distribution.
Patches are encouraged to improve it.
lib/AnyEvent/WebSocket/Client.pm view on Meta::CPAN
=head1 SYNOPSIS
use AnyEvent::WebSocket::Client 0.12;
my $client = AnyEvent::WebSocket::Client->new;
$client->connect("ws://localhost:1234/service")->cb(sub {
# make $connection an our variable rather than
# my so that it will stick around. Once the
# connection falls out of scope any callbacks
# tied to it will be destroyed.
our $connection = eval { shift->recv };
if($@) {
# handle error...
warn $@;
return;
}
# send a message through the websocket...
$connection->send('a message');
lib/AnyEvent/WebSocket/Client.pm view on Meta::CPAN
=head1 FAQ
=head2 My program exits before doing anything, what is up with that?
See this FAQ from L<AnyEvent>:
L<AnyEvent::FAQ#My-program-exits-before-doing-anything-whats-going-on>.
It is probably also a good idea to review the L<AnyEvent> documentation
if you are new to L<AnyEvent> or event-based programming.
=head2 My callbacks aren't being called!
Make sure that the connection object is still in scope. This often happens
if you use a C<my $connection> variable and don't save it somewhere. For
example:
$client->connect("ws://foo/service")->cb(sub {
my $connection = eval { shift->recv };
if($@)
{
warn $@;
return;
}
...
});
Unless C<$connection> is saved somewhere it will get deallocated along with
any associated message callbacks will also get deallocated once the connect
callback is executed. One way to make sure that the connection doesn't
get deallocated is to make it a C<our> variable (as in the synopsis above)
instead.
=head1 CAVEATS
This is pretty simple minded and there are probably WebSocket features
that you might like to use that aren't supported by this distribution.
Patches are encouraged to improve it.
lib/AnyEvent/WebSocket/Connection.pm view on Meta::CPAN
init_arg => undef,
default => sub { 0 },
);
sub BUILD
{
my $self = shift;
Scalar::Util::weaken $self;
my @temp_messages = ();
my $are_callbacks_supposed_to_be_ready = 0;
my $finish = sub {
my(undef, undef, $message) = @_;
my $strong_self = $self; # preserve $self because otherwise $self can be destroyed in the callbacks.
return if $self->_is_finished;
eval
{
$self->_process_message($_) foreach @temp_messages;
};
@temp_messages = ();
$self->_is_finished(1);
$self->handle->push_shutdown;
$self->_is_read_open(0);
$self->_is_write_open(0);
lib/AnyEvent/WebSocket/Connection.pm view on Meta::CPAN
$self->handle->on_eof($finish);
my $frame = Protocol::WebSocket::Frame->new(
maybe max_payload_size => $self->max_payload_size,
maybe max_fragments_amount => $self->max_fragments,
);
my $read_cb = sub {
my ($handle) = @_;
local $@;
my $strong_self = $self; # preserve $self because otherwise $self can be destroyed in the callbacks
my $success = eval
{
$frame->append($handle->{rbuf});
while(defined(my $body = $frame->next_bytes))
{
next if !$self->_is_read_open; # not 'last' but 'next' in order to consume data in $frame buffer.
my $message = AnyEvent::WebSocket::Message->new(
body => $body,
opcode => $frame->opcode,
);
if($are_callbacks_supposed_to_be_ready)
{
$self->_process_message($message);
}
else
{
push(@temp_messages, $message);
}
}
1; # succeed to parse.
};
if(!$success)
{
$self->_force_shutdown();
$_->($self, $@) for @{ $self->_parse_error_cb };
}
};
# Message processing (calling _process_message) is delayed by
# $are_callbacks_supposed_to_be_ready flag. This is necessary to
# make sure all received messages are delivered to each_message and
# next_message callbacks. If there is some data in rbuf, changing
# the on_read callback makes the callback fire, but there is of
# course no each_message/next_message callback to receive the
# message yet. So we put messages to @temp_messages for a
# while. After the control is returned to the user, who sets up
# each_message/next_message callbacks, @temp_messages are processed.
# An alternative approach would be temporarily disabling on_read by
# $self->handle->on_read(undef). However, this can cause a weird
# situation in TLS mode, because on_eof can fire even if we don't
# have any on_read (
# https://metacpan.org/pod/AnyEvent::Handle#I-get-different-callback-invocations-in-TLS-mode-Why-cant-I-pause-reading
# )
$self->handle->on_read($read_cb);
my $idle_w; $idle_w = AE::idle sub {
undef $idle_w;
if(defined($self))
{
my $strong_self = $self;
$are_callbacks_supposed_to_be_ready = 1;
local $@;
my $success = eval
{
$self->_process_message($_) foreach @temp_messages;
1;
};
@temp_messages = ();
if(!$success)
{
$self->_force_shutdown();
lib/AnyEvent/WebSocket/Connection.pm view on Meta::CPAN
};
}
sub _process_message
{
my ($self, $received_message) = @_;
return if !$self->_is_read_open;
if($received_message->is_text || $received_message->is_binary)
{
# make a copy in order to allow specifying new callbacks inside the
# currently executed next_callback itself. otherwise, any next_callback
# added inside the currently executed callback would be added to the end
# of the array and executed for the currently processed message instead of
# actually the next one.
my @next_callbacks = @{ $self->_next_message_cb };
@{ $self->_next_message_cb } = ();
$_->($self, $received_message) for @next_callbacks;
# make a copy in case one of the callbacks get
# unregistered in the middle of the loop
my @callbacks = @{ $self->_each_message_cb };
$_->($self, $received_message, $self->_cancel_for(each_message => $_) )
for @callbacks;
}
elsif($received_message->is_close)
{
my $body = $received_message->body;
if($body)
{
my($code, $reason) = unpack 'na*', $body;
$self->close_code($code);
$self->close_reason(Encode::decode('UTF-8', $reason));
}
lib/AnyEvent/WebSocket/Connection.pm view on Meta::CPAN
$cb->($connection, $message)
Called only for the next message received from the WebSocket.
[0.49]
Adding a next_message callback from within a next_message callback will
result in a callback called on the next message instead of the current
one. There was a bug in previous versions where the callback would be
called immediately after current set of callbacks with the same message.
=head3 parse_error
$cb->($connection, $text_error_message)
Called if there is an error parsing a message sent from the remote end.
After this callback is called, the connection will be closed.
Among other possible errors, this event will trigger if a frame has a
payload which is larger that C<max_payload_size>.
t/anyevent_websocket_client.t view on Meta::CPAN
});
$conn->on(finish => sub {
$cv_finish->send();
});
$cv_finish->recv;
is(\@received_messages, ["initial message from server"]);
};
subtest 'callbacks can be unregistered' => sub {
my $url = start_server(
handshake => sub {
my $opt = { @_ };
$opt->{hdl}->push_write(Protocol::WebSocket::Frame->new("initial message from server")->to_bytes) for 1..10;
},
message => sub {
my $opt = { @_ };
$opt->{hdl}->push_shutdown;
},
t/anyevent_websocket_client.t view on Meta::CPAN
$conn->send("finish") unless --$countdown;
});
$conn->on(finish => sub {
$cv_finish->send();
});
$cv_finish->recv;
is(\@received_messages, [("initial message from server")x10]);
is(\@counters, [2,2], "callbacks got unregistered after second message");
};
done_testing;
t/anyevent_websocket_connection__destroy_in_callbacks.t view on Meta::CPAN
use lib 't/lib';
use Test2::Plugin::EV;
use Test2::Plugin::AnyEvent::Timeout;
use Test2::V0 -no_srand => 1;
use Test2::Tools::WebSocket::Connection qw( create_connection_pair );
use AnyEvent::WebSocket::Connection;
use Scalar::Util qw(weaken);
note("It should be safe (exception-free) to destroy the Connection object in callbacks.");
sub test_case
{
my ($label, $a_conn_code, $b_conn_code) = @_;
subtest $label, sub {
my $b_conn;
my $a_conn_weak;
my $cv_finish = AnyEvent->condvar;
$cv_finish->begin;
$cv_finish->begin;
xt/author/pod_spelling_system.t view on Meta::CPAN
Ollis
Mojolicious
plicease
CPAN
reinstall
TODO
filename
filenames
login
callback
callbacks
standalone
VMS
hostname
hostnames
TCP
UDP
IP
API
MSWin32
OpenBSD