File Coverage

blib/lib/Net/Async/EmptyPort.pm
Criterion Covered Total %
statement 29 29 100.0
branch 5 8 62.5
condition 9 14 64.2
subroutine 8 8 100.0
pod 2 2 100.0
total 53 61 86.8


line stmt bran cond sub pod time code
1             package Net::Async::EmptyPort;
2             $Net::Async::EmptyPort::VERSION = '0.001000';
3             # ABSTRACT: Asynchronously wait for a port to open
4              
5 1     1   21739 use Moo;
  1         14894  
  1         8  
6 1     1   2423 use Future::Utils 'try_repeat_until_success', 'try_repeat';
  1         19790  
  1         511  
7              
8             has _loop => (
9             is => 'ro',
10             init_arg => 'loop',
11             required => 1,
12             handles => {
13             _connect => 'connect',
14             _listen => 'listen',
15             _delay => 'delay_future',
16             _timeout => 'timeout_future',
17             },
18             );
19              
20             my %family_map = (
21             tcp => 'stream',
22             udp => 'dgram',
23             );
24             sub empty_port {
25 3     3 1 62188 my ($self, $args) = @_;
26              
27 3   100     19 $args //= {};
28 3   50     19 $args->{host} //= '127.0.0.1';
29 3   100     13 $args->{port} //= 0;
30 3   50     12 $args->{proto} //= 'tcp';
31              
32 3 100       8 if ($args->{port} == 0) {
33             $self->_listen(
34       1     on_socket => sub {},
35             host => $args->{host},
36             socktype => $family_map{$args->{proto}},
37             service => $args->{port},
38             )
39 2         37 } else {
40 1         3 my $port = $args->{port};
41              
42             try_repeat {
43             $self->_listen(
44             on_socket => sub {},
45             host => $args->{host},
46             socktype => $family_map{$args->{proto}},
47 1     1   64 service => $port++,
48             )
49             } while => sub {
50 1 50   1   863 !shift->is_done && $port < 65000
51             },
52 1         13 }
53             }
54              
55             sub wait_port {
56 1     1 1 866 my ($self, $args) = @_;
57              
58             die 'port is a required argument'
59 1 50       6 unless $args->{port};
60              
61 1   50     7 $args->{host} //= '127.0.0.1';
62 1   50     8 $args->{proto} //= 'tcp';
63 1   50     7 $args->{max_wait} //= 10;
64              
65 1         1 my $amount = 2;
66 1         2 my $attempt = 0;
67              
68             my $f = try_repeat_until_success {
69             $self->_delay(
70             after => $amount * (2 ** $attempt++) - $amount,
71             )->then(sub {
72             $self->_connect(
73             host => $args->{host},
74             socktype => $family_map{$args->{proto}},
75             service => $args->{port},
76             )
77 1         175 })
78 1     1   6 };
  1         45  
79              
80             $f = Future->wait_any(
81             $f,
82             $self->_timeout( after => $args->{max_wait} )
83 1 50       3486 ) if $args->{max_wait} > 0;
84              
85 1         596 $f
86             }
87              
88             1;
89              
90             __END__