line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Plack::App::WebSocket; |
2
|
3
|
|
|
3
|
|
600610
|
use strict; |
|
3
|
|
|
|
|
19
|
|
|
3
|
|
|
|
|
74
|
|
3
|
3
|
|
|
3
|
|
13
|
use warnings; |
|
3
|
|
|
|
|
5
|
|
|
3
|
|
|
|
|
70
|
|
4
|
3
|
|
|
3
|
|
689
|
use parent qw(Plack::Component); |
|
3
|
|
|
|
|
680
|
|
|
3
|
|
|
|
|
15
|
|
5
|
3
|
|
|
3
|
|
15018
|
use Carp; |
|
3
|
|
|
|
|
6
|
|
|
3
|
|
|
|
|
137
|
|
6
|
3
|
|
|
3
|
|
769
|
use Plack::Response; |
|
3
|
|
|
|
|
23482
|
|
|
3
|
|
|
|
|
79
|
|
7
|
3
|
|
|
3
|
|
790
|
use AnyEvent::WebSocket::Server; |
|
3
|
|
|
|
|
188685
|
|
|
3
|
|
|
|
|
75
|
|
8
|
3
|
|
|
3
|
|
20
|
use Try::Tiny; |
|
3
|
|
|
|
|
6
|
|
|
3
|
|
|
|
|
128
|
|
9
|
3
|
|
|
3
|
|
809
|
use Plack::App::WebSocket::Connection; |
|
3
|
|
|
|
|
8
|
|
|
3
|
|
|
|
|
74
|
|
10
|
3
|
|
|
3
|
|
15
|
use Scalar::Util qw(blessed); |
|
3
|
|
|
|
|
6
|
|
|
3
|
|
|
|
|
1548
|
|
11
|
|
|
|
|
|
|
|
12
|
|
|
|
|
|
|
our $VERSION = "0.06"; |
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__ |