rainbow_storage 1.0.1
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 +7 -0
- data/README.md +0 -0
- data/TODO.md +0 -0
- data/lib/rainbow_storage.rb +16 -0
- data/lib/rainbow_storage/adapters/abstract_adapter.rb +34 -0
- data/lib/rainbow_storage/adapters/repository.rb +19 -0
- data/lib/rainbow_storage/adapters/s3.rb +8 -0
- data/lib/rainbow_storage/adapters/s3/adapter.rb +46 -0
- data/lib/rainbow_storage/configuration.rb +20 -0
- data/lib/rainbow_storage/exceptions/storage_not_configured_exception.rb +3 -0
- data/lib/rainbow_storage/exceptions/unknown_adapter_exception.rb +3 -0
- data/lib/rainbow_storage/exceptions/unsupported_file_type_exception.rb +3 -0
- data/lib/rainbow_storage/manager.rb +73 -0
- data/lib/rainbow_storage/path_generator.rb +42 -0
- data/rainbow_storage.gemspec +13 -0
- metadata +71 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 0c221a06f5c7d6ac3cbbada2cfa3d0f5c02c3d97
|
4
|
+
data.tar.gz: f5016782b665e2df5c3f1c6f75a30cba8b63c724
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 9a18d1deae6e864974972b6e88f024e9bf9df1bee13396fceed742b9cd63b6f66a933952e961a0c25afd77b16f3b5e33b77c19630e7eab6576750634fcb7981f
|
7
|
+
data.tar.gz: b8d4a7113b95c27ae8fb65b1023907632b8df7a6fa03f2e066ad0707ccfbb444c28aad64d713a2256a8afaace3145444a06da85458dd26b0d7015aa1468e6c88
|
data/README.md
ADDED
File without changes
|
data/TODO.md
ADDED
File without changes
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'rainbow_storage/configuration'
|
2
|
+
require 'rainbow_storage/manager'
|
3
|
+
require 'rainbow_storage/path_generator'
|
4
|
+
|
5
|
+
module RainbowStorage
|
6
|
+
class << self
|
7
|
+
def manager
|
8
|
+
fail StorageNotConfiguredException unless config
|
9
|
+
RainbowStorage::Manager.new(config, path_generator)
|
10
|
+
end
|
11
|
+
|
12
|
+
def path_generator
|
13
|
+
RainbowStorage::PathGenerator.new(config)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module RainbowStorage
|
2
|
+
module Adapters
|
3
|
+
class AbstractAdapter
|
4
|
+
attr_accessor :config
|
5
|
+
|
6
|
+
def initialize(config)
|
7
|
+
@config = config
|
8
|
+
post_initialize
|
9
|
+
end
|
10
|
+
|
11
|
+
def get(path)
|
12
|
+
fail NotImplementedError
|
13
|
+
end
|
14
|
+
|
15
|
+
def put(path, data)
|
16
|
+
fail NotImplementedError
|
17
|
+
end
|
18
|
+
|
19
|
+
def delete(path)
|
20
|
+
fail NotImplementedError
|
21
|
+
end
|
22
|
+
|
23
|
+
def public_url(path)
|
24
|
+
fail NotImplementedError
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
# Hook-method to add custom initialization logic to adapter
|
30
|
+
def post_initialize
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'rainbow_storage/exceptions/unknown_adapter_exception'
|
2
|
+
|
3
|
+
module RainbowStorage
|
4
|
+
module Adapters
|
5
|
+
class Repository
|
6
|
+
class << self
|
7
|
+
def get(name)
|
8
|
+
adapters[name] || fail(RainbowStorage::UnknownAdapterException, "Unknown adapter '#{name}'")
|
9
|
+
end
|
10
|
+
|
11
|
+
def adapters
|
12
|
+
{
|
13
|
+
s3: RainbowStorage::Adapters::S3::Adapter
|
14
|
+
}
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
require 's3'
|
2
|
+
require 'rainbow_storage/adapters/abstract_adapter'
|
3
|
+
|
4
|
+
module RainbowStorage
|
5
|
+
module Adapters
|
6
|
+
module S3
|
7
|
+
class Adapter < RainbowStorage::Adapters::AbstractAdapter
|
8
|
+
attr_accessor :bucket
|
9
|
+
|
10
|
+
# TODO: should we deal with tempfiles here? or just return a data?
|
11
|
+
def get(path)
|
12
|
+
object = bucket.objects.find(path)
|
13
|
+
tempfile = Tempfile.new
|
14
|
+
tempfile.write(object.content)
|
15
|
+
tempfile.rewind
|
16
|
+
tempfile
|
17
|
+
end
|
18
|
+
|
19
|
+
def put(path, data)
|
20
|
+
new_object = bucket.objects.build(path)
|
21
|
+
new_object.content = data
|
22
|
+
new_object.acl = :public_read
|
23
|
+
new_object.save
|
24
|
+
end
|
25
|
+
|
26
|
+
def delete(path)
|
27
|
+
object = bucket.objects.find(path)
|
28
|
+
object.destroy
|
29
|
+
end
|
30
|
+
|
31
|
+
def public_url(path)
|
32
|
+
object = bucket.objects.find(path)
|
33
|
+
object.temporary_url(Time.now + 1800)
|
34
|
+
end
|
35
|
+
|
36
|
+
private
|
37
|
+
|
38
|
+
def post_initialize
|
39
|
+
@service = ::S3::Service.new(access_key_id: config[:access_key],
|
40
|
+
secret_access_key: config[:secret_key])
|
41
|
+
@bucket = @service.bucket(config[:bucket])
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module RainbowStorage
|
2
|
+
class Configuration
|
3
|
+
attr_accessor :salt, :nesting, :adapter, :adapter_config
|
4
|
+
|
5
|
+
def initialize
|
6
|
+
@salt = 'default_salt'
|
7
|
+
@nesting = 3
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
class << self
|
12
|
+
def setup
|
13
|
+
yield(config)
|
14
|
+
end
|
15
|
+
|
16
|
+
def config
|
17
|
+
@config ||= RainbowStorage::Configuration.new
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
require 'rainbow_storage/adapters/s3'
|
2
|
+
require 'rainbow_storage/adapters/repository'
|
3
|
+
require 'rainbow_storage/exceptions/unsupported_file_type_exception'
|
4
|
+
require 'open-uri'
|
5
|
+
|
6
|
+
module RainbowStorage
|
7
|
+
class Manager
|
8
|
+
attr_accessor :config, :path_generator
|
9
|
+
|
10
|
+
def initialize(config, path_generator)
|
11
|
+
@config = config
|
12
|
+
@path_generator = path_generator
|
13
|
+
end
|
14
|
+
|
15
|
+
# TODO: maybe introduce RainbowStorage::File class for path, extension, content and content-type?
|
16
|
+
# Usage examples:
|
17
|
+
# RainbowStorage.manager.upload({file: URI('http://site.com/files/1358_1495284100.jpg'), id: 1, extension: '.jpg'})
|
18
|
+
def upload(options = {})
|
19
|
+
validate_upload_options!(options)
|
20
|
+
|
21
|
+
file = options[:file]
|
22
|
+
id = options[:id] || "#{file.object_id}#{Time.now.to_i}"
|
23
|
+
extension = options[:extension] || infer_extenstion_from_file(file)
|
24
|
+
|
25
|
+
content = case file
|
26
|
+
when Tempfile
|
27
|
+
file.rewind
|
28
|
+
file.read
|
29
|
+
when URI
|
30
|
+
open(file.to_s).read
|
31
|
+
else
|
32
|
+
fail RainbowStorage::UnsupportedFileTypeException,
|
33
|
+
"#{file.class} is not valid type for file attribute"
|
34
|
+
end
|
35
|
+
|
36
|
+
path = path_generator.filename(id, extension)
|
37
|
+
adapter.put(path, content)
|
38
|
+
end
|
39
|
+
|
40
|
+
# Usage example:
|
41
|
+
# RainbowStorage.manager.download(1, '.jpg')
|
42
|
+
def download(id, extension = nil)
|
43
|
+
path = path_generator.filename(id, extension)
|
44
|
+
adapter.get(path)
|
45
|
+
end
|
46
|
+
|
47
|
+
# Usage example:
|
48
|
+
# RainbowStorage.manager.remove(1, 'jpg')
|
49
|
+
def remove(id, extension = nil)
|
50
|
+
path = path_generator.filename(id, extension)
|
51
|
+
adapter.delete(path)
|
52
|
+
end
|
53
|
+
|
54
|
+
# Usage example:
|
55
|
+
# RainbowStorage.manager.link(1, 'jpg')
|
56
|
+
def link(id, extension = nil)
|
57
|
+
path = path_generator.filename(id, extension)
|
58
|
+
adapter.public_url(path)
|
59
|
+
end
|
60
|
+
|
61
|
+
private
|
62
|
+
|
63
|
+
def validate_upload_options!(options)
|
64
|
+
end
|
65
|
+
|
66
|
+
def infer_extension_from_file(file)
|
67
|
+
end
|
68
|
+
|
69
|
+
def adapter
|
70
|
+
@adapter ||= RainbowStorage::Adapters::Repository.get(config.adapter).new(config.adapter_config)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
module RainbowStorage
|
2
|
+
class PathGenerator
|
3
|
+
attr_accessor :config
|
4
|
+
|
5
|
+
def initialize(config)
|
6
|
+
@config = config
|
7
|
+
end
|
8
|
+
|
9
|
+
# Add extension to path if present
|
10
|
+
# do not add extra dot before extesion
|
11
|
+
def filename(id, extension)
|
12
|
+
path = filepath(id)
|
13
|
+
return path if extension.nil?
|
14
|
+
"#{path}.#{extension.gsub(/^\./, '')}"
|
15
|
+
end
|
16
|
+
|
17
|
+
# Convert string like `abcdefghi` to `ab/cd/ef/ghi`
|
18
|
+
# to represent location on file system
|
19
|
+
def filepath(id)
|
20
|
+
tokens = hmac(id).chars.each_slice(2).map(&:join)
|
21
|
+
result = []
|
22
|
+
nesting_depth.times { result << tokens.shift }
|
23
|
+
result << tokens.join
|
24
|
+
result.join('/')
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
def hmac(id)
|
30
|
+
digest = OpenSSL::Digest.new('sha1')
|
31
|
+
OpenSSL::HMAC.hexdigest(digest, hmac_key, id.to_s)
|
32
|
+
end
|
33
|
+
|
34
|
+
def hmac_key
|
35
|
+
config.salt
|
36
|
+
end
|
37
|
+
|
38
|
+
def nesting_depth
|
39
|
+
config.nesting
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
Gem::Specification.new do |s|
|
2
|
+
s.name = "rainbow_storage"
|
3
|
+
s.version = "1.0.1"
|
4
|
+
s.licenses = ['MIT']
|
5
|
+
s.summary = "This is an example!"
|
6
|
+
s.description = "Much longer explanation of the example!"
|
7
|
+
s.author = "Stanislav Mekhonoshin"
|
8
|
+
s.email = "ejabberd@gmail.com"
|
9
|
+
s.require_paths = ["lib"]
|
10
|
+
s.files = `git ls-files`.split($/)
|
11
|
+
|
12
|
+
s.add_runtime_dependency "s3", ["= 0.3.25"]
|
13
|
+
end
|
metadata
ADDED
@@ -0,0 +1,71 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: rainbow_storage
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Stanislav Mekhonoshin
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2017-06-07 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: s3
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - '='
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 0.3.25
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - '='
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 0.3.25
|
27
|
+
description: Much longer explanation of the example!
|
28
|
+
email: ejabberd@gmail.com
|
29
|
+
executables: []
|
30
|
+
extensions: []
|
31
|
+
extra_rdoc_files: []
|
32
|
+
files:
|
33
|
+
- README.md
|
34
|
+
- TODO.md
|
35
|
+
- lib/rainbow_storage.rb
|
36
|
+
- lib/rainbow_storage/adapters/abstract_adapter.rb
|
37
|
+
- lib/rainbow_storage/adapters/repository.rb
|
38
|
+
- lib/rainbow_storage/adapters/s3.rb
|
39
|
+
- lib/rainbow_storage/adapters/s3/adapter.rb
|
40
|
+
- lib/rainbow_storage/configuration.rb
|
41
|
+
- lib/rainbow_storage/exceptions/storage_not_configured_exception.rb
|
42
|
+
- lib/rainbow_storage/exceptions/unknown_adapter_exception.rb
|
43
|
+
- lib/rainbow_storage/exceptions/unsupported_file_type_exception.rb
|
44
|
+
- lib/rainbow_storage/manager.rb
|
45
|
+
- lib/rainbow_storage/path_generator.rb
|
46
|
+
- rainbow_storage.gemspec
|
47
|
+
homepage:
|
48
|
+
licenses:
|
49
|
+
- MIT
|
50
|
+
metadata: {}
|
51
|
+
post_install_message:
|
52
|
+
rdoc_options: []
|
53
|
+
require_paths:
|
54
|
+
- lib
|
55
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
56
|
+
requirements:
|
57
|
+
- - ">="
|
58
|
+
- !ruby/object:Gem::Version
|
59
|
+
version: '0'
|
60
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
61
|
+
requirements:
|
62
|
+
- - ">="
|
63
|
+
- !ruby/object:Gem::Version
|
64
|
+
version: '0'
|
65
|
+
requirements: []
|
66
|
+
rubyforge_project:
|
67
|
+
rubygems_version: 2.5.1
|
68
|
+
signing_key:
|
69
|
+
specification_version: 4
|
70
|
+
summary: This is an example!
|
71
|
+
test_files: []
|