App-geoip

 view release on metacpan or  search on metacpan

lib/App/geoip.pm  view on Meta::CPAN

    "u|update!"		=> \$conf{update},
    "f|fetch!"		=> \$conf{fetch},
    "d|dist|distance!"	=> \$conf{distance},
    "w|whois!"		=> \$conf{whois},
    "s|short!"		=> \$conf{short},
    "j|json!"		=> \$conf{json},
    "J|json-pretty!"	=> \ my $opt_J,
    "l|local=s"		=> \$conf{local_location},

    "D|DB=s"		=> \$conf{dsn},

    # Queries
      "country=s"	=> \ my $query_c,

    "v|verbose:1"	=> \(my $opt_v = 0),
    ) or usage (1);

sub pod_text {
    require Pod::Text::Color;
    my $m = $ENV{NO_COLOR} ? "Pod::Text" : "Pod::Text::Color";
    my $p = $m->new ();
    open my $fh, ">", \my $out;
    $p->parse_from_file ($0, $fh);
    close $fh;
    print $out;
    exit 0;
    } # pod_text

sub pod_nroff {
    first { -x "$_/nroff" } grep { -d } split m/:+/ => $ENV{PATH} or pod_text ();

    require Pod::Man;
    my $p = Pod::Man->new ();
    open my $fh, "|-", "nroff", "-man";
    $p->parse_from_file ($0, $fh);
    close $fh;
    exit 0;
    } # pod_nroff

$opt_v >= 7 and _dump ("Configuration", \%conf);

if (defined $opt_J) {
    if ($opt_J) {
	$conf{json_pretty}++;
	$conf{json}++;
	}
    else {
	$conf{json_pretty} = 0;
	}
    }
$conf{json} and $opt_J = $conf{json_pretty};

if (@ARGV == 0 and my $eh = $ENV{GEOIP_HOST}) {
    $eh =~ s{[\s\r\n]+\z}{};
    # No IPv6 support yet
    if ($eh =~ m{^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$} and
	$1 > 0 && $1 < 256 && $2 < 256 && $3 < 256 && $4 < 256) {
	# Simplistic IPv4
	push @ARGV => $eh;
	}
    elsif ($eh =~ m/^\w[-.\w]{0,252}\z/) { # Skip invalid clipboard content
	# https://en.wikipedia.org/wiki/Hostname#Syntax
	for (split m/\./ => $eh) {
	    m/^\w[-\w]{0,62}$/ or die "$eh is not a valid hostname or IPv4\n";
	    }
	push @ARGV => $eh;
	}
    }

my $dbh = do {
    my $dsn = $conf{dsn} =~ s{^b=(?=\w+:)}{}ir; # catch -DB=.. instead of --DB=
    my $help = $dsn =~ m/^dbi:(\w+):/i
	? "Did you forget to install DBD::$1?"
	: "Maybe the matching DBD for $dsn is not installed";
    eval {
	my %seen;
	my $fail = sub {
	    my $e = DBI->errstr or return;
	    !$seen{$e}++ and warn "$e\n";
	    };
	local $SIG{__WARN__} = $fail;
	local $SIG{__DIE__}  = $fail;
	DBI->connect ($conf{dsn}, undef, undef, {
	    AutoCommit		=> 0,
	    RaiseError		=> 1,
	    PrintError		=> 1,
	    ShowErrorStatement	=> 1,
	    });
	} or die "Cannot continue without a working database\n$help\n";
    };

sub _dump {
    my ($label, $ref) = @_;
    print STDERR $use_data_peek
	? Data::Peek::DDumper ({ $label => $ref })
	: Data::Dumper->Dump ([$ref], [$label]);
    } # _dump

# Based on GeoIP2 CSV databases
#  City:   http://geolite.maxmind.com/download/geoip/database/GeoLite2-City-CSV.zip
#  Country http://geolite.maxmind.com/download/geoip/database/GeoLite2-Country-CSV.zip
#  ASN     http://geolite.maxmind.com/download/geoip/database/GeoLite2-ASN-CSV.zip

my $idx_type = $conf{dsn} =~ m/:Pg/     ? "using btree" : "";
my $truncate = $conf{dsn} =~ m/:SQLite/ ? "delete from" : "truncate table";

unless (grep m/\b country \b/ix => $dbh->tables (undef, undef, undef, undef)) {
    say "Create table stamps";
    $dbh->do (qq; create table stamps (
	name		text		not null	primary key,
	stamp		bigint);
	);
    say "Create table continent";
    $dbh->do (qq; create table continent (
	id		char (4)	not null	primary key,
	name		text);
	);
    say "Create table country";
    $dbh->do (qq; create table country (
	id		bigint		not null	primary key,
	name		text		not null,



( run in 1.934 second using v1.01-cache-2.11-cpan-df04353d9ac )