Acme-Sort-Sleep
view release on metacpan or search on metacpan
local/lib/perl5/IO/Async/Resolver.pm view on Meta::CPAN
=head1 METHODS
The following methods documented with a trailing call to C<< ->get >> return
L<Future> instances.
=cut
=head2 resolve
@result = $loop->resolve( %params )->get
Performs a single name resolution operation, as given by the keys in the hash.
The C<%params> hash keys the following keys:
=over 8
=item type => STRING
Name of the resolution operation to perform. See BUILT-IN RESOLVERS for the
list of available operations.
=item data => ARRAY
Arguments to pass to the resolver function. Exact meaning depends on the
specific function chosen by the C<type>; see BUILT-IN RESOLVERS.
=item timeout => NUMBER
Optional. Timeout in seconds, after which the resolver operation will abort
with a timeout exception. If not supplied, a default of 10 seconds will apply.
=back
On failure, the fail category name is C<resolve>; the details give the
individual resolver function name (e.g. C<getaddrinfo>), followed by other
error details specific to the resolver in question.
->fail( $message, resolve => $type => @details )
=head2 resolve (void)
$resolver->resolve( %params )
When not returning a future, additional parameters can be given containing the
continuations to invoke on success or failure:
=over 8
=item on_resolved => CODE
A continuation that is invoked when the resolver function returns a successful
result. It will be passed the array returned by the resolver function.
$on_resolved->( @result )
=item on_error => CODE
A continuation that is invoked when the resolver function fails. It will be
passed the exception thrown by the function.
=back
=cut
sub resolve
{
my $self = shift;
my %args = @_;
my $type = $args{type};
defined $type or croak "Expected 'type'";
if( $type eq "getaddrinfo_hash" ) {
$type = "getaddrinfo";
}
exists $METHODS{$type} or croak "Expected 'type' to be an existing resolver method, got '$type'";
my $on_resolved;
if( $on_resolved = $args{on_resolved} ) {
ref $on_resolved or croak "Expected 'on_resolved' to be a reference";
}
elsif( !defined wantarray ) {
croak "Expected 'on_resolved' or to return a Future";
}
my $on_error;
if( $on_error = $args{on_error} ) {
ref $on_error or croak "Expected 'on_error' to be a reference";
}
elsif( !defined wantarray ) {
croak "Expected 'on_error' or to return a Future";
}
my $timeout = $args{timeout} || 10;
my $future = $self->call(
args => [ $type, $timeout, @{$args{data}} ],
)->else( sub {
my ( $message, @detail ) = @_;
Future->fail( $message, resolve => $type => @detail );
});
$future->on_done( $on_resolved ) if $on_resolved;
$future->on_fail( $on_error ) if $on_error;
return $future if defined wantarray;
# Caller is not going to keep hold of the Future, so we have to ensure it
# stays alive somehow
$self->adopt_future( $future->else( sub { Future->done } ) );
}
=head2 getaddrinfo
@addrs = $resolver->getaddrinfo( %args )->get
A shortcut wrapper around the C<getaddrinfo> resolver, taking its arguments in
a more convenient form.
local/lib/perl5/IO/Async/Resolver.pm view on Meta::CPAN
$flags |= NI_DGRAM if $args{dgram};
$flags |= NI_NUMERICHOST|NI_NUMERICSERV if $args{numeric};
if( $flags & (NI_NUMERICHOST|NI_NUMERICSERV) ) {
# This is a numeric-only lookup that can be done synchronously
my ( $err, $host, $service ) = Socket::getnameinfo( $args{addr}, $flags );
if( $err ) {
my $future = $self->loop->new_future->fail( $err, resolve => getnameinfo => $err+0 );
$future->on_fail( $args{on_error} ) if $args{on_error};
return $future;
}
else {
my $future = $self->loop->new_future->done( $host, $service );
$future->on_done( $args{on_resolved} ) if $args{on_resolved};
return $future;
}
}
my $future = $self->resolve(
type => "getnameinfo",
data => [ $args{addr}, $flags ],
timeout => $args{timeout},
)->transform(
done => sub { @{ $_[0] } }, # unpack the ARRAY ref
);
$future->on_done( $args{on_resolved} ) if $args{on_resolved};
$future->on_fail( $args{on_error} ) if $args{on_error};
return $future if defined wantarray;
# Caller is not going to keep hold of the Future, so we have to ensure it
# stays alive somehow
$self->adopt_future( $future->else( sub { Future->done } ) );
}
=head1 FUNCTIONS
=cut
=head2 register_resolver( $name, $code )
Registers a new named resolver function that can be called by the C<resolve>
method. All named resolvers must be registered before the object is
constructed.
=over 8
=item $name
The name of the resolver function; must be a plain string. This name will be
used by the C<type> argument to the C<resolve> method, to identify it.
=item $code
A CODE reference to the resolver function body. It will be called in list
context, being passed the list of arguments given in the C<data> argument to
the C<resolve> method. The returned list will be passed to the
C<on_resolved> callback. If the code throws an exception at call time, it will
be passed to the C<on_error> continuation. If it returns normally, the list of
values it returns will be passed to C<on_resolved>.
=back
=cut
# Plain function, not a method
sub register_resolver
{
my ( $name, $code ) = @_;
croak "Cannot register new resolver methods once the resolver has been started" if $started;
croak "Already have a resolver method called '$name'" if exists $METHODS{$name};
$METHODS{$name} = $code;
}
=head1 BUILT-IN RESOLVERS
The following resolver names are implemented by the same-named perl function,
taking and returning a list of values exactly as the perl function does:
getpwnam getpwuid
getgrnam getgrgid
getservbyname getservbyport
gethostbyname gethostbyaddr
getnetbyname getnetbyaddr
getprotobyname getprotobynumber
=cut
# Now register the inbuilt methods
register_resolver getpwnam => sub { my @r = getpwnam( $_[0] ) or die "$!\n"; @r };
register_resolver getpwuid => sub { my @r = getpwuid( $_[0] ) or die "$!\n"; @r };
register_resolver getgrnam => sub { my @r = getgrnam( $_[0] ) or die "$!\n"; @r };
register_resolver getgrgid => sub { my @r = getgrgid( $_[0] ) or die "$!\n"; @r };
register_resolver getservbyname => sub { my @r = getservbyname( $_[0], $_[1] ) or die "$!\n"; @r };
register_resolver getservbyport => sub { my @r = getservbyport( $_[0], $_[1] ) or die "$!\n"; @r };
register_resolver gethostbyname => sub { my @r = gethostbyname( $_[0] ) or die "$!\n"; @r };
register_resolver gethostbyaddr => sub { my @r = gethostbyaddr( $_[0], $_[1] ) or die "$!\n"; @r };
register_resolver getnetbyname => sub { my @r = getnetbyname( $_[0] ) or die "$!\n"; @r };
register_resolver getnetbyaddr => sub { my @r = getnetbyaddr( $_[0], $_[1] ) or die "$!\n"; @r };
register_resolver getprotobyname => sub { my @r = getprotobyname( $_[0] ) or die "$!\n"; @r };
register_resolver getprotobynumber => sub { my @r = getprotobynumber( $_[0] ) or die "$!\n"; @r };
=pod
The following three resolver names are implemented using the L<Socket> module.
getaddrinfo
getaddrinfo_array
getnameinfo
( run in 2.142 seconds using v1.01-cache-2.11-cpan-39bf76dae61 )