Using Callbacks with Net::SFTP::Foreign in Perl

One of the more robust SFTP modules for Perl is Net::SFTP::Foreign.  Among its many features, it offers a find method that performs a recursive search over a path and returns a list.  It also accepts a callback subroutine as an argument which allows us to customize the search filter.   

The find method relies on the callback to determine if we want the file in our list.   The callback should return 1 for a files accept and 0 for files we reject.

Here I am retrieving a list of files that meet the following criteria:

  • File timestamp is from yesterday
  • File size is under 2GB
  • File name confirms to a standard (/sftp/vendor/output_*.mp3 or wav)
#!/usr/bin/perl

use strict;
use warnings;
use Net::SFTP::Foreign;
use Fcntl qw(S_ISDIR S_ISREG);
use DateTime::Format::Strptime;

# Get start epoch time - yesterday at midnight
my $dt = DateTime->now(time_zone => 'America/New_York');
$dt->subtract(days => 1);
$dt->set_hour(0);
$dt->set_minute(0);
$dt->set_second(0);

my $epoch_start = $dt->epoch;

# Get end epoch time - yesterday at 23:59:59
$dt->set_hour(23);
$dt->set_minute(59);
$dt->set_second(59);

my $epoch_end = $dt->epoch;

my $sftp_host = 'sftp.vendor.com';
my $sftp_username = 'username';
my $sftp_password = 'xxxxx';
my $sftp_port = 22;

# Max file size
my $max_size = 2147483648;

my $path = '/sftp/vendor';

my $sftp = Net::SFTP::Foreign->new($sftp_host,port => $sftp_port, user => $sftp_username, password => $sftp_password, stderr_discard => 1);

# Retrieve list of files matching criteria
my @list = $sftp->find($path, names_only => 1, wanted => \&callback);

$sftp->disconnect;

# Perform validation checks
sub callback
{
    my($sftp, $data, $offset, $size) = @_;

    my $check_type          = ( S_ISREG($data->{a}->perm) );
    my $check_size          = ( $data->{a}->size < $max_size );
    my $check_timestamp     = ( $data->{a}->mtime >= $epoch_start &&  $data->{a}->mtime <= $epoch_end );
    my $check_name          = ( $data->{filename} =~ m[^$path/output_*\.(mp3|wav)]i );

    # Return true if all checks pass
    return 1 if ($check_name && $check_type && $check_size && $check_timestamp);

    # Otherwise, return false
    return 0;
}