shrine-gridfs 0.3.1 → 0.3.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: b919da6ec801c8888bf1fbeb877cbdc8ad251d43
4
- data.tar.gz: a3cbea2effb35eaee531176df0bcd533749bae62
3
+ metadata.gz: 32f189d0c100716ffe7658f1bf04e84f6ed05415
4
+ data.tar.gz: 2ede8fa5db17c83fff263cd33e7d1434cad9da96
5
5
  SHA512:
6
- metadata.gz: cf9beeb12753001aaf4366ecc0507ea450accd740994b9d28d9c31f4e94dba1c02f71668ebeb946692e5b29ad76feedb38b72ad53443c687fc5c1d87d24f569a
7
- data.tar.gz: f668ac2435e9e46dc46b2e28eaa2fe37aa30cf80a716331901096f0175e71455e3b4773f6a74369c176a88c079ba3969f3e7c575bdde00bc8a617cf2989d7933
6
+ metadata.gz: e0cd1b8dfbfaaf44644777f45b087b49485dd19528c4a2b1eff61a0fb1e932b891f7e4be4150cc134deea9940045fb4784ed1ca08e13c3ebb437bf28b0378384
7
+ data.tar.gz: b8394324dea43b926e78ae961cfaecb949d98983c5afde5a0c0752c8074fd5b1ea3c70be7a6058c44f035cd3cef801af8a0e14aa003a750ab8af75bf17acbb20
data/README.md CHANGED
@@ -40,6 +40,15 @@ change that via `:chunk_size`:
40
40
  Shrine::Storage::Gridfs.new(client: client, chunk_size: 1*1024*1024) # 1MB
