Acme-Free-API-Geodata-GeoIP

 view release on metacpan or  search on metacpan

bin/geoip  view on Meta::CPAN

use strict;
use warnings;

use Acme::Free::API::Geodata::GeoIP;

my $ip = shift @ARGV;
if(!defined($ip)) {
    die("Usage: geoip IPADDRESS");
}
  
my $agent = Acme::Free::API::Geodata::GeoIP->new(debug => 1);

my $geodata = $agent->lookup($ip);

if(!defined($geodata)) {
    die("Lookup failed");
}

print "$ip is hosted by ", $geodata->{org}, " in ", $geodata->{city}, " (", $geodata->{country}, ")\n";

lib/Acme/Free/API/Geodata/GeoIP.pm  view on Meta::CPAN

sub new($proto, %config) {
    my $class = ref($proto) || $proto;

    my $self = bless \%config, $class;

    my $agent = WWW::Mechanize->new(cookie_jar => {});
    $agent->agent('PerlMonks contest/1 (https://perlmonks.org/?node_id=11161472)');
    $agent->stack_depth(1);
    $self->{agent} = $agent;

    if(!defined($self->{debug})) {
        $self->{debug} = 0;
    }

    return $self;
}

sub lookup($self, $ip) {
    my $url = "http://ip-api.com/json/" . $ip;

    my $content = $self->_fetchURL($url);

    my $ok = 0;
    my $decoded;
    eval {
        $decoded = decode_json($content);
        $ok = 1;
    };

    if(!$ok || !defined($decoded)) {
        $self->_debuglog("Failed to decode response. Not a JSON document?");
        $self->_debuglog(Dumper($decoded));
        return;
    }

    #$self->_debuglog(Dumper($decoded));

    return $decoded;
}



# internal helpers
# these are copied from CAVACs vast framework. But we don't want hundreds of dependencies in this example code, only a couple of functions
sub _fetchURL($self, $url) {
    $self->{agent}->get($url);

    if(!$self->{agent}->success()) {
        $self->_debuglog("Network error while fetching URL $url");
        return;
    }

    my $response = $self->{agent}->response();
    if(!defined($response)) {
        $self->_debuglog("Could not get agent response");
        return;
    }

    my $content = $response->decoded_content;
    if(!defined($content) || !length($content)) {
        $self->_debuglog("Could not get response content");
        return;
    }

    #$self->_debuglog(Dumper($content));

    return $content;

}

sub _debuglog($self, $message) {
    if(!$self->{debug}) {
        return;
    }
    print STDERR $message, "\n";
}


1;
__END__

=head1 NAME

Acme::Free::API::Geodata::GeoIP - Lookup GeoIP data for an IP address

=head1 SYNOPSIS

  use Acme::Free::API::Geodata::GeoIP;
  
  my $agent = Acme::Free::API::Geodata::GeoIP->new(debug => 1);

  my $geodata = $agent->lookup('24.48.0.1');

  if(!defined($geodata)) {
      die("Lookup failed");
  }

  print "$ip is hosted by ", $geodata->{org}, " in ", $geodata->{city}, " (", $geodata->{country}, ")\n";

=head1 DESCRIPTION

This module looks up GeoIP data through a public API, see L<https://www.freepublicapis.com/ip-geolocation-api>.

It returns a hashref on success, undefined on failure. To see what went wrong, set debug to a true value in new().

=head1 SEE ALSO

Call for API implementations on PerlMonks: L<https://perlmonks.org/?node_id=11161472>

=head1 AUTHOR

Rene Schickbauer, E<lt>cavac@cpan.orgE<gt>

=head1 SOURCECODE

t/Acme-Free-API-Geodata-GeoIP.t  view on Meta::CPAN

#########################

# change 'tests => 1' to 'tests => last_test_to_print';

use strict;
use warnings;

use Test::More tests => 8;
BEGIN { use_ok('Acme::Free::API::Geodata::GeoIP') };

my $geoip = Acme::Free::API::Geodata::GeoIP->new(debug => 0);
ok(defined($geoip), 'Initialization');

my %map = (
    '24.48.0.1' => 'Videotron',
    '94.130.141.212' => 'Hetzner',
);

foreach my $ip (sort keys %map) {
    my $org = $map{$ip};



( run in 1.086 second using v1.01-cache-2.11-cpan-49f99fa48dc )