Net-MAC-Vendor

 view release on metacpan or  search on metacpan

lib/Net/MAC/Vendor.pm  view on Meta::CPAN

	return \@lines;
	}

#pod =item oui_url
#pod
#pod =item oui_urls
#pod
#pod Returns the URLs of the oui.txt resource. The IEEE likes to move this
#pod around. These are the default URL that C<load_cache> will use, but you
#pod can also supply your own with the C<NET_MAC_VENDOR_OUI_URL> environment
#pod variable.
#pod
#pod =cut

sub oui_url { (grep { /\Ahttp:/ } &oui_urls)[0] }

sub oui_urls {
	my @urls = 'http://standards-oui.ieee.org/oui.txt';

	unshift @urls, $ENV{NET_MAC_VENDOR_OUI_URL}
		if defined $ENV{NET_MAC_VENDOR_OUI_URL};

	@urls;
	}

#pod =item load_cache( [ SOURCE[, DEST ] ] )
#pod
#pod Downloads the current list of all OUIs in SOURCE, parses it with
#pod C<parse_oui()>, and stores it in the cache. The C<fetch_oui()> will
#pod use this cache if it exists.
#pod
#pod By default, this uses the URL from C<oui_url>, but given an argument,
#pod it tries to use that.
#pod
#pod If the url indicates that the data is compressed, the response content
#pod is decompressed before being stored.
#pod
#pod If C<load_cache> cannot load the data, it issues a warning and returns
#pod nothing.
#pod
#pod This previously used DBM::Deep if it was installed, but that was much
#pod too slow. Instead, if you want persistence, you can play with
#pod C<$Net::MAC::Vendor::Cached> yourself.
#pod
#pod If you want to store the data fetched for later use, add a destination
#pod filename to the request. To fetch from the default location and store,
#pod specify C<undef> as source.
#pod
#pod =cut

sub load_cache {
	my( $source, $dest ) = @_;

	my $data = do {;
		if( defined $source ) {
			unless( -e $source ) {
				Carp::carp "Net::Mac::Vendor cache source [$source] does not exist";
				return;
				}

			do { local( *ARGV, $/ ); @ARGV = $source; <> }
			}
		else {
			#say time . " Fetching URL";
			my $url = oui_url();
			my $tx = __PACKAGE__->ua->get( $url );
			#say time . " Fetched URL";
			#say "size is " . $tx->res->headers->header( 'content-length' );
			($url =~ /\.bz2/) ? _bunzip($tx->res->body) :
			($url =~ /\.gz/)  ? _gunzip($tx->res->body) :
			                    $tx->res->body;
			}
		};

	if( defined $dest ) {
		if( open my $fh, '>:utf8', $dest ) {
			print { $fh } $data;
			close $fh;
			}
		else { # notify on error, but continue
			Carp::carp "Could not write to '$dest': $!";
			}
		}


	# The PRIVATE entries fill in a template with no
	# company name or address, but the whitespace is
	# still there. We need to split on a newline
	# followed by some potentially horizontal whitespace
	# and another newline
	my $CRLF = qr/(?:\r?\n)/;
	my @entries = split /[\t ]* $CRLF [\t ]* $CRLF/x, $data;
	shift @entries;

	my $count = '';
	foreach my $entry ( @entries ) {
		$entry =~ s/^\s+//;
		my $oui = substr $entry, 0, 8;
		__PACKAGE__->add_to_cache( $oui, parse_oui( $entry ) );
		}

	return 1;
	}

sub _bunzip {
	my $content = shift;
	if (eval { +require Compress::Bzip2; 1 }) {
		return Compress::Bzip2::memBunzip($content);
		}
	else {
		require File::Temp;
		my ($tempfh, $tempfilename) = File::Temp::tempfile( UNLINK => 1 );
		binmode $tempfh, ':raw';
		print $tempfh $content;
		close $tempfh;

		open my $unzipfh, "bunzip2 --stdout $tempfilename |"
			or die "cannot pipe to bunzip2: $!";
		local $/;
		return <$unzipfh>;
		}



( run in 0.608 second using v1.01-cache-2.11-cpan-5a3173703d6 )