Class: SFML::Network::Ftp

Inherits:
Object
  • Object
show all
Defined in:
lib/sfml/network/ftp.rb

Overview

CSFML's FTP client. Useful for the rare game that needs to fetch extra content from a plain-FTP server. For anything modern, Ruby's stdlib Net::FTP (and the Net::FTP gem) is a much nicer tool — this binding exists for parity with CSFML.

ftp = SFML::Network::Ftp.new
ftp.connect("ftp.example.com").ok?      #=> true
ftp..ok?                  #=> true
ftp.directory_listing("/").names         #=> ["pub", "incoming", ...]
ftp.download("/pub/file.bin", "/tmp/")
ftp.disconnect

Each call returns a Response (or DirectoryResponse / ListingResponse for commands that return a path or a list). All responses expose #ok?, #status (Integer), #status_symbol, #message.

Defined Under Namespace

Classes: DirectoryResponse, ListingResponse, Response

Constant Summary collapse

DEFAULT_PORT =

Standard port for the protocol.

21
DEFAULT_TIMEOUT =

Default per-call timeout.

SFML::Time.zero
STATUS_NAMES =

FTP status codes mapped to symbols. The transport-error ones at ≥ 1000 are SFML's, not RFC 959.

{
  110 => :restart_marker_reply, 120 => :service_ready_soon,
  125 => :data_connection_already_opened, 150 => :opening_data_connection,
  200 => :ok, 211 => :system_status, 212 => :directory_status,
  213 => :file_status, 214 => :help_message,
  215 => :system_type, 220 => :service_ready, 221 => :closing_connection,
  225 => :data_connection_opened, 226 => :closing_data_connection,
  227 => :entering_passive_mode, 230 => :logged_in,
  250 => :file_action_ok, 257 => :directory_ok,
  331 => :need_password, 332 => :need_account_to_log_in,
  350 => :need_information,
  421 => :service_unavailable, 425 => :data_connection_unavailable,
  426 => :transfer_aborted, 450 => :file_action_aborted,
  451 => :local_error, 452 => :insufficient_storage_space,
  500 => :command_unknown, 501 => :parameters_unknown,
  502 => :command_not_implemented, 503 => :bad_command_sequence,
  504 => :parameter_not_implemented, 530 => :not_logged_in,
  532 => :need_account_to_store, 550 => :file_unavailable,
  551 => :page_type_unknown, 552 => :not_enough_memory,
  553 => :filename_not_allowed,
  1000 => :invalid_response, 1001 => :connection_failed,
  1002 => :connection_closed, 1003 => :invalid_file,
}.freeze

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize ⇒ Ftp

Create a new FTP client. Call #connect next to open a session.

Raises:



52
53
54
55
56
57
# File 'lib/sfml/network/ftp.rb', line 52

def initialize
  ptr = C::Network.sfFtp_create
  raise NetworkError, "sfFtp_create returned NULL" if ptr.null?

  @handle = FFI::AutoPointer.new(ptr, C::Network.method(:sfFtp_destroy))
end

Instance Attribute Details

#handle ⇒ Object (readonly)

:nodoc:



144
145
146
# File 'lib/sfml/network/ftp.rb', line 144

def handle
  @handle
end

Instance Method Details

#change_directory(directory) ⇒ Object

cd to a directory.



94
95
96
# File 'lib/sfml/network/ftp.rb', line 94

def change_directory(directory)
  Response._take_ownership(C::Network.sfFtp_changeDirectory(@handle, directory.to_s))
end

#connect(host, port: DEFAULT_PORT, timeout: DEFAULT_TIMEOUT) ⇒ Object

Connect to an FTP server. host may be an IP string ("1.2.3.4") or hostname ("ftp.example.com"); pass timeout as a SFML::Time or numeric seconds (default 0 = no timeout).



62
63
64
65
66
# File 'lib/sfml/network/ftp.rb', line 62

def connect(host, port: DEFAULT_PORT, timeout: DEFAULT_TIMEOUT)
  addr = IpAddress.from_string(host).struct
  t    = timeout.is_a?(Time) ? timeout : Time.seconds(timeout.to_f)
  Response._take_ownership(C::Network.sfFtp_connect(@handle, addr, Integer(port), t.to_native))
end

#create_directory(name) ⇒ Object

mkdir — returns a DirectoryResponse with the new path.



