Class: Tus::Storage::Filesystem

Inherits:
Object
  • Object
show all
Defined in:
lib/tus/storage/filesystem.rb

Defined Under Namespace

Classes: Response

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(directory, permissions: 0644, directory_permissions: 0755) ⇒ Filesystem

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



17
18
19
20
21
22
23
# 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

Instance Attribute Details

#directoryObject (readonly)

Returns the value of attribute directory.



13
14
15
# File 'lib/tus/storage/filesystem.rb', line 13

def directory
  @directory
end

Instance Method Details

#concatenate(uid, part_uids, info = {}) ⇒ Object

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.



39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
# 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 = {}) ⇒ Object

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



26
27
28
29
30
31
32
# 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 = {}) ⇒ Object

Deletes data and info files for the specified upload.



103
104
105
# File 'lib/tus/storage/filesystem.rb', line 103

def delete_file(uid, info = {})
  delete([uid])
end

#expire_files(expiration_date) ⇒ Object

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



108
109
110
111
112
113
114
# 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) ⇒ Object

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.



81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
# 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 = {}) ⇒ Object

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



61
62
63
# 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) ⇒ Object

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

Raises:



67
68
69
70
71
# 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) ⇒ Object

Updates info of the specified upload.



74
75
76
# File 'lib/tus/storage/filesystem.rb', line 74

def update_info(uid, info)
  info_path(uid).binwrite(JSON.generate(info))
end