kithe 2.0.0.pre.alpha2 → 2.0.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 +4 -4
- data/README.md +4 -4
- data/app/indexing/kithe/indexable/record_index_updater.rb +1 -1
- data/app/jobs/kithe/create_derivatives_job.rb +2 -2
- data/app/models/kithe/asset.rb +82 -154
- data/app/models/kithe/asset/derivative_creator.rb +32 -62
- data/app/models/kithe/asset/derivative_definition.rb +12 -13
- data/app/models/kithe/asset/set_shrine_uploader.rb +64 -0
- data/app/models/kithe/collection.rb +0 -6
- data/app/models/kithe/model.rb +0 -21
- data/app/models/kithe/work.rb +0 -5
- data/app/uploaders/kithe/asset_uploader.rb +15 -78
- data/lib/kithe.rb +22 -20
- data/{app/models → lib}/kithe/config_base.rb +6 -1
- data/lib/kithe/engine.rb +14 -3
- data/lib/kithe/indexable_settings.rb +1 -1
- data/lib/kithe/patch_fx.rb +39 -0
- data/lib/kithe/version.rb +4 -1
- data/lib/shrine/plugins/kithe_checksum_signatures.rb +41 -0
- data/lib/shrine/plugins/kithe_controllable_backgrounding.rb +53 -0
- data/lib/shrine/plugins/kithe_derivative_definitions.rb +101 -0
- data/lib/shrine/plugins/kithe_derivatives.rb +54 -0
- data/lib/shrine/plugins/kithe_determine_mime_type.rb +39 -0
- data/lib/shrine/plugins/kithe_persisted_derivatives.rb +161 -0
- data/lib/shrine/plugins/kithe_promotion_callbacks.rb +4 -0
- data/lib/shrine/plugins/kithe_promotion_directives.rb +33 -3
- data/lib/shrine/plugins/kithe_storage_location.rb +53 -4
- data/lib/tasks/kithe_tasks.rake +22 -15
- data/spec/dummy/app/models/plain_active_record.rb +3 -0
- data/spec/dummy/config/database.yml +6 -0
- data/spec/dummy/db/schema.rb +102 -0
- data/spec/dummy/log/development.log +3616 -0
- data/spec/dummy/log/test.log +86464 -0
- data/spec/dummy/tmp/development_secret.txt +1 -1
- data/spec/indexing/indexable_spec.rb +1 -1
- data/spec/models/kithe/asset/asset_derivatives_spec.rb +137 -0
- data/spec/models/kithe/asset/asset_promotion_hooks_spec.rb +26 -5
- data/spec/models/kithe/asset/set_shrine_uploader_spec.rb +39 -0
- data/spec/models/kithe/asset_spec.rb +9 -59
- data/spec/models/kithe/model_spec.rb +0 -32
- data/spec/models/kithe_spec.rb +10 -0
- data/spec/shrine/kithe_accept_remote_url_spec.rb +49 -0
- data/spec/shrine/kithe_checksum_signatures_spec.rb +63 -0
- data/spec/shrine/kithe_derivative_definitions_spec.rb +303 -0
- data/spec/shrine/kithe_persisted_derivatives_spec.rb +424 -0
- data/spec/shrine/kithe_storage_location_spec.rb +43 -15
- data/spec/spec_helper.rb +0 -19
- data/spec/test_support/images/3x3_pixel.jpg +0 -0
- data/spec/test_support/shrine_spec_support.rb +2 -1
- metadata +60 -36
- data/app/models/kithe/asset/derivative_updater.rb +0 -119
- data/app/models/kithe/derivative.rb +0 -15
- data/app/uploaders/kithe/derivative_uploader.rb +0 -48
- data/spec/dummy/db/structure.sql +0 -309
- data/spec/models/kithe/asset/asset_create_derivatives_spec.rb +0 -320
- data/spec/models/kithe/derivative_spec.rb +0 -168
@@ -4,29 +4,57 @@ require 'shrine/plugins/kithe_storage_location'
|
|
4
4
|
describe Shrine::Plugins::KitheStorageLocation do
|
5
5
|
let(:uploader) { test_uploader { plugin :kithe_storage_location } }
|
6
6
|
|
7
|
-
|
8
|
-
|
7
|
+
describe "for main file" do
|
8
|
+
it "uploads with a record with id" do
|
9
|
+
uploaded_file = uploader.upload(fakeio, record: OpenStruct.new(id: "81060886-4f93-42e7-ace7-ab51399f4808"), name: :file)
|
9
10
|
|
10
|
-
|
11
|
-
|
11
|
+
expect(uploaded_file.id).to match %r{\Aasset/81060886-4f93-42e7-ace7-ab51399f4808/[0-9a-f]+}
|
12
|
+
end
|
12
13
|
|
13
|
-
|
14
|
-
|
14
|
+
it "has suffix with a record id and filename" do
|
15
|
+
uploaded_file = uploader.upload(fakeio(filename: "foo.jpg"), record: OpenStruct.new(id: "81060886-4f93-42e7-ace7-ab51399f4808"), name: :file)
|
15
16
|
|
16
|
-
|
17
|
-
|
17
|
+
expect(uploaded_file.id).to match %r{\Aasset/81060886-4f93-42e7-ace7-ab51399f4808/[0-9a-f]+\.jpg}
|
18
|
+
end
|
18
19
|
|
19
|
-
|
20
|
-
|
20
|
+
it "uploads with no record" do
|
21
|
+
uploaded_file = uploader.upload(fakeio, record: OpenStruct.new(id: "81060886-4f93-42e7-ace7-ab51399f4808"), name: :file)
|
21
22
|
|
22
|
-
|
23
|
-
|
23
|
+
expect(uploaded_file.id).to match %r{\Aasset/[0-9a-f]+}
|
24
|
+
end
|
24
25
|
|
25
|
-
|
26
|
-
|
26
|
+
it "uploads with record with no id" do
|
27
|
+
uploaded_file = uploader.upload(fakeio, record: OpenStruct.new(), name: :file)
|
27
28
|
|
28
|
-
|
29
|
+
expect(uploaded_file.id).to match %r{\Aasset/[0-9a-f]+}
|
30
|
+
end
|
29
31
|
end
|
30
32
|
|
33
|
+
describe "for shrine derivatives" do
|
34
|
+
let(:image_path) { Kithe::Engine.root.join("spec/test_support/images/1x1_pixel.jpg") }
|
35
|
+
|
36
|
+
let(:uploader) do
|
37
|
+
test_uploader do
|
38
|
+
plugin :kithe_storage_location
|
39
|
+
end
|
40
|
+
end
|
31
41
|
|
42
|
+
it "uses good path for derivative" do
|
43
|
+
uploaded_file = uploader.upload(fakeio("foo.jpg"), derivative: :fixed, record: OpenStruct.new(id: "81060886-4f93-42e7-ace7-ab51399f4808"), name: :file)
|
44
|
+
|
45
|
+
expect(uploaded_file.id).to match %r{\A81060886-4f93-42e7-ace7-ab51399f4808/fixed/[0-9a-f]+}
|
46
|
+
end
|
47
|
+
|
48
|
+
it "raises with no record" do
|
49
|
+
expect {
|
50
|
+
uploader.upload(fakeio("foo.jpg"), record: nil, derivative: :fixed, name: :file)
|
51
|
+
}.to raise_error(TypeError)
|
52
|
+
end
|
53
|
+
|
54
|
+
it "raises with record with no id" do
|
55
|
+
expect {
|
56
|
+
uploader.upload(fakeio("foo.jpg"), record: OpenStruct.new, derivative: :fixed, name: :file)
|
57
|
+
}.to raise_error(TypeError)
|
58
|
+
end
|
59
|
+
end
|
32
60
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -123,22 +123,3 @@ RSpec.configure do |config|
|
|
123
123
|
=end
|
124
124
|
end
|
125
125
|
|
126
|
-
# Workaround ruby 2.7.0 StringIO enccoding weirdness, which hopefully
|
127
|
-
# will be fixed in shrine 3.x before we get there. if you can remove this patch
|
128
|
-
# and tests still pass, you're good.
|
129
|
-
#
|
130
|
-
# https://github.com/shrinerb/shrine/pull/443
|
131
|
-
#
|
132
|
-
require 'sane_patch'
|
133
|
-
SanePatch.patch("shrine", "< 3.2.2") do
|
134
|
-
require 'shrine/storage/memory'
|
135
|
-
class Shrine::Storage::Memory
|
136
|
-
def open(id, *)
|
137
|
-
str = store.fetch(id)
|
138
|
-
StringIO.new(str).set_encoding(str.encoding, str.encoding)
|
139
|
-
end
|
140
|
-
end
|
141
|
-
end
|
142
|
-
|
143
|
-
|
144
|
-
|
Binary file
|
@@ -59,8 +59,9 @@ require "stringio"
|
|
59
59
|
class FakeIO
|
60
60
|
attr_reader :original_filename, :content_type
|
61
61
|
|
62
|
-
def initialize(content, filename: nil, content_type: nil)
|
62
|
+
def initialize(content, filename: nil, content_type: nil, encoding: "BINARY")
|
63
63
|
@io = StringIO.new(content)
|
64
|
+
@io.set_encoding(encoding, encoding) # weird ruby workaround
|
64
65
|
@original_filename = filename
|
65
66
|
@content_type = content_type
|
66
67
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: kithe
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.0.
|
4
|
+
version: 2.0.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jonathan Rochkind
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2021-01-11 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|
@@ -19,7 +19,7 @@ dependencies:
|
|
19
19
|
version: 5.2.1
|
20
20
|
- - "<"
|
21
21
|
- !ruby/object:Gem::Version
|
22
|
-
version: '6.
|
22
|
+
version: '6.2'
|
23
23
|
type: :runtime
|
24
24
|
prerelease: false
|
25
25
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -29,7 +29,7 @@ dependencies:
|
|
29
29
|
version: 5.2.1
|
30
30
|
- - "<"
|
31
31
|
- !ruby/object:Gem::Version
|
32
|
-
version: '6.
|
32
|
+
version: '6.2'
|
33
33
|
- !ruby/object:Gem::Dependency
|
34
34
|
name: attr_json
|
35
35
|
requirement: !ruby/object:Gem::Requirement
|
@@ -182,6 +182,26 @@ dependencies:
|
|
182
182
|
- - ">="
|
183
183
|
- !ruby/object:Gem::Version
|
184
184
|
version: '0'
|
185
|
+
- !ruby/object:Gem::Dependency
|
186
|
+
name: fx
|
187
|
+
requirement: !ruby/object:Gem::Requirement
|
188
|
+
requirements:
|
189
|
+
- - ">="
|
190
|
+
- !ruby/object:Gem::Version
|
191
|
+
version: 0.5.0
|
192
|
+
- - "<"
|
193
|
+
- !ruby/object:Gem::Version
|
194
|
+
version: '1'
|
195
|
+
type: :runtime
|
196
|
+
prerelease: false
|
197
|
+
version_requirements: !ruby/object:Gem::Requirement
|
198
|
+
requirements:
|
199
|
+
- - ">="
|
200
|
+
- !ruby/object:Gem::Version
|
201
|
+
version: 0.5.0
|
202
|
+
- - "<"
|
203
|
+
- !ruby/object:Gem::Version
|
204
|
+
version: '1'
|
185
205
|
- !ruby/object:Gem::Dependency
|
186
206
|
name: traject
|
187
207
|
requirement: !ruby/object:Gem::Requirement
|
@@ -272,20 +292,6 @@ dependencies:
|
|
272
292
|
- - ">="
|
273
293
|
- !ruby/object:Gem::Version
|
274
294
|
version: '0'
|
275
|
-
- !ruby/object:Gem::Dependency
|
276
|
-
name: shrine-memory
|
277
|
-
requirement: !ruby/object:Gem::Requirement
|
278
|
-
requirements:
|
279
|
-
- - ">="
|
280
|
-
- !ruby/object:Gem::Version
|
281
|
-
version: '0'
|
282
|
-
type: :development
|
283
|
-
prerelease: false
|
284
|
-
version_requirements: !ruby/object:Gem::Requirement
|
285
|
-
requirements:
|
286
|
-
- - ">="
|
287
|
-
- !ruby/object:Gem::Version
|
288
|
-
version: '0'
|
289
295
|
- !ruby/object:Gem::Dependency
|
290
296
|
name: webmock
|
291
297
|
requirement: !ruby/object:Gem::Requirement
|
@@ -314,7 +320,7 @@ dependencies:
|
|
314
320
|
- - "<"
|
315
321
|
- !ruby/object:Gem::Version
|
316
322
|
version: '2'
|
317
|
-
description:
|
323
|
+
description:
|
318
324
|
email:
|
319
325
|
- jrochkind@sciencehistory.org
|
320
326
|
executables: []
|
@@ -341,10 +347,8 @@ files:
|
|
341
347
|
- app/models/kithe/asset.rb
|
342
348
|
- app/models/kithe/asset/derivative_creator.rb
|
343
349
|
- app/models/kithe/asset/derivative_definition.rb
|
344
|
-
- app/models/kithe/asset/
|
350
|
+
- app/models/kithe/asset/set_shrine_uploader.rb
|
345
351
|
- app/models/kithe/collection.rb
|
346
|
-
- app/models/kithe/config_base.rb
|
347
|
-
- app/models/kithe/derivative.rb
|
348
352
|
- app/models/kithe/mediainfo_analyzer.rb
|
349
353
|
- app/models/kithe/model.rb
|
350
354
|
- app/models/kithe/model_contains.rb
|
@@ -355,7 +359,6 @@ files:
|
|
355
359
|
- app/simple_form_enhancements/kithe/form_builder.rb
|
356
360
|
- app/simple_form_enhancements/kithe/repeatable_input_generator.rb
|
357
361
|
- app/uploaders/kithe/asset_uploader.rb
|
358
|
-
- app/uploaders/kithe/derivative_uploader.rb
|
359
362
|
- app/validators/array_inclusion_validator.rb
|
360
363
|
- config/locales/en.yml
|
361
364
|
- config/routes.rb
|
@@ -370,12 +373,20 @@ files:
|
|
370
373
|
- lib/kithe.rb
|
371
374
|
- lib/kithe/blacklight_tools/bulk_loading_search_service.rb
|
372
375
|
- lib/kithe/blacklight_tools/search_service_bulk_load.rb
|
376
|
+
- lib/kithe/config_base.rb
|
373
377
|
- lib/kithe/engine.rb
|
374
378
|
- lib/kithe/indexable_settings.rb
|
379
|
+
- lib/kithe/patch_fx.rb
|
375
380
|
- lib/kithe/sti_preload.rb
|
376
381
|
- lib/kithe/version.rb
|
377
382
|
- lib/shrine/plugins/kithe_accept_remote_url.rb
|
383
|
+
- lib/shrine/plugins/kithe_checksum_signatures.rb
|
384
|
+
- lib/shrine/plugins/kithe_controllable_backgrounding.rb
|
385
|
+
- lib/shrine/plugins/kithe_derivative_definitions.rb
|
386
|
+
- lib/shrine/plugins/kithe_derivatives.rb
|
387
|
+
- lib/shrine/plugins/kithe_determine_mime_type.rb
|
378
388
|
- lib/shrine/plugins/kithe_multi_cache.rb
|
389
|
+
- lib/shrine/plugins/kithe_persisted_derivatives.rb
|
379
390
|
- lib/shrine/plugins/kithe_promotion_callbacks.rb
|
380
391
|
- lib/shrine/plugins/kithe_promotion_directives.rb
|
381
392
|
- lib/shrine/plugins/kithe_storage_location.rb
|
@@ -395,6 +406,7 @@ files:
|
|
395
406
|
- spec/dummy/app/jobs/application_job.rb
|
396
407
|
- spec/dummy/app/mailers/application_mailer.rb
|
397
408
|
- spec/dummy/app/models/application_record.rb
|
409
|
+
- spec/dummy/app/models/plain_active_record.rb
|
398
410
|
- spec/dummy/app/views/layouts/application.html.erb
|
399
411
|
- spec/dummy/app/views/layouts/mailer.html.erb
|
400
412
|
- spec/dummy/app/views/layouts/mailer.text.erb
|
@@ -431,7 +443,7 @@ files:
|
|
431
443
|
- spec/dummy/config/routes.rb
|
432
444
|
- spec/dummy/config/spring.rb
|
433
445
|
- spec/dummy/config/storage.yml
|
434
|
-
- spec/dummy/db/
|
446
|
+
- spec/dummy/db/schema.rb
|
435
447
|
- spec/dummy/log/development.log
|
436
448
|
- spec/dummy/log/test.log
|
437
449
|
- spec/dummy/package.json
|
@@ -448,19 +460,24 @@ files:
|
|
448
460
|
- spec/indexing/indexable_spec.rb
|
449
461
|
- spec/indexing/indexer_spec.rb
|
450
462
|
- spec/indexing/obj_extract_spec.rb
|
451
|
-
- spec/models/kithe/asset/
|
463
|
+
- spec/models/kithe/asset/asset_derivatives_spec.rb
|
452
464
|
- spec/models/kithe/asset/asset_promotion_hooks_spec.rb
|
465
|
+
- spec/models/kithe/asset/set_shrine_uploader_spec.rb
|
453
466
|
- spec/models/kithe/asset_spec.rb
|
454
467
|
- spec/models/kithe/collection_spec.rb
|
455
468
|
- spec/models/kithe/config_spec.rb
|
456
|
-
- spec/models/kithe/derivative_spec.rb
|
457
469
|
- spec/models/kithe/mediainfo_analyzer_spec.rb
|
458
470
|
- spec/models/kithe/model_spec.rb
|
459
471
|
- spec/models/kithe/parameters_spec.rb
|
460
472
|
- spec/models/kithe/representatives_spec.rb
|
461
473
|
- spec/models/kithe/work_spec.rb
|
474
|
+
- spec/models/kithe_spec.rb
|
462
475
|
- spec/rails_helper.rb
|
476
|
+
- spec/shrine/kithe_accept_remote_url_spec.rb
|
477
|
+
- spec/shrine/kithe_checksum_signatures_spec.rb
|
478
|
+
- spec/shrine/kithe_derivative_definitions_spec.rb
|
463
479
|
- spec/shrine/kithe_multi_cache_spec.rb
|
480
|
+
- spec/shrine/kithe_persisted_derivatives_spec.rb
|
464
481
|
- spec/shrine/kithe_storage_location_spec.rb
|
465
482
|
- spec/simple_form_enhancements/repeatable_input_generator_spec.rb
|
466
483
|
- spec/spec_helper.rb
|
@@ -468,6 +485,7 @@ files:
|
|
468
485
|
- spec/test_support/audio/ice_cubes.mp3
|
469
486
|
- spec/test_support/images/1x1_pixel.jpg
|
470
487
|
- spec/test_support/images/2x2_pixel.jpg
|
488
|
+
- spec/test_support/images/3x3_pixel.jpg
|
471
489
|
- spec/test_support/images/photo_800x586.jpg
|
472
490
|
- spec/test_support/shrine_spec_support.rb
|
473
491
|
- spec/test_support/temporary_class_for_specs.rb
|
@@ -476,7 +494,7 @@ homepage: https://github.com/sciencehistory/kithe
|
|
476
494
|
licenses:
|
477
495
|
- MIT
|
478
496
|
metadata: {}
|
479
|
-
post_install_message:
|
497
|
+
post_install_message:
|
480
498
|
rdoc_options: []
|
481
499
|
require_paths:
|
482
500
|
- lib
|
@@ -487,18 +505,18 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
487
505
|
version: '2.5'
|
488
506
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
489
507
|
requirements:
|
490
|
-
- - "
|
508
|
+
- - ">="
|
491
509
|
- !ruby/object:Gem::Version
|
492
|
-
version:
|
510
|
+
version: '0'
|
493
511
|
requirements: []
|
494
|
-
|
495
|
-
|
496
|
-
signing_key:
|
512
|
+
rubygems_version: 3.0.3
|
513
|
+
signing_key:
|
497
514
|
specification_version: 4
|
498
515
|
summary: Shareable tools/components for building a digital collections app in Rails.
|
499
516
|
test_files:
|
500
517
|
- spec/spec_helper.rb
|
501
518
|
- spec/dummy/app/mailers/application_mailer.rb
|
519
|
+
- spec/dummy/app/models/plain_active_record.rb
|
502
520
|
- spec/dummy/app/models/application_record.rb
|
503
521
|
- spec/dummy/app/jobs/application_job.rb
|
504
522
|
- spec/dummy/app/controllers/application_controller.rb
|
@@ -553,7 +571,7 @@ test_files:
|
|
553
571
|
- spec/dummy/public/404.html
|
554
572
|
- spec/dummy/public/apple-touch-icon-precomposed.png
|
555
573
|
- spec/dummy/package.json
|
556
|
-
- spec/dummy/db/
|
574
|
+
- spec/dummy/db/schema.rb
|
557
575
|
- spec/dummy/log/test.log
|
558
576
|
- spec/dummy/log/development.log
|
559
577
|
- spec/dummy/tmp/development_secret.txt
|
@@ -561,23 +579,29 @@ test_files:
|
|
561
579
|
- spec/derivative_transformers/ffmpeg_transformer_spec.rb
|
562
580
|
- spec/models/kithe/collection_spec.rb
|
563
581
|
- spec/models/kithe/config_spec.rb
|
582
|
+
- spec/models/kithe/asset/asset_derivatives_spec.rb
|
564
583
|
- spec/models/kithe/asset/asset_promotion_hooks_spec.rb
|
565
|
-
- spec/models/kithe/asset/
|
584
|
+
- spec/models/kithe/asset/set_shrine_uploader_spec.rb
|
566
585
|
- spec/models/kithe/representatives_spec.rb
|
567
586
|
- spec/models/kithe/work_spec.rb
|
568
587
|
- spec/models/kithe/mediainfo_analyzer_spec.rb
|
569
588
|
- spec/models/kithe/parameters_spec.rb
|
570
|
-
- spec/models/kithe/derivative_spec.rb
|
571
589
|
- spec/models/kithe/asset_spec.rb
|
572
590
|
- spec/models/kithe/model_spec.rb
|
591
|
+
- spec/models/kithe_spec.rb
|
573
592
|
- spec/shrine/kithe_multi_cache_spec.rb
|
574
593
|
- spec/shrine/kithe_storage_location_spec.rb
|
594
|
+
- spec/shrine/kithe_persisted_derivatives_spec.rb
|
595
|
+
- spec/shrine/kithe_derivative_definitions_spec.rb
|
596
|
+
- spec/shrine/kithe_accept_remote_url_spec.rb
|
597
|
+
- spec/shrine/kithe_checksum_signatures_spec.rb
|
575
598
|
- spec/factories/kithe_works.rb
|
576
599
|
- spec/factories/kithe_collections.rb
|
577
600
|
- spec/factories/kithe_assets.rb
|
578
601
|
- spec/test_support/temporary_class_for_specs.rb
|
579
602
|
- spec/test_support/shrine_spec_support.rb
|
580
603
|
- spec/test_support/images/2x2_pixel.jpg
|
604
|
+
- spec/test_support/images/3x3_pixel.jpg
|
581
605
|
- spec/test_support/images/1x1_pixel.jpg
|
582
606
|
- spec/test_support/images/photo_800x586.jpg
|
583
607
|
- spec/test_support/audio/README.md
|
@@ -1,119 +0,0 @@
|
|
1
|
-
# A service object to add an IO stream as a derivative with a certain key, to a asset.
|
2
|
-
# Adds a Derivative database object for such. This class is normally only used from
|
3
|
-
# Asset#update_derivative, it's a helper object, you aren't expected to use it independently.
|
4
|
-
#
|
5
|
-
# This would be very straightforward if it weren't for taking account of a couple concurrency race
|
6
|
-
# conditions involving data integrity:
|
7
|
-
#
|
8
|
-
# 1. There should be only one derivative for a given asset/key pair. This is enforced by
|
9
|
-
# a DB constraint. If the record already exists, we want to update the current record,
|
10
|
-
# otherwise add a new one. We want to do this in a race-condition safe way, with possibly
|
11
|
-
# multiple processes editing db.
|
12
|
-
#
|
13
|
-
# 2. The DB should at no point in time contain a derivative generated for an _old_ version
|
14
|
-
# of the asset. If an asset#file is changed, it's existing derivatives need to be deleted,
|
15
|
-
# and this needs to happen in a race-condition safe way when something may be trying to
|
16
|
-
# add a derivative concurrently.
|
17
|
-
#
|
18
|
-
# I believe we have solved those challenges, but it leads to a bit tricky code. We use
|
19
|
-
# a kind of "optimistic" approach to (1) (try to insert, if you get a uniqueness violation
|
20
|
-
# try to find and use the record that's already there). And a "pessimistic" approach to (2),
|
21
|
-
# where we actually briefly take out a DB pessimistic lock to make sure the asset#file hasn't
|
22
|
-
# changed, and can't until we're done updating. (using sha512 as a marker, which is why you
|
23
|
-
# can't add an asset until it has a sha512 in it's metadata, usually post-promotion).
|
24
|
-
#
|
25
|
-
# If we made a given Asset objects's file bytestream immutable, this would all be a lot simpler;
|
26
|
-
# we wouldn't need to worry about (2) at all, and maybe not even (1). We might consider that, but
|
27
|
-
# for now we're tackling the hard way.
|
28
|
-
#
|
29
|
-
class Kithe::Asset::DerivativeUpdater
|
30
|
-
attr_reader :asset, :key, :io, :storage_key, :metadata, :max_optimistic_tries
|
31
|
-
|
32
|
-
def initialize(asset, key, io, storage_key: :kithe_derivatives, metadata: {})
|
33
|
-
@asset = asset
|
34
|
-
@key = key
|
35
|
-
@io = io
|
36
|
-
@storage_key = storage_key
|
37
|
-
@metadata = metadata
|
38
|
-
|
39
|
-
@max_optimistic_tries = 3
|
40
|
-
|
41
|
-
unless asset_has_persisted_sha512?
|
42
|
-
raise ArgumentError.new("Can not safely add derivative to an asset without a persisted sha512 value")
|
43
|
-
end
|
44
|
-
end
|
45
|
-
|
46
|
-
def update
|
47
|
-
deriv = Kithe::Derivative.new(key: key.to_s, asset: asset)
|
48
|
-
|
49
|
-
# skip cache phase, right to specified storage, but with metadata extraction.
|
50
|
-
uploader = deriv.file_attacher.shrine_class.new(storage_key)
|
51
|
-
|
52
|
-
# add our derivative key to context when uploading, so Kithe::DerivativeUploader can
|
53
|
-
# use it if needed.
|
54
|
-
uploaded_file = uploader.upload(io, record: deriv, metadata: metadata, kithe_derivative_key: key)
|
55
|
-
optimistically_save_derivative(uploaded_file: uploaded_file, derivative: deriv)
|
56
|
-
end
|
57
|
-
|
58
|
-
# Attaches UploadedFile to Derivative and tries to save it -- if we get a
|
59
|
-
# unique constraint violation because a Derivative for that asset/key already existed,
|
60
|
-
# we fetch that alredy existing one from the db and update it's actual bytestream.
|
61
|
-
#
|
62
|
-
# This method calls itself recursively to do that. Gives up after max_optimistic_tries,
|
63
|
-
# at which point it'll just raise the constraint violation exception.
|
64
|
-
def optimistically_save_derivative(uploaded_file:, derivative:, tries: 0)
|
65
|
-
derivative.file_attacher.change(uploaded_file)
|
66
|
-
save_deriv_ensuring_unchanged_asset(derivative)
|
67
|
-
rescue ActiveRecord::RecordNotUnique => e
|
68
|
-
if tries < max_optimistic_tries
|
69
|
-
# find the one that's already there, try to attach our new file
|
70
|
-
# to that one
|
71
|
-
derivative = Kithe::Derivative.where(key: key.to_s, asset: asset).first || derivative
|
72
|
-
optimistically_save_derivative(uploaded_file: uploaded_file, derivative: derivative, tries: tries + 1)
|
73
|
-
else
|
74
|
-
uploaded_file.delete if uploaded_file
|
75
|
-
raise e
|
76
|
-
end
|
77
|
-
rescue StandardError => e
|
78
|
-
# aggressively clean up our file on errors!
|
79
|
-
uploaded_file.delete if uploaded_file
|
80
|
-
raise e
|
81
|
-
end
|
82
|
-
|
83
|
-
# Save a Derivative model with some fancy DB footwork to ensure at the time
|
84
|
-
# we save it, the original asset file it is based on is still in db unchanged,
|
85
|
-
# in a concurrency-safe way.
|
86
|
-
#
|
87
|
-
# We re-fetch to ensure asset still exists, with sha512 we expect. (kithe model ensures sha512
|
88
|
-
# exists in shrine metadata). With a pessmistic lock in a transaction. This ensures that at
|
89
|
-
# the point we save the new derivative, the db is still in a state where the original file
|
90
|
-
# the derivative relates to is still in the db.
|
91
|
-
#
|
92
|
-
# Can raise a ActiveRecord::RecordNotUnique, if derivative unique constraint is violated,
|
93
|
-
# that is handled above here.
|
94
|
-
def save_deriv_ensuring_unchanged_asset(deriv)
|
95
|
-
# fancy throw/catch keep our abort rescue from being in the transaction
|
96
|
-
catch(:kithe_unchanged_abort) do
|
97
|
-
Kithe::Asset.transaction do
|
98
|
-
# the file we're trying to add a derivative to doesn't exist anymore, forget it
|
99
|
-
unless asset.acquire_lock_on_sha
|
100
|
-
throw :kithe_unchanged_abort
|
101
|
-
end
|
102
|
-
|
103
|
-
deriv.save!
|
104
|
-
return deriv
|
105
|
-
end
|
106
|
-
end
|
107
|
-
|
108
|
-
# If we made it here, we've aborted
|
109
|
-
deriv.file.delete
|
110
|
-
return nil
|
111
|
-
end
|
112
|
-
|
113
|
-
def asset_has_persisted_sha512?
|
114
|
-
asset.persisted? && asset.sha512.present? &&
|
115
|
-
!( asset.file_data_changed? &&
|
116
|
-
asset.file_data_change.first.try(:dig, "metadata", "sha512") !=
|
117
|
-
asset.file_data_change.second.try(:dig, "metadata", "sha512"))
|
118
|
-
end
|
119
|
-
end
|