41
41
  ```
42
42
 
43
+ ### Batch size
44
+
45
+ When Gridfs storage uploads or copies a file, it will ensure that no more
46
+ than `:batch_size` of data is loaded into memory at once (defaults to 5MB).
47
+
48
+ ```rb
49
+ Shrine::Storage::Gridfs.new(client: client, batch_size: 10*1024*1024) # 10MB
50
+ ```
51
+
43
52
  ### URLs
44
53
 
45
54
  You can generate URLs through which the GridFS files will be streamed with the
@@ -8,53 +8,26 @@ class Shrine
8
8
  class Gridfs
9
9
  attr_reader :client, :prefix, :bucket, :chunk_size
10
10
 
11
- BATCH_SIZE = 5 * 1024 * 1024
12
-
13
- def initialize(client:, prefix: "fs", chunk_size: 256*1024, **options)
11
+ def initialize(client:, prefix: "fs", chunk_size: 256*1024, batch_size: 5 * 1024*1024, **options)
14
12
  @client = client
15
13
  @prefix = prefix
16
14
  @chunk_size = chunk_size
15
+ @batch_size = batch_size
17
16
  @bucket = @client.database.fs(bucket_name: @prefix)
18
17
 
19
18
  @bucket.send(:ensure_indexes!)
20
19
  end
21
20
 
22
21
  def upload(io, id, shrine_metadata: {}, **)
23
- file = create_file(id, shrine_metadata: shrine_metadata)
24
-
25
- until io.eof?
26
- chunk = io.read([BATCH_SIZE, chunk_size].max, buffer ||= "")
27
- grid_chunks = Mongo::Grid::File::Chunk.split(chunk, file.info, offset ||= 0)
28
-
29
- chunks_collection.insert_many(grid_chunks)
30
-
31
- offset += grid_chunks.count
32
- grid_chunks.each { |grid_chunk| grid_chunk.data.data.clear } # deallocate strings
33
- chunk.clear # deallocate string
22
+ if copyable?(io, id)
23
+ copy(io, id, shrine_metadata: shrine_metadata)
24
+ else
25
+ create(io, id, shrine_metadata: shrine_metadata)
34
26
  end
35
-
36
- files_collection.find(_id: file.id).update_one(
37
- "$set" => {
38
- length: io.size,
39
- uploadDate: Time.now.utc,
40
- md5: file.info.md5.hexdigest,
41
- }
42
- )
43
- end
44
-
45
- def move(io, id, shrine_metadata: {}, **)
46
- file = create_file(id, shrine_metadata: shrine_metadata)
47
-
48
- chunks_collection.find(files_id: bson_id(io.id)).update_many("$set" => {files_id: file.id})
49
- files_collection.delete_one(_id: bson_id(io.id))
50
- end
51
-
52
- def movable?(io, id)
53
- io.is_a?(UploadedFile) && io.storage.is_a?(Storage::Gridfs)
54
27
  end
55
28
 
56
29
  def open(id)
57
- content_length = bucket.find(_id: bson_id(id)).limit(1).first[:length]
30
+ content_length = file_info(id)[:length]
58
31
  stream = bucket.open_download_stream(bson_id(id))
59
32
 
60
33
  Down::ChunkedIO.new(
@@ -65,7 +38,7 @@ class Shrine
65
38
  end
66
39
 
67
40
  def exists?(id)
68
- !!bucket.find(_id: bson_id(id)).first
41
+ !!file_info(id)
69
42
  end
70
43
 
71
44
  def delete(id)
@@ -87,29 +60,90 @@ class Shrine
87
60
  chunks_collection.find.delete_many
88
61
  end
89
62
 
63
+ protected
64
+
65
+ def file_info(id)
66
+ bucket.find(_id: bson_id(id)).limit(1).first
67
+ end
68
+
69
+ def files_collection
70
+ bucket.files_collection
71
+ end
72
+
73
+ def chunks_collection
74
+ bucket.chunks_collection
75
+ end
76
+
90
77
  private
91
78
 
79
+ def create(io, id, shrine_metadata: {})
80
+ file = create_file(id, shrine_metadata: shrine_metadata)
81
+
82
+ until io.eof?
83
+ chunk = io.read([@batch_size, chunk_size].max, buffer ||= "")
84
+ grid_chunks = Mongo::Grid::File::Chunk.split(chunk, file.info, offset ||= 0)
85
+
86
+ chunks_collection.insert_many(grid_chunks)
87
+
88
+ offset += grid_chunks.count
89
+ grid_chunks.each { |grid_chunk| grid_chunk.data.data.clear } # deallocate strings
90
+ chunk.clear # deallocate string
91
+ end
92
+
93
+ files_collection.find(_id: file.id).update_one("$set" => {
94
+ length: io.size,
95
+ uploadDate: Time.now.utc,
96
+ md5: file.info.md5.hexdigest,
97
+ })
98
+ end
99
+
100
+ def copy(io, id, shrine_metadata: {})
101
+ source_storage = io.storage
102
+ source_info = source_storage.file_info(io.id)
103
+ dest_info = source_info.merge(_id: BSON::ObjectId.new)
104
+
105
+ batch_size = (@batch_size.to_f / chunk_size).ceil
106
+ chunk_batches = source_storage.chunks_collection
107
+ .find(files_id: source_info[:_id])
108
+ .batch_size(batch_size).each_slice(batch_size)
109
+
110
+ chunk_batches.each do |chunks|
111
+ chunks.each do |chunk|
112
+ chunk[:_id] = BSON::ObjectId.new
113
+ chunk[:files_id] = dest_info[:_id]
114
+ end
115
+
116
+ chunks_collection.insert_many(chunks)
117
+
118
+ chunks.each do |chunk|
119
+ chunk[:data].data.clear # deallocate strings
120
+ end
121
+ end
122
+
123
+ dest_info[:uploadDate] = Time.now.utc
124
+ dest_info[:filename] = shrine_metadata["filename"] || id
125
+ files_collection.insert_one(dest_info)
126
+ id.replace(dest_info[:_id].to_s + File.extname(id))
127
+ end
128
+
129
+ def copyable?(io, id)
130
+ io.is_a?(UploadedFile) && io.storage.is_a?(Storage::Gridfs)
131
+ end
132
+
92
133
  def create_file(id, shrine_metadata: {})
93
134
  file = Mongo::Grid::File.new("",
94
135
  filename: shrine_metadata["filename"] || id,
95
- content_type: shrine_metadata["mime_type"],
136
+ content_type: shrine_metadata["mime_type"] || "application/octet-stream",
96
137
  metadata: shrine_metadata,
97
138
  chunk_size: chunk_size,
98
139
  )
99
- id.replace(file.id.to_s + File.extname(id))
100
140
 
101
141
  bucket.insert_one(file)
102
142
 
143
+ id.replace(file.id.to_s + File.extname(id))
103
144
  file.info.document[:md5] = Digest::MD5.new
104
- file
105
- end
106
-
107
- def files_collection
108
- bucket.files_collection
109
- end
110
145
 
111
- def chunks_collection
112
- bucket.chunks_collection
146
+ file
113
147
  end
114
148
 
115
149
  def bson_id(id)
@@ -1,6 +1,6 @@
1
1
  Gem::Specification.new do |gem|
2
2
  gem.name = "shrine-gridfs"
3
- gem.version = "0.3.1"
3
+ gem.version = "0.3.2"
4
4
 
5
5
  gem.required_ruby_version = ">= 2.1"
6
6
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: shrine-gridfs
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.1
4
+ version: 0.3.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Janko Marohnić