class Tus::Storage::Filesystem

Attributes

directory[R]

Public Class Methods

new(directory, permissions: 0644, directory_permissions: 0755) click to toggle source

Initializes the storage with a directory, in which it will save all files. Creates the directory if it doesn't exist.

# File lib/tus/storage/filesystem.rb, line 17
def initialize(directory, permissions: 0644, directory_permissions: 0755)
  @directory             = Pathname(directory)
  @permissions           = permissions
  @directory_permissions = directory_permissions

  create_directory! unless @directory.exist?
end

Public Instance Methods

concatenate(uid, part_uids, info = {}) click to toggle source

Concatenates multiple partial uploads into a single upload, and returns the size of the resulting upload. The partial uploads are deleted after concatenation.

Raises Tus::Error if any partial upload is missing.

# File lib/tus/storage/filesystem.rb, line 39
def concatenate(uid, part_uids, info = {})
  create_file(uid, info)

  file_path(uid).open("wb") do |file|
    part_uids.each do |part_uid|
      # Rather than checking upfront whether all parts exist, we use
      # exception flow to account for the possibility of parts being
      # deleted during concatenation.
      begin
        IO.copy_stream(file_path(part_uid), file)
      rescue Errno::ENOENT
        raise Tus::Error, "some parts for concatenation are missing"
      end
    end
  end

  # Delete parts after concatenation.
  delete(part_uids)
end
create_file(uid, info = {}) click to toggle source

Creates a file for storing uploaded data and a file for storing info.

# File lib/tus/storage/filesystem.rb, line 26
def create_file(uid, info = {})
  file_path(uid).binwrite("")
  file_path(uid).chmod(@permissions)

  info_path(uid).binwrite("{}") unless info_path(uid).exist?
  info_path(uid).chmod(@permissions)
end
delete_file(uid, info = {}) click to toggle source

Deletes data and info files for the specified upload.

# File lib/tus/storage/filesystem.rb, line 103
def delete_file(uid, info = {})
  delete([uid])
end
expire_files(expiration_date) click to toggle source

Deletes data and info files of uploads older than the specified date.

# File lib/tus/storage/filesystem.rb, line 108
def expire_files(expiration_date)
  uids = directory.children
    .select { |pathname| pathname.mtime <= expiration_date }
    .map { |pathname| pathname.basename(".*").to_s }

  delete(uids)
end
get_file(uid, info = {}, range: nil) click to toggle source

Returns a Tus::Response object through which data of the specified upload can be retrieved in a streaming fashion. Accepts an optional range parameter for selecting a subset of bytes to retrieve.

# File lib/tus/storage/filesystem.rb, line 81
def get_file(uid, info = {}, range: nil)
  file = file_path(uid).open("rb")
  length = range ? range.size : file.size

  # Create an Enumerator which will yield chunks of the requested file
  # content, allowing tus server to efficiently stream requested content
  # to the client.
  chunks = Enumerator.new do |yielder|
    file.seek(range.begin) if range
    remaining_length = length

    while remaining_length > 0
      chunk = file.read([16*1024, remaining_length].min) or break
      remaining_length -= chunk.bytesize
      yielder << chunk
    end
  end

  Response.new(chunks: chunks, close: file.method(:close), path: file_path(uid).to_s)
end
patch_file(uid, input, info = {}) click to toggle source

Appends data to the specified upload in a streaming fashion, and returns the number of bytes it managed to save.

# File lib/tus/storage/filesystem.rb, line 61
def patch_file(uid, input, info = {})
  file_path(uid).open("ab") { |file| IO.copy_stream(input, file) }
end
read_info(uid) click to toggle source

Returns info of the specified upload. Raises Tus::NotFound if the upload wasn't found.

# File lib/tus/storage/filesystem.rb, line 67
def read_info(uid)
  raise Tus::NotFound if !file_path(uid).exist?

  JSON.parse(info_path(uid).binread)
end
update_info(uid, info) click to toggle source

Updates info of the specified upload.

# File lib/tus/storage/filesystem.rb, line 74
def update_info(uid, info)
  info_path(uid).binwrite(JSON.generate(info))
end

Private Instance Methods

create_directory!() click to toggle source
# File lib/tus/storage/filesystem.rb, line 132
def create_directory!
  directory.mkpath
  directory.chmod(@directory_permissions)
end
delete(uids) click to toggle source
# File lib/tus/storage/filesystem.rb, line 118
def delete(uids)
  paths = uids.flat_map { |uid| [file_path(uid), info_path(uid)] }

  FileUtils.rm_f paths
end
file_path(uid) click to toggle source
# File lib/tus/storage/filesystem.rb, line 124
def file_path(uid)
  directory.join("#{uid}")
end
info_path(uid) click to toggle source
# File lib/tus/storage/filesystem.rb, line 128
def info_path(uid)
  directory.join("#{uid}.info")
end