class GxG::Networking::SftpClient
Public Class Methods
new()
click to toggle source
# File lib/gxg/net_clients.rb, line 4329 def initialize() @client = nil @user = nil self end
Public Instance Methods
async_download(the_remote_source=nil, the_destination=nil, options={}, &progress_block)
click to toggle source
# File lib/gxg/net_clients.rb, line 4457 def async_download(the_remote_source=nil, the_destination=nil, options={}, &progress_block) # progress - either a block or an object to act as a progress callback. See the discussion of "progress monitoring" # at http://net-ssh.github.io/net-sftp/classes/Net/SFTP/Operations/Download.html. # # :requests - the number of pending SFTP requests to allow at any given time. When downloading an # entire directory tree recursively, this will default to 16. Setting this higher might improve throughput. # Reducing it will reduce throughput. # # :read_size - the maximum number of bytes to read at a time from the source. Increasing this value might # improve throughput. It defaults to 32,000 bytes. # result = false begin if @client unless the_remote_source.is_a?(::String) raise ArgumentError, "You MUST provide a local path as a String." end unless the_destination.is_a?(::String) raise ArgumentError, "You MUST provide a remote path as a String." end if progress_block.respond_to?(:call) channel = @client.download(the_remote_source, the_destination, options, &progress_block) else channel = @client.download(the_remote_source, the_destination, options) end channel.wait # True result means the request was sent, not that it completed. result = true end rescue Exception => the_error log_error({:error => the_error, :parameters => {:remote_path => the_remote_source, :local_path => the_destination, :options => options}}) end result end
async_upload(the_local_source=nil, the_destination=nil, options={}, &progress_block)
click to toggle source
# File lib/gxg/net_clients.rb, line 4378 def async_upload(the_local_source=nil, the_destination=nil, options={}, &progress_block) # options: #:progress - either a block or an object to act as a progress callback. See the discussion of "progress monitoring" # below. # #:requests - the number of pending SFTP requests to allow at any given time. When uploading an entire directory # tree recursively, this will default to 16, otherwise it will default to 2. Setting this higher might improve # throughput. Reducing it will reduce throughput. # #:read_size - the maximum number of bytes to read at a time from the source. Increasing this value might # improve throughput. It defaults to 32,000 bytes. # #:name - the filename to report to the progress monitor when an IO object is given as local. This defaults # to "<memory>". result = false begin if @client unless the_local_source.is_a?(::String) raise ArgumentError, "You MUST provide a local path as a String." end unless the_destination.is_a?(::String) raise ArgumentError, "You MUST provide a remote path as a String." end unless options[:name] options[:name] = File.basename(the_local_source) end if progress_block.respond_to?(:call) channel = @client.upload(the_local_source, the_destination, options, &progress_block) else channel = @client.upload(the_local_source, the_destination, options) end channel.wait # True result means the request was sent, not that it completed. result = true end rescue Exception => the_error log_error({:error => the_error, :parameters => {:local_path => the_local_source, :remote_path => the_destination, :options => options}}) end result end
change_ownership(the_path=nil, new_owners=nil, &block)
click to toggle source
# File lib/gxg/net_clients.rb, line 4679 def change_ownership(the_path=nil, new_owners=nil, &block) result = false begin unless the_path.is_a?(::String) raise ArgumentError, "You MUST supply a remote path. (/path/to/something)." end unless new_owners.is_a?(::Hash) raise ArgumentError, "You MUST supply a Hash with :user, and optionally :group, defined with a String." end unless new_owners[:user].is_a?(::String) raise ArgumentError, "You MUST supply a Hash with :user, and optionally :group, defined with a String." end response = @client.setstat!(the_path, new_owners) if block.respond_to?(:call) block.call(response) end result = response.ok? rescue Exception => the_error log_error({:error => the_error, :parameters => {:path => the_path, :new_owners => new_owners}}) end result end
change_permissions(the_path=nil, new_permissions=nil, &block)
click to toggle source
# File lib/gxg/net_clients.rb, line 4702 def change_permissions(the_path=nil, new_permissions=nil, &block) result = false begin unless the_path.is_a?(::String) raise ArgumentError, "You MUST supply a remote path. (/path/to/something)." end unless new_permissions raise ArgumentError, "You MUST supply a new permission value. (GxG permission or Integer/Octal)." end if new_permissions.is_a?(::Hash) new_permissions = ::File.gxg_permissions_to_mode(new_permissions) end response = @client.setstat!(the_path, {:permissions => new_permissions}) if block.respond_to?(:call) block.call(response) end result = response.ok? rescue Exception => the_error log_error({:error => the_error, :parameters => {:path => the_path, :new_permissions => new_permissions}}) end result end
closed?()
click to toggle source
# File lib/gxg/net_clients.rb, line 4362 def closed?() if @client @client.closed? else true end end
download(the_remote_source=nil, the_destination=nil, options={}, &progress_block)
click to toggle source
# File lib/gxg/net_clients.rb, line 4492 def download(the_remote_source=nil, the_destination=nil, options={}, &progress_block) # progress - either a block or an object to act as a progress callback. See the discussion of "progress monitoring" # at http://net-ssh.github.io/net-sftp/classes/Net/SFTP/Operations/Download.html. # # :requests - the number of pending SFTP requests to allow at any given time. When downloading an # entire directory tree recursively, this will default to 16. Setting this higher might improve throughput. # Reducing it will reduce throughput. # # :read_size - the maximum number of bytes to read at a time from the source. Increasing this value might # improve throughput. It defaults to 32,000 bytes. # result = false begin if @client unless the_remote_source.is_a?(::String) raise ArgumentError, "You MUST provide a remote path as a String." end unless the_destination.is_a?(::String) raise ArgumentError, "You MUST provide a local path (or file name) as a String." end if progress_block.respond_to?(:call) result = @client.download!(the_remote_source, the_destination, options, &progress_block) else result = @client.download!(the_remote_source, the_destination, options) end end rescue Exception => the_error log_error({:error => the_error, :parameters => {:remote_path => the_remote_source, :local_path => the_destination, :options => options}}) end result end
entries(the_path=nil, pattern=nil, flags=0, &block)
click to toggle source
Remote File System Operations and Objects
# File lib/gxg/net_clients.rb, line 4524 def entries(the_path=nil, pattern=nil, flags=0, &block) # List entries in a given remote path. # If block is provided, resultant list is iterated over the block - (each_entry). result = [] begin if @client # Validate the_path: /.*(?:\\|\/)(.+)$/ from: https://www.experts-exchange.com/questions/22088316/Extract-Filename-from-PATH-using-REGEX.html unless (/.*(?:\\|\/)(.+)$/.match(the_path.to_s) || the_path.to_s.split("/").size > 0 || the_path == "/") raise ArgumentError, "You MUST provide a valid remote file system path." end if pattern.is_a?(::String) # use glob unless flags.is_a?(::Numeric) flags = 0 end raw_list = @client.dir.glob(the_path, pattern, flags) else # use entries raw_list = @client.dir.entries(the_path) end list = [] raw_permission = { :execute => false, :rename => false, :move => false, :destroy => false, :create => false, :write => false, :read => false } blank_permissions = {:effective => nil, :owner => raw_permission.clone, :group => raw_permission.clone, :other => raw_permission.clone} # raw_list.each do |details| # unless details.name == "." || details.name == ".." # record = {:title => (details.name), :type => :virtual_directory, :owner_type => :virtual_directory, :on_device => nil, :on_device_major => nil, :on_device_minor => nil, :is_device => nil, :is_device_major => nil, :is_device_minor => nil, :inode => nil, :flags => [], :hardlinks_to => 0, :user_id => nil, :group_id => nil, :size => 0, :block_size => 0, :blocks => 0, :accessed => nil, :modified => nil, :status_modified => nil, :permissions => nil, :mode=>nil} permission_record = blank_permissions.clone # record = record.merge({:size => (details.attributes.size), :accessed => (Time.at(details.attributes.atime)).to_datetime, :modified => (Time.at(details.attributes.mtime)).to_datetime, :state_modified => (Time.at(details.attributes.mtime)).to_datetime, :user_id => (details.attributes.uid), :group_id => (details.attributes.gid)}) if details.directory?() record[:type] = :directory record[:owner_type] = :directory end if details.file?() record[:type] = :file record[:owner_type] = :file end if details.symlink?() record[:type] = :symlink record[:owner_type] = :symlink end # puts "Got: #{details.attributes.permissions.inspect}" record[:permissions] = ::File.mode_permission_to_gxg(details.attributes.permissions.to_i) current_groups = @client.session.exec!("groups").gsub("\n","").split(" ") if current_groups.size > 0 effective_permissions = raw_permission.clone if @user == details.attributes.owner include_owner = true else include_owner = false end if current_groups.include?(details.attributes.group) include_group = true else include_group = false end # permissions_stack = [] if include_owner permissions_stack << record[:permissions][:owner] end if include_group permissions_stack << record[:permissions][:group] end permissions_stack << record[:permissions][:other] permissions_stack.each do |entry| entry.keys do |the_key| if entry[(the_key)] == true effective_permissions[(the_key)] = true end end end record[:permissions][:effective] = effective_permissions if record[:permissions][:effective][:read] record[:flags] << :read end if record[:permissions][:effective][:write] record[:flags] << :write end end list << record end # end # if block.respond_to?(:call) list.each do |entry| block.call(entry) end end result = list end rescue Exception => the_error log_error({:error => the_error, :parameters => {:remote_path => the_path}}) end result end
login(the_url=nil, options={})
click to toggle source
# File lib/gxg/net_clients.rb, line 4335 def login(the_url=nil, options={}) result = false begin unless the_url.is_a?(::URI::Generic) raise ArgumentError, "You MUST provide a valid URI" end @user = the_url.user if the_url.password options[:password] = the_url.password end if the_url.port options[:port] = the_url.port end @client = ::Net::SFTP.start(the_url.hostname, the_url.user, options) @client.connect! if @client.closed? @client = nil raise Exception, "Failed to open a connection." else result = true end rescue Exception => the_error log_error({:error => the_error, :parameters => {:url => the_url, :options => options}}) end result end
logout()
click to toggle source
# File lib/gxg/net_clients.rb, line 4370 def logout() if @client @client.close_channel @client = nil true end end
make_directory(the_path=nil, &block)
click to toggle source
# File lib/gxg/net_clients.rb, line 4785 def make_directory(the_path=nil, &block) result = false begin unless the_path.is_a?(::String) raise ArgumentError, "You MUST supply a new directory path. (/path/to/new_dir)." end response = @client.mkdir!(the_path) if block.respond_to?(:call) block.call(response) end result = response.ok? rescue Exception => the_error log_error({:error => the_error, :parameters => {:original_name => name, :new_name => new_name}}) end result end
make_link(new_link_path=nil, existing_path=nil, symlink=true, &block)
click to toggle source
# File lib/gxg/net_clients.rb, line 4742 def make_link(new_link_path=nil, existing_path=nil, symlink=true, &block) result = false begin unless new_link_path.is_a?(::String) raise ArgumentError, "You MUST supply a new link path. (/path/to/new_link)." end unless existing_path.is_a?(::String) raise ArgumentError, "You MUST supply an existing file path. (/path/to/file)." end unless symlink symlink = true end response = @client.link!(new_link_path,existing_path,symlink) if block.respond_to?(:call) block.call(response) end result = response.ok? rescue Exception => the_error log_error({:error => the_error, :parameters => {:new_link_path => new_link_path, :existing_path => existing_path, :symlink => symlink}}) end result end
open_remote_file(the_path=nil, permissions={})
click to toggle source
# File lib/gxg/net_clients.rb, line 4625 def open_remote_file(the_path=nil, permissions={}) result = nil begin if @client filename = ::File.basename(the_path) entries = this().entries(::File.dirname(the_path)) open_only = false flags = [] entries.each do |item| if item[:title] == filename open_only = true flags = item[:flags] break end end if open_only if flags.include?(:read) if flags.include?(:write) open_mode = "w+" else open_mode = "r" end else if flags.include?(:write) open_mode = "w" else open_mode = "r" end end #open result = @client.file.open(the_path.to_s, open_mode) else #create if permissions.is_a?(::Hash) if permissions[:owner].is_a?(::Hash) && permissions[:group].is_a?(::Hash) && permissions[:other].is_a?(::Hash) permissions = ::File.gxg_permissions_to_mode(permissions) end end if permissions.is_a?(::Numeric) unless permissions > 0 permissions = 0644.to_i end else permissions = 0644.to_i end result = @client.file.open(the_path.to_s, "w+", permissions) end end rescue Exception => the_error log_error({:error => the_error, :parameters => {:remote_path => the_path, :permissions => permissions}}) end result end
remove_directory(the_path=nil, &block)
click to toggle source
# File lib/gxg/net_clients.rb, line 4802 def remove_directory(the_path=nil, &block) result = false begin unless the_path.is_a?(::String) raise ArgumentError, "You MUST supply a directory path to remove. (/path/to/dir)." end response = @client.rmdir!(the_path) if block.respond_to?(:call) block.call(response) end result = response.ok? rescue Exception => the_error log_error({:error => the_error, :parameters => {:original_name => name, :new_name => new_name}}) end result end
remove_remote_file(the_path=nil, &block)
click to toggle source
# File lib/gxg/net_clients.rb, line 4725 def remove_remote_file(the_path=nil, &block) result = false begin unless the_path.is_a?(::String) raise ArgumentError, "You MUST supply a remote file path. (/path/to/file)." end response = @client.remove!(the_path) if block.respond_to?(:call) block.call(response) end result = response.ok? rescue Exception => the_error log_error({:error => the_error, :parameters => {:path => the_path}}) end result end
rename(name=nil, new_name=nil,&block)
click to toggle source
# File lib/gxg/net_clients.rb, line 4765 def rename(name=nil, new_name=nil,&block) result = false begin unless name.is_a?(::String) raise ArgumentError, "You MUST supply a remote file path. (/path/to/old_name)." end unless new_name.is_a?(::String) raise ArgumentError, "You MUST supply a new file name path. (/path/to/new_name)." end response = @client.rename!(name,new_name,0x0004) if block.respond_to?(:call) block.call(response) end result = response.ok? rescue Exception => the_error log_error({:error => the_error, :parameters => {:original_name => name, :new_name => new_name}}) end result end
upload(the_local_source=nil, the_destination=nil, options={}, &progress_block)
click to toggle source
# File lib/gxg/net_clients.rb, line 4419 def upload(the_local_source=nil, the_destination=nil, options={}, &progress_block) # options: #:progress - either a block or an object to act as a progress callback. See the discussion of "progress monitoring" # below. # #:requests - the number of pending SFTP requests to allow at any given time. When uploading an entire directory # tree recursively, this will default to 16, otherwise it will default to 2. Setting this higher might improve # throughput. Reducing it will reduce throughput. # #:read_size - the maximum number of bytes to read at a time from the source. Increasing this value might # improve throughput. It defaults to 32,000 bytes. # #:name - the filename to report to the progress monitor when an IO object is given as local. This defaults # to "<memory>". result = false begin if @client unless the_local_source.is_a?(::String) raise ArgumentError, "You MUST provide a local path as a String." end unless the_destination.is_a?(::String) raise ArgumentError, "You MUST provide a remote path as a String." end unless options[:name] options[:name] = File.basename(the_local_source) end if progress_block.respond_to?(:call) result = @client.upload!(the_local_source, the_destination, options, &progress_block) else result = @client.upload!(the_local_source, the_destination, options) end end rescue Exception => the_error log_error({:error => the_error, :parameters => {:local_path => the_local_source, :remote_path => the_destination, :options => options}}) end result end