class Eco::API::UseCases::DefaultCases::Samples::Sftp < Eco::API::Common::Loaders::UseCase class WrongConst < ArgumentError; end class MissRemoteFolder < ArgumentError; end require_relative 'cli/sftp_cli' name "sftp" type :other CONST_REFERRAL = /^(?:::)?(?:[A-Z][a-zA-Z0-9_]*(?:::[A-Z][a-zA-Z0-9_]*)*)$/ def main(session, options, usecase) options[:end_get] = false raise "The SFTP is not configured" unless session.sftp? case options.dig(:sftp, :command) when :list list_folder when :get get_files when :get_last get_last when :archive archive_files end end private # Can't pass this via CLI option, as it breaks the regular expression def file_pattern(require: true) fpc = file_pattern_const return fpc if fpc raise WrongConst, "(#{self.class}) You should redefine the file_pattern function as a RegEx expression that matches the target remote file" if require end def file_pattern_const if fpc = options.dig(:sftp, :file_pattern_const) raise WrongConst, "(#{self.class}) Invalid file pattern const referral: #{fpc}" unless fpc.match(CONST_REFERRAL) begin self.eval(fpc) rescue NameError self.class.const_get(fpc) end end rescue NameError raise WrongConst, "(#{self.class}) Unknown constant: #{fpc}" end # Ex: "/IN/Personnel" def remote_subfolder(require: true) rm_sf = options.dig(:sftp, :remote_subfolder) return rm_sf if rm_sf raise MissRemoteFolder, "(#{self.class}) You should redefine remote_subfolder as the folder where the target file sits. Ex: /IN/Personnel" if require end # `remote_target_folder` overrides `sftp_config.remote_folder` as well as `remote_subfolder` # `remote_folder` overrides `sftp_config.remote_folder` but NOT `remote_subfolder` def remote_folder rm_tf = options.dig(:sftp, :remote_target_folder) rm_fd = options.dig(:sftp, :remote_folder) || sftp_config.remote_folder rm_tf || File.join(rm_fd, remote_subfolder) end def to_remote_path(file) File.join(remote_folder, file) end def local_folder options.dig(:sftp, :local_folder) || "." end def with_remote_files begin sftp.files(remote_folder, pattern: file_pattern).each do |remote_file| yield(remote_file) if block_given? end rescue ArgumentError raise rescue ::Net::SFTP::StatusException => e logger.error("(#{self.class}) There was an error trying to access the remote folder '#{remote_folder}'") [] end end def list_folder puts "Listing remote folder: '#{remote_folder}' (host: #{sftp.host}):" with_remote_files {|file| puts file.longname} end def get_files with_remote_files.tap do |files| unless files.empty? file_names = files.map {|file| to_remote_path(file.name)} puts "Getting the following files into the local folder '#{local_folder}':" puts file_names sftp.download(file_names, local_folder: local_folder) end end end def get_last with_remote_files.last.tap do |file| if file file_name = to_remote_path(file.name) puts "Getting the following file: #{file_name}" sftp.download(file_name, local_folder: local_folder) end end end def archive_files with_remote_files do |file| source = to_remote_path(file.name) # should probably be file.longname dest = to_remote_path("#{archive_subfolder}/#{file.name}") move_file(source, dest) end.tap do |files| puts "Moved the file(s) to the #{archive_subfolder} folder" unless files.empty? end end def move_file(source, dest) sftp.move(source, dest, 0x0001) do |response| if response.ok? puts "#{source}\n -to-> #{dest}" else puts "Could not move file #{source}" end end end def archive_subfolder "Archive" end def sftp_config session.config.sftp end def sftp session.sftp end end