class Stockboy::Providers::FTP

Get data from a remote FTP server

Allows for selecting the appropriate file to be read from the given directory by glob pattern or regex pattern (glob string is more efficient for listing files from FTP). By default the :last file in the list is used, but can be controlled by sorting and reducing with the {#pick} option.

Job template DSL

provider :ftp do
  host      'ftp.example.com'
  username  'example'
  password  '424242'
  file_dir  'data/daily'
  file_name /report-[0-9]+\.csv/
  pick      ->(list) { list[-2] }
end

Public Class Methods

new(opts={}, &block) click to toggle source

Initialize a new FTP provider

Calls superclass method Stockboy::Provider::new
# File lib/stockboy/providers/ftp.rb, line 98
def initialize(opts={}, &block)
  super(opts, &block)
  @host         = opts[:host]
  @passive      = opts[:passive]
  @username     = opts[:username]
  @password     = opts[:password]
  @secure       = opts[:secure]
  @binary       = opts[:binary]
  @file_dir     = opts[:file_dir]
  @file_name    = opts[:file_name]
  @file_newer   = opts[:file_newer]
  @file_smaller = opts[:file_smaller]
  @file_larger  = opts[:file_larger]
  @pick         = opts[:pick] || :last
  DSL.new(self).instance_eval(&block) if block_given?
  @open_adapter  = nil
end

Public Instance Methods

adapter() { |open_adapter| ... } click to toggle source
# File lib/stockboy/providers/ftp.rb, line 120
def adapter
  return yield @open_adapter if @open_adapter

  adapter_class.new(self).open do |ftp|
    @open_adapter = ftp
    ftp.chdir file_dir if file_dir
    response = yield ftp
    @open_adapter = nil
    response
  end

rescue adapter_class.exception_class => e
  errors << e.message
  logger.warn e.message
  nil
end
adapter_class() click to toggle source
# File lib/stockboy/providers/ftp.rb, line 116
def adapter_class
  secure ? SFTPAdapter : FTPAdapter
end
clear() click to toggle source
Calls superclass method Stockboy::Provider#clear
# File lib/stockboy/providers/ftp.rb, line 158
def clear
  super
  @matching_file = nil
  @data_time = nil
  @data_size = nil
end
client() { |client| ... } click to toggle source
# File lib/stockboy/providers/ftp.rb, line 137
def client
  adapter { |ftp| yield ftp.client }
end
delete_data() click to toggle source
# File lib/stockboy/providers/ftp.rb, line 149
def delete_data
  raise Stockboy::OutOfSequence, "must confirm #matching_file or calling #data" unless picked_matching_file?
  adapter do |ftp|
    logger.info "FTP deleting file #{host} #{file_dir}/#{matching_file}"
    ftp.delete matching_file
    matching_file
  end
end
matching_file() click to toggle source
# File lib/stockboy/providers/ftp.rb, line 141
def matching_file
  return @matching_file if @matching_file
  adapter do |ftp|
    file_listing = ftp.list_files
    @matching_file = pick_from file_listing.select(&file_name_matcher)
  end
end

Private Instance Methods

fetch_data() click to toggle source
# File lib/stockboy/providers/ftp.rb, line 167
def fetch_data
  adapter do |ftp|
    validate_file(matching_file)
    if valid?
      logger.debug "FTP getting file #{inspect_matching_file}"
      @data = ftp.download(matching_file)
      logger.debug "FTP got file #{inspect_matching_file} (#{data_size} bytes)"
    end
  end
  !@data.nil?
end
file_name_matcher() click to toggle source
# File lib/stockboy/providers/ftp.rb, line 189
def file_name_matcher
  case file_name
  when Regexp
    ->(i) { i =~ file_name }
  when String
    ->(i) { ::File.fnmatch(file_name, i) }
  end
end
inspect_matching_file() click to toggle source
# File lib/stockboy/providers/ftp.rb, line 226
def inspect_matching_file
  "#{host} #{file_dir}/#{matching_file}"
end
picked_matching_file?() click to toggle source
# File lib/stockboy/providers/ftp.rb, line 179
def picked_matching_file?
  !!@matching_file
end
validate() click to toggle source
# File lib/stockboy/providers/ftp.rb, line 183
def validate
  errors << "host must be specified" if host.blank?
  errors << "file_name must be specified" if file_name.blank?
  errors.empty?
end
validate_file(data_file) click to toggle source
# File lib/stockboy/providers/ftp.rb, line 198
def validate_file(data_file)
  return errors << "No matching files" unless data_file
  validate_file_newer(data_file)
  validate_file_smaller(data_file)
  validate_file_larger(data_file)
end
validate_file_larger(data_file) click to toggle source
# File lib/stockboy/providers/ftp.rb, line 219
def validate_file_larger(data_file)
  @data_size ||= adapter { |ftp| ftp.size(data_file) }
  if file_larger and @data_size < file_larger
    errors << "File size smaller than #{file_larger}"
  end
end
validate_file_newer(data_file) click to toggle source
# File lib/stockboy/providers/ftp.rb, line 205
def validate_file_newer(data_file)
  @data_time ||= adapter { |ftp| ftp.modification_time(data_file) }
  if file_newer and @data_time < file_newer
    errors << "No new files since #{file_newer}"
  end
end
validate_file_smaller(data_file) click to toggle source
# File lib/stockboy/providers/ftp.rb, line 212
def validate_file_smaller(data_file)
  @data_size ||= adapter { |ftp| ftp.size(data_file) }
  if file_smaller and @data_size > file_smaller
    errors << "File size larger than #{file_smaller}"
  end
end