# rubocop:disable Naming/AccessorMethodName 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 return unless require msg = "(#{self.class}) You should redefine the file_pattern function " msg << "as a RegEx expression that matches the target remote file" raise WrongConst, msg 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 return unless require msg = "(#{self.class}) You should redefine remote_subfolder " msg << "as the folder where the target file sits. Ex: /IN/Personnel" raise MissRemoteFolder, msg 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 || [rm_fd, remote_subfolder].compact.join('/') end def to_remote_path(file) [remote_folder, file].compact.join('/') end def local_folder options.dig(:sftp, :local_folder) || "." end def with_remote_files(folder: remote_folder, pattern: file_pattern) sftp.files(folder, pattern: pattern).each do |remote_file| yield(remote_file) if block_given? end rescue ArgumentError raise rescue ::Net::SFTP::StatusException => err log(:error) { msg = "(#{self.class}) There was an error trying to access " msg << "the remote folder '#{remote_folder}': #{err}" msg } [] 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| next if 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 def get_last with_remote_files.last.tap do |file| next unless 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 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| next if files.empty? puts "Moved the file(s) to the #{archive_subfolder} folder" 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 # rubocop:enable Naming/AccessorMethodName