active_storage-cloud_transformations 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 947d49d6ce59f73258bc8093ee848f0a1a35ff948779db0a4f3e969a0a01340d
4
+ data.tar.gz: a3137c207d361317c4ff14ba26cd5e4728b7133a082e612bb042990d2753bf9e
5
+ SHA512:
6
+ metadata.gz: 58383b12689b2fccd8e2228b524ba8318f6e52f29258cf48b365cb18dd7d1dd5fd03d9bdd6a33c066c51db0c6903eb8b970ca7662fa989b30413ac9455a51013
7
+ data.tar.gz: be8e63d61cd35c883a3fedd257740a2c1e5f31bf9ca2589ff6f1ccd41116d08cd7017358134874dcfeb24e2c5dba3019b382f4c4e348be63374794781778e333
data/.gitignore ADDED
@@ -0,0 +1,15 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /_yardoc/
4
+ /coverage/
5
+ /doc/
6
+ /pkg/
7
+ /spec/reports/
8
+ /spec/storage.yml
9
+ /tmp/
10
+ /Gemfile.lock
11
+ /.ruby-version
12
+ /.ruby-gemset
13
+ /.byebug_history
14
+ .rspec_status
15
+
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --format documentation
2
+ --color
3
+ --require spec_helper
data/.travis.yml ADDED
@@ -0,0 +1,6 @@
1
+ ---
2
+ language: ruby
3
+ cache: bundler
4
+ rvm:
5
+ - 2.6.3
6
+ before_install: gem install bundler -v 2.1.4
data/Gemfile ADDED
@@ -0,0 +1,13 @@
1
+ source "https://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in active_storage-cloud_transformations.gemspec
4
+ gemspec
5
+
6
+ gem "rake", "~> 12.0"
7
+ gem "rspec", "~> 3.0"
8
+ gem "rails", "~> 6.1"
9
+ gem 'sqlite3', '~> 1.4'
10
+ gem 'bootsnap', '>= 1.4.4', require: false
11
+ gem 'byebug'
12
+ gem 'aws-sdk-s3'
13
+
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2021 Micah Geisel
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,40 @@
1
+ # ActiveStorage::CloudTransformations
2
+
3
+ Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/active_storage/cloud_transformations`. To experiment with that code, run `bin/console` for an interactive prompt.
4
+
5
+ TODO: Delete this and the text above, and describe your gem
6
+
7
+ ## Installation
8
+
9
+ Add this line to your application's Gemfile:
10
+
11
+ ```ruby
12
+ gem 'active_storage-cloud_transformations'
13
+ ```
14
+
15
+ And then execute:
16
+
17
+ $ bundle install
18
+
19
+ Or install it yourself as:
20
+
21
+ $ gem install active_storage-cloud_transformations
22
+
23
+ ## Usage
24
+
25
+ TODO: Write usage instructions here
26
+
27
+ ## Development
28
+
29
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
30
+
31
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
32
+
33
+ ## Contributing
34
+
35
+ Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/active_storage-cloud_transformations.
36
+
37
+
38
+ ## License
39
+
40
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
data/Rakefile ADDED
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
@@ -0,0 +1,26 @@
1
+ require_relative 'lib/active_storage/cloud_transformations/version'
2
+
3
+ Gem::Specification.new do |spec|
4
+ spec.name = "active_storage-cloud_transformations"
5
+ spec.version = ActiveStorage::CloudTransformations::VERSION
6
+ spec.authors = ["Micah Geisel"]
7
+ spec.email = ["micah@botandrose.com"]
8
+
9
+ spec.summary = %q{Generate ActiveStorage Variants and Previews via external cloud services, rather than on-server.}
10
+ spec.homepage = "https://github.com/botandrose/active_storage-cloud_transformations"
11
+ spec.license = "MIT"
12
+ spec.required_ruby_version = Gem::Requirement.new(">= 2.3.0")
13
+
14
+ spec.metadata["homepage_uri"] = spec.homepage
15
+
16
+ # Specify which files should be added to the gem when it is released.
17
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
18
+ spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
19
+ `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
20
+ end
21
+ spec.bindir = "exe"
22
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
23
+ spec.require_paths = ["lib"]
24
+
25
+ spec.add_dependency "activestorage", "~>6.1"
26
+ end
data/bin/console ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "active_storage/cloud_transformations"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start(__FILE__)
data/bin/setup ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,65 @@
1
+ Rails.application.reloader.to_prepare do
2
+ require "active_storage/cloud_transformations/preview"
3
+ require "active_storage/cloud_transformations/variant"
4
+
5
+ # Overwrite original methods to replace Rails' variant implementation with our own
6
+
7
+ ActiveStorage::Blob.prepend Module.new {
8
+ def representation(transformations)
9
+ case
10
+ when previewable?(transformations)
11
+ preview transformations
12
+ when variable?
13
+ variant transformations
14
+ else
15
+ raise ActiveStorage::UnrepresentableError
16
+ end
17
+ end
18
+
19
+ def previewable? transformations=nil
20
+ if transformations.nil?
21
+ super()
22
+ else
23
+ variation = ActiveStorage::Variation.wrap(transformations)
24
+ video? && MimeMagic.by_extension(variation.format).image?
25
+ end
26
+ end
27
+
28
+ def preview(transformations)
29
+ if video? && service.class.to_s == "ActiveStorage::Service::S3Service"
30
+ ActiveStorage::CloudTransformations::Preview.new(self, transformations)
31
+ else
32
+ super
33
+ end
34
+ end
35
+
36
+ def default_variant_format
37
+ if video?
38
+ :mp4
39
+ else
40
+ super
41
+ end
42
+ end
43
+
44
+ def variable?
45
+ # # Original method implementation documented here as of ActiveStorage 6.1:
46
+ # ActiveStorage.variable_content_types.include?(content_type)
47
+
48
+ content_type =~ /^(image|video)\//
49
+ end
50
+
51
+ private
52
+
53
+ def variant_class
54
+ # # Original method implementation documented here as of ActiveStorage 6.1:
55
+ # ActiveStorage.track_variants ? ActiveStorage::VariantWithRecord : ActiveStorage::Variant
56
+
57
+ if service.class.to_s == "ActiveStorage::Service::S3Service"
58
+ ActiveStorage::CloudTransformations::Variant
59
+ else
60
+ super
61
+ end
62
+ end
63
+ }
64
+ end
65
+
data/config/routes.rb ADDED
@@ -0,0 +1,5 @@
1
+ Rails.application.routes.draw do
2
+ resolve("ActiveStorage::CloudTransformations::Variant") { |variant, options| route_for(ActiveStorage.resolve_model_to_route, variant, options) }
3
+ resolve("ActiveStorage::CloudTransformations::Preview") { |preview, options| route_for(ActiveStorage.resolve_model_to_route, preview, options) }
4
+ end
5
+
@@ -0,0 +1,66 @@
1
+ module ActiveStorage
2
+ module CloudTransformations
3
+ class Preview < ActiveStorage::Preview
4
+ def process
5
+ # TODO
6
+ # if image.attached?
7
+ # if image.variant(variation).processed?
8
+ # variant
9
+ # else
10
+ # create_blob_preview_image_variant
11
+ # end
12
+ # else
13
+ create_blob_preview_image_and_blob_preview_image_variant
14
+ # end
15
+ self
16
+ end
17
+
18
+ def processed?
19
+ image.variant(variation)&.processed?
20
+ end
21
+
22
+ private
23
+
24
+ def create_blob_preview_image_and_blob_preview_image_variant
25
+ preview_image_blob = ActiveStorage::Blob.create_before_direct_upload!({
26
+ filename: "#{blob.filename.base}.#{variation.format}",
27
+ content_type: variation.content_type,
28
+ service_name: blob.service_name,
29
+ byte_size: 0, # we don"t know this yet, can we get it from the results?
30
+ checksum: 0, # we don"t know this yet, can we get it from the results?
31
+ })
32
+ blob.preview_image.attach(preview_image_blob)
33
+
34
+ variant_variation = variation.default_to(preview_image_blob.send(:default_variant_transformations))
35
+ variant_record = blob.preview_image.variant_records.create!(variation_digest: variant_variation.digest)
36
+ variant_blob = ActiveStorage::Blob.create_before_direct_upload!({
37
+ filename: "#{blob.filename.base}.#{variant_variation.format}",
38
+ content_type: variant_variation.content_type,
39
+ service_name: blob.service_name,
40
+ byte_size: 0, # we don"t know this yet, can we get it from the results?
41
+ checksum: 0, # we don"t know this yet, can we get it from the results?
42
+ })
43
+ variant_record.image.attach(variant_blob)
44
+
45
+ width, height = variation.transformations.fetch(:resize_to_limit)
46
+ post! "https://huuabwxpqf.execute-api.us-west-2.amazonaws.com/prod/video/preview", {
47
+ blob_url: blob.url.split("?").first,
48
+ dimensions: "#{width}x#{height}",
49
+ preview_image_url: preview_image_blob.url.split("?").first,
50
+ preview_image_variant_url: variant_blob.url.split("?").first,
51
+ }
52
+ end
53
+
54
+ def post! url, body
55
+ uri = URI.parse(url)
56
+ http = Net::HTTP.new(uri.host, uri.port)
57
+ http.use_ssl = uri.scheme == "https"
58
+ request = Net::HTTP::Post.new(uri.request_uri, {"Content-Type": "application/json"})
59
+ request.body = body.to_json
60
+ response = http.request(request)
61
+ response.code == "201" || (raise body.to_json + response.inspect)
62
+ end
63
+ end
64
+ end
65
+ end
66
+
@@ -0,0 +1,59 @@
1
+ require "active_storage/variant_with_record"
2
+
3
+ module ActiveStorage
4
+ module CloudTransformations
5
+ class Variant < ActiveStorage::VariantWithRecord
6
+ def process
7
+ raise ActiveStorage::InvariableError unless blob.image? || blob.video?
8
+
9
+ ActiveRecord::Base.connected_to(role: ActiveRecord::Base.writing_role) do
10
+ # FIXME #create_or_find_by! runs the block in both cases. bug in rails?
11
+ blob.variant_records.find_or_create_by!(variation_digest: variation.digest) do |record|
12
+ output_blob = ActiveStorage::Blob.create_before_direct_upload!({
13
+ filename: "#{blob.filename.base}.#{variation.format}",
14
+ content_type: variation.content_type,
15
+ service_name: blob.service_name,
16
+ byte_size: 0, # we don"t know this yet, can we get it from the results?
17
+ checksum: 0, # we don"t know this yet, can we get it from the results?
18
+ })
19
+ record.image.attach(output_blob)
20
+ run_crucible_job(blob, output_blob)
21
+ end
22
+ end
23
+ rescue ActiveRecord::RecordNotUnique
24
+ retry
25
+ end
26
+
27
+ private
28
+
29
+ def run_crucible_job input_blob, output_blob
30
+ width, height = variation.transformations.fetch(:resize_to_limit)
31
+ post! "https://huuabwxpqf.execute-api.us-west-2.amazonaws.com/prod/#{path}", {
32
+ blob_url: input_blob.url.split("?").first,
33
+ dimensions: "#{width}x#{height}",
34
+ variant_url: output_blob.url.split("?").first,
35
+ }
36
+ end
37
+
38
+ def path
39
+ return "image/variant" if blob.image?
40
+ return "video/variant" if blob.video?
41
+ end
42
+
43
+ def format
44
+ variation.transformations.fetch(:format)
45
+ end
46
+
47
+ def post! url, body
48
+ uri = URI.parse(url)
49
+ http = Net::HTTP.new(uri.host, uri.port)
50
+ http.use_ssl = uri.scheme == "https"
51
+ request = Net::HTTP::Post.new(uri.request_uri, {"Content-Type": "application/json"})
52
+ request.body = body.to_json
53
+ response = http.request(request)
54
+ response.code == "201" || (raise body.to_json + response.inspect)
55
+ end
56
+ end
57
+ end
58
+ end
59
+
@@ -0,0 +1,5 @@
1
+ module ActiveStorage
2
+ module CloudTransformations
3
+ VERSION = "0.1.0"
4
+ end
5
+ end
@@ -0,0 +1,9 @@
1
+ require "active_storage/cloud_transformations/version"
2
+
3
+ module ActiveStorage
4
+ module CloudTransformations
5
+ class Rails < ::Rails::Engine
6
+ end
7
+ end
8
+ end
9
+
metadata ADDED
@@ -0,0 +1,75 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: active_storage-cloud_transformations
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Micah Geisel
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2021-10-02 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: activestorage
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '6.1'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '6.1'
27
+ description:
28
+ email:
29
+ - micah@botandrose.com
30
+ executables: []
31
+ extensions: []
32
+ extra_rdoc_files: []
33
+ files:
34
+ - ".gitignore"
35
+ - ".rspec"
36
+ - ".travis.yml"
37
+ - Gemfile
38
+ - LICENSE.txt
39
+ - README.md
40
+ - Rakefile
41
+ - active_storage-cloud_transformations.gemspec
42
+ - bin/console
43
+ - bin/setup
44
+ - config/initializers/active_storage-cloud_transformations.rb
45
+ - config/routes.rb
46
+ - lib/active_storage/cloud_transformations.rb
47
+ - lib/active_storage/cloud_transformations/preview.rb
48
+ - lib/active_storage/cloud_transformations/variant.rb
49
+ - lib/active_storage/cloud_transformations/version.rb
50
+ homepage: https://github.com/botandrose/active_storage-cloud_transformations
51
+ licenses:
52
+ - MIT
53
+ metadata:
54
+ homepage_uri: https://github.com/botandrose/active_storage-cloud_transformations
55
+ post_install_message:
56
+ rdoc_options: []
57
+ require_paths:
58
+ - lib
59
+ required_ruby_version: !ruby/object:Gem::Requirement
60
+ requirements:
61
+ - - ">="
62
+ - !ruby/object:Gem::Version
63
+ version: 2.3.0
64
+ required_rubygems_version: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ requirements: []
70
+ rubygems_version: 3.0.8
71
+ signing_key:
72
+ specification_version: 4
73
+ summary: Generate ActiveStorage Variants and Previews via external cloud services,
74
+ rather than on-server.
75
+ test_files: []