104
105
106
# File 'lib/sfml/network/ftp.rb', line 104

def create_directory(name)
  DirectoryResponse._take_ownership(C::Network.sfFtp_createDirectory(@handle, name.to_s))
end

#delete_directory(name) ⇒ Object

rmdir.



109
110
111
# File 'lib/sfml/network/ftp.rb', line 109

def delete_directory(name)
  Response._take_ownership(C::Network.sfFtp_deleteDirectory(@handle, name.to_s))
end

#delete_file(name) ⇒ Object

Delete a single file.



119
120
121
# File 'lib/sfml/network/ftp.rb', line 119

def delete_file(name)
  Response._take_ownership(C::Network.sfFtp_deleteFile(@handle, name.to_s))
end

#directory_listing(directory = "") ⇒ Object

List directory (default = current). Returns a ListingResponse.



89
90
91
# File 'lib/sfml/network/ftp.rb', line 89

def directory_listing(directory = "")
  ListingResponse._take_ownership(C::Network.sfFtp_getDirectoryListing(@handle, directory.to_s))
end

#disconnect ⇒ Object

Close the connection.



79
80
# File 'lib/sfml/network/ftp.rb', line 79

def disconnect = Response._take_ownership(C::Network.sfFtp_disconnect(@handle))
# Send a no-op to keep the connection alive against server timeouts.

#download(remote, local, mode: :binary) ⇒ Object

Pull remote from the server to local path. mode is :binary (default), :ascii, or :ebcdic.



125
126
127
128
129
# File 'lib/sfml/network/ftp.rb', line 125

def download(remote, local, mode: :binary)
  idx = C::Network::FTP_TRANSFER_MODES.index(mode) ||
    raise(ArgumentError, "Unknown FTP transfer mode: #{mode.inspect}")
  Response._take_ownership(C::Network.sfFtp_download(@handle, remote.to_s, local.to_s, idx))
end

#keep_alive ⇒ Object

Send a no-op to keep the connection alive against server timeouts.



81
# File 'lib/sfml/network/ftp.rb', line 81

def keep_alive = Response._take_ownership(C::Network.sfFtp_keepAlive(@handle))

#login(user, password) ⇒ Object

Log in with credentials.



74
75
76
# File 'lib/sfml/network/ftp.rb', line 74

def (user, password)
  Response._take_ownership(C::Network.(@handle, user.to_s, password.to_s))
end

#login_anonymous ⇒ Object

Log in as anonymous. Returns a Response.



69
70
71
# File 'lib/sfml/network/ftp.rb', line 69

def 
  Response._take_ownership(C::Network.sfFtp_loginAnonymous(@handle))
end

#parent_directory ⇒ Object

cd ...



99
100
101
# File 'lib/sfml/network/ftp.rb', line 99

def parent_directory
  Response._take_ownership(C::Network.sfFtp_parentDirectory(@handle))
end

#rename_file(file, new_name) ⇒ Object

Rename / move a file on the server.



114
115
116
# File 'lib/sfml/network/ftp.rb', line 114

def rename_file(file, new_name)
  Response._take_ownership(C::Network.sfFtp_renameFile(@handle, file.to_s, new_name.to_s))
end

#send_command(command, parameter = "") ⇒ Object

Send a raw FTP command (e.g. "STAT") and an optional parameter.



140
141
142
# File 'lib/sfml/network/ftp.rb', line 140

def send_command(command, parameter = "")
  Response._take_ownership(C::Network.sfFtp_sendCommand(@handle, command.to_s, parameter.to_s))
end

#upload(local, remote, mode: :binary, append: false) ⇒ Object

Push local to remote. append: true extends an existing remote file rather than replacing it.



133
134
135
136
137
# File 'lib/sfml/network/ftp.rb', line 133

def upload(local, remote, mode: :binary, append: false)
  idx = C::Network::FTP_TRANSFER_MODES.index(mode) ||
    raise(ArgumentError, "Unknown FTP transfer mode: #{mode.inspect}")
  Response._take_ownership(C::Network.sfFtp_upload(@handle, local.to_s, remote.to_s, idx, !!append))
end

#working_directory ⇒ Object

Current working directory as a DirectoryResponse.



84
85
86
# File 'lib/sfml/network/ftp.rb', line 84

def working_directory
  DirectoryResponse._take_ownership(C::Network.sfFtp_getWorkingDirectory(@handle))
end