File Coverage

blib/lib/Plack/App/WebSocket.pm
Criterion Covered Total %
statement 27 74 36.4
branch 0 22 0.0
condition 0 11 0.0
subroutine 9 14 64.2
pod 2 2 100.0
total 38 123 30.8


line stmt bran cond sub pod time code
1             package Plack::App::WebSocket;
2 3     3   702340 use strict;
  3         7  
  3         73  
3 3     3   18 use warnings;
  3         4  
  3         87  
4 3     3   2026 use parent qw(Plack::Component);
  3         878  
  3         15  
5 3     3   24675 use Carp;
  3         7  
  3         177  
6 3     3   2125 use Plack::Response;
  3         36328  
  3         94  
7 3     3   2397 use AnyEvent::WebSocket::Server;
  3         326110  
  3         85  
8 3     3   21 use Try::Tiny;
  3         9  
  3         175  
9 3     3   1817 use Plack::App::WebSocket::Connection;
  3         7  
  3         102  
10 3     3   17 use Scalar::Util qw(blessed);
  3         6  
  3         2349  
11              
12             our $VERSION = "0.05";
13              
14             my $ERROR_ENV = "plack.app.websocket.error";
15              
16             sub new {
17 0     0 1   my ($class, @args) = @_;
18 0           my $self = $class->SUPER::new(@args);
19 0 0         croak "on_establish param is mandatory" if not defined $self->{on_establish};
20 0 0         croak "on_establish param must be a code-ref" if ref($self->{on_establish}) ne "CODE";
21 0   0       $self->{on_error} ||= \&_default_on_error;
22 0 0         croak "on_error param must be a code-ref" if ref($self->{on_error}) ne "CODE";
23              
24 0 0         if(!defined($self->{websocket_server})) {
25 0           $self->{websocket_server} = AnyEvent::WebSocket::Server->new();
26             }
27 0 0 0       if(blessed($self->{websocket_server}) && !$self->{websocket_server}->isa("AnyEvent::WebSocket::Server")) {
28 0           croak "websocket_server param must be a AnyEvent::WebSocket::Server";
29             }
30            
31 0           return $self;
32             }
33              
34             sub _default_on_error {
35 0     0     my ($env) = @_;
36 0           my $res = Plack::Response->new;
37 0           $res->content_type("text/plain");
38 0 0         if(!defined($env->{$ERROR_ENV})) {
    0          
    0          
39 0           $res->status(500);
40 0           $res->body("Unknown error");
41             }elsif($env->{$ERROR_ENV} eq "not supported by the PSGI server") {
42 0           $res->status(500);
43 0           $res->body("The server does not support WebSocket.");
44             }elsif($env->{$ERROR_ENV} eq "invalid request") {
45 0           $res->status(400);
46 0           $res->body("The request is invalid for a WebSocket request.");
47             }else {
48 0           $res->status(500);
49 0           $res->body("Unknown error: $env->{$ERROR_ENV}");
50             }
51 0           $res->content_length(length($res->body));
52 0           return $res->finalize;
53             }
54              
55             sub _respond_via {
56 0     0     my ($responder, $psgi_res) = @_;
57 0 0         if(ref($psgi_res) eq "CODE") {
58 0           $psgi_res->($responder);
59             }else {
60 0           $responder->($psgi_res);
61             }
62             }
63              
64             sub call {
65 0     0 1   my ($self, $env) = @_;
66 0 0 0       if(!$env->{"psgi.streaming"} || !$env->{"psgi.nonblocking"} || !$env->{"psgix.io"}) {
      0        
67 0           $env->{$ERROR_ENV} = "not supported by the PSGI server";
68 0           return $self->{on_error}->($env);
69             }
70 0           my $cv_conn = $self->{websocket_server}->establish_psgi($env, $env->{"psgix.io"});
71             return sub {
72 0     0     my $responder = shift;
73             $cv_conn->cb(sub {
74 0           my ($cv_conn) = @_;
75             my ($conn, $error) = try {
76 0           (scalar($cv_conn->recv), undef);
77             }catch {
78 0           (undef, $_[0]);
79 0           };
80 0 0         if(!$conn) {
81 0           $env->{$ERROR_ENV} = "invalid request";
82 0           $env->{"plack.app.websocket.error.handshake"} = $error;
83 0           _respond_via($responder, $self->{on_error}->($env));
84 0           return;
85             }
86 0           $self->{on_establish}->(Plack::App::WebSocket::Connection->new($conn, $responder), $env);
87 0           });
88 0           };
89             }
90              
91             1;
92              
93             __END__