Class: Wavesync::Libmtp

Inherits:
Object
  • Object
show all
Defined in:
lib/wavesync/libmtp.rb

Defined Under Namespace

Modules: FFIBindings Classes: DeviceFile, DeviceFolder, DeviceNotFound, Error

Constant Summary collapse

INSTALL_HINT =
'Install libmtp with `brew install libmtp`'
LIBRARY_PATHS =
[
  '/usr/local/opt/libmtp/lib/libmtp.dylib',
  '/opt/homebrew/opt/libmtp/lib/libmtp.dylib',
  'libmtp.dylib',
  'libmtp.so.9',
  'libmtp.so'
].freeze

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initializeLibmtp

: () -> void



134
135
136
137
# File 'lib/wavesync/libmtp.rb', line 134

def initialize
  @device_handle = nil #: FFI::Pointer?
  @raw_devices_pointer = nil #: FFI::Pointer?
end

Class Method Details

.init_library!Object

: () -> void



124
125
126
127
128
129
130
# File 'lib/wavesync/libmtp.rb', line 124

def init_library!
  return if @library_initialized

  FFIBindings.bind!
  FFIBindings.LIBMTP_Init
  @library_initialized = true
end

Instance Method Details

#close!Object

: () -> void



221
222
223
224
225
226
227
228
# File 'lib/wavesync/libmtp.rb', line 221

def close!
  device_handle = @device_handle
  raw_devices_pointer = @raw_devices_pointer
  FFIBindings.LIBMTP_Release_Device(device_handle) if device_handle
  FFIBindings.LIBMTP_FreeMemory(raw_devices_pointer) if raw_devices_pointer && !raw_devices_pointer.null?
  @device_handle = nil
  @raw_devices_pointer = nil
end

#create_folder(name:, parent_id:, storage_id:) ⇒ Object

: (name: String, parent_id: Integer, storage_id: Integer) -> Integer

Raises:



197
198
199
200
201
202
203
204
# File 'lib/wavesync/libmtp.rb', line 197

def create_folder(name:, parent_id:, storage_id:)
  ensure_open!
  name_pointer = FFI::MemoryPointer.from_string(name)
  new_id = FFIBindings.LIBMTP_Create_Folder(@device_handle, name_pointer, parent_id, storage_id)
  raise Error, "create_folder failed for #{name.inspect}" if new_id.zero?

  new_id
end

#delete_file(id:) ⇒ Object

: (id: Integer) -> void



207
208
209
210
211
# File 'lib/wavesync/libmtp.rb', line 207

def delete_file(id:)
  ensure_open!
  result = FFIBindings.LIBMTP_Delete_Object(@device_handle, id)
  raise_on_error!(result, "delete_file failed for id #{id}")
end

#detected?Boolean

: () -> bool

Returns:

  • (Boolean)


140
141
142
143
144
145
146
147
148
149
150
151
# File 'lib/wavesync/libmtp.rb', line 140

def detected?
  ensure_library_loaded!
  raw_devices_pointer_pointer = FFI::MemoryPointer.new(:pointer)
  count_pointer = FFI::MemoryPointer.new(:int)
  result = FFIBindings.LIBMTP_Detect_Raw_Devices(raw_devices_pointer_pointer, count_pointer)
  count = count_pointer.read_int
  raw_devices_address = raw_devices_pointer_pointer.read_pointer
  FFIBindings.LIBMTP_FreeMemory(raw_devices_address) unless raw_devices_address.null?
  result.zero? && count.positive?
rescue Error
  false
end

#filesObject

: () -> Array



154
155
156
157
158
159
160
# File 'lib/wavesync/libmtp.rb', line 154

def files
  ensure_open!
  list_head = FFIBindings.LIBMTP_Get_Filelisting_With_Callback(@device_handle, nil, nil)
  result = walk_files(list_head)
  FFIBindings.LIBMTP_destroy_file_t(list_head) unless list_head.null?
  result
end

#foldersObject

: () -> Array



163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
# File 'lib/wavesync/libmtp.rb', line 163

def folders
  ensure_open!
  mtp_device = FFIBindings::MtpDevice.new(@device_handle)
  result = [] #: Array[DeviceFolder]
  storage_node = mtp_device[:storage]
  until storage_node.null?
    storage = FFIBindings::DeviceStorage.new(storage_node)
    storage_id = storage[:id]
    folder_root = FFIBindings.LIBMTP_Get_Folder_List_For_Storage(@device_handle, storage_id)
    walk_folders(folder_root, storage_id, result) unless folder_root.null?
    FFIBindings.LIBMTP_destroy_folder_t(folder_root) unless folder_root.null?
    storage_node = storage[:next]
  end
  result
end

#get_file(id:, local_path:) ⇒ Object

: (id: Integer, local_path: String) -> void



214
215
216
217
218
# File 'lib/wavesync/libmtp.rb', line 214

def get_file(id:, local_path:)
  ensure_open!
  result = FFIBindings.LIBMTP_Get_File_To_File(@device_handle, id, local_path, nil, nil)
  raise_on_error!(result, "get_file failed for id #{id}")
end

#send_file(local_path:, remote_filename:, parent_id:, storage_id:) ⇒ Object

: (local_path: String, remote_filename: String, parent_id: Integer, storage_id: Integer) -> void



180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
# File 'lib/wavesync/libmtp.rb', line 180

def send_file(local_path:, remote_filename:, parent_id:, storage_id:)
  ensure_open!
  filesize = ::File.size(local_path)
  filename_pointer = FFI::MemoryPointer.from_string(remote_filename)
   = FFIBindings::File.new
  [:item_id] = 0
  [:parent_id] = parent_id
  [:storage_id] = storage_id
  [:filename] = filename_pointer
  [:filesize] = filesize
  [:modificationdate] = 0
  [:filetype] = filetype_for(remote_filename)
  result = FFIBindings.LIBMTP_Send_File_From_File(@device_handle, local_path, .to_ptr, nil, nil)
  raise_on_error!(result, "send_file failed for #{local_path}")
end