File Coverage

blib/lib/Plack/App/WebSocket.pm
Criterion Covered Total %
statement 27 75 36.0
branch 0 22 0.0
condition 0 11 0.0
subroutine 9 14 64.2
pod 2 2 100.0
total 38 124 30.6


line stmt bran cond sub pod time code
1             package Plack::App::WebSocket;
2 3     3   708772 use strict;
  3         18  
  3         69  
3 3     3   12 use warnings;
  3         4  
  3         68  
4 3     3   1147 use parent qw(Plack::Component);
  3         715  
  3         14  
5 3     3   17731 use Carp;
  3         6  
  3         132  
6 3     3   1174 use Plack::Response;
  3         24302  
  3         75  
7 3     3   1196 use AnyEvent::WebSocket::Server;
  3         195016  
  3         109  
8 3     3   19 use Try::Tiny;
  3         5  
  3         128  
9 3     3   1099 use Plack::App::WebSocket::Connection;
  3         6  
  3         75  
10 3     3   16 use Scalar::Util qw(blessed);
  3         4  
  3         1611  
11              
12             our $VERSION = "0.08";
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 0           my ($conn, @handshake_results, $error);
76             try {
77 0           ($conn, @handshake_results) = $cv_conn->recv;
78             }catch {
79 0           $error = $_[0];
80 0           };
81 0 0         if(!$conn) {
82 0           $env->{$ERROR_ENV} = "invalid request";
83 0           $env->{"plack.app.websocket.error.handshake"} = $error;
84 0           _respond_via($responder, $self->{on_error}->($env));
85 0           return;
86             }
87 0           $self->{on_establish}->(Plack::App::WebSocket::Connection->new($conn, $responder), $env, \@handshake_results);
88 0           });
89 0           };
90             }
91              
92             1;
93              
94             __END__