faster_s3 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,18 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ .idea
7
+ Gemfile.lock
8
+ InstalledFiles
9
+ _yardoc
10
+ coverage
11
+ doc/
12
+ lib/bundler/man
13
+ pkg
14
+ rdoc
15
+ spec/reports
16
+ test/tmp
17
+ test/version_tmp
18
+ tmp
data/.ruby-gemset ADDED
@@ -0,0 +1 @@
1
+ faster_s3
data/.ruby-version ADDED
@@ -0,0 +1 @@
1
+ ruby-1.9.3-p392
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in faster_s3.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 Pat Leamon
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,36 @@
1
+ # FasterS3
2
+
3
+ Download files from s3 faster by downloading chunks in parallel
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ gem 'faster_s3'
10
+
11
+ And then execute:
12
+
13
+ $ bundle
14
+
15
+ Or install it yourself as:
16
+
17
+ $ gem install faster_s3
18
+
19
+ ## Usage
20
+
21
+ FasterS3.download(
22
+ "path_to_local_file",
23
+ access_key_id: "s3 access key id",
24
+ secret_access_key: "s3 secret access key",
25
+ bucket_name: "s3-bucket",
26
+ path: "path-in-s3"
27
+ )
28
+
29
+
30
+ ## Contributing
31
+
32
+ 1. Fork it
33
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
34
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
35
+ 4. Push to the branch (`git push origin my-new-feature`)
36
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
data/faster_s3.gemspec ADDED
@@ -0,0 +1,25 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'faster_s3/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "faster_s3"
8
+ spec.version = FasterS3::VERSION
9
+ spec.authors = ["Pat Leamon"]
10
+ spec.email = ["patrick@redbubble.com"]
11
+ spec.description = %q{Download files from s3 in parallel}
12
+ spec.summary = %q{Faster s3 downloads}
13
+ spec.homepage = ""
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files`.split($/)
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_development_dependency "bundler", "~> 1.3"
22
+ spec.add_development_dependency "rake"
23
+ spec.add_dependency "aws-sdk"
24
+ spec.add_dependency "parallel"
25
+ end
@@ -0,0 +1,3 @@
1
+ module FasterS3
2
+ VERSION = "1.0.0"
3
+ end
data/lib/faster_s3.rb ADDED
@@ -0,0 +1,85 @@
1
+ require "faster_s3/version"
2
+ require 'aws/s3'
3
+ require 'parallel'
4
+
5
+ module FasterS3
6
+ # @param [String] destination File will be written to this destination
7
+ # @param [Hash] options
8
+ #
9
+ # @option options [String] :access_key_id The access key id for the s3 account
10
+ #
11
+ # @option options [String] :secret_access_key The secret access key for the s3 account
12
+ #
13
+ # @option options [String] :bucket_name The s3 bucket name
14
+ #
15
+ # @option options [String] :path The path in s3 of the file
16
+ #
17
+ # @option options [String] :parallel Optional - number of parallel parts to download. Default is 8
18
+ #
19
+ def self.download(destination, options)
20
+ Download.new(options).download_to(destination)
21
+ end
22
+
23
+ class Download
24
+ DEFAULT_PARTS = 8
25
+ CHUNK_SIZE = 1024*1024
26
+
27
+ attr_reader :config, :parts
28
+
29
+ def initialize(config = {})
30
+ @config = config
31
+ @parts = config[:parallel] || DEFAULT_PARTS
32
+ end
33
+
34
+ def download_to(path)
35
+ s3_object = remote_object
36
+ length = s3_object.content_length
37
+ raise "File is too small to download in parallel" if length < parts
38
+
39
+ # Split into parts
40
+ part_length = length / parts
41
+ remainder = length % parts
42
+
43
+ part_array = Array(1..parts)
44
+ file_parts = Parallel.map(part_array, in_threads: parts) do |part|
45
+ start = (part - 1) * part_length
46
+ end_pos = start + part_length
47
+
48
+ if part == part_array.last
49
+ end_pos += remainder
50
+ byte_range = start..end_pos
51
+ else
52
+ byte_range = start...end_pos
53
+ end
54
+
55
+ part_path = "#{path}.part.#{part}"
56
+ File.open("#{path}.part.#{part}", 'wb') do |file|
57
+ s3_object.read(range: byte_range) do |chunk|
58
+ file.write(chunk)
59
+ end
60
+ end
61
+ part_path
62
+ end
63
+
64
+ reconstitute_parts(path, file_parts)
65
+ end
66
+
67
+ def reconstitute_parts(path, file_parts)
68
+ File.open(path, 'wb') do |file|
69
+ file_parts.each do |part_path|
70
+ File.open(part_path, 'rb') do |part_file|
71
+ file.write(part_file.read(CHUNK_SIZE)) until part_file.eof?
72
+ end
73
+ File.delete(part_path)
74
+ end
75
+ end
76
+ end
77
+
78
+ def remote_object
79
+ s3 = AWS::S3.new({:access_key_id => config[:access_key_id], :secret_access_key => config[:secret_access_key]})
80
+ bucket = s3.buckets[config[:bucket_name]]
81
+ bucket.objects[config[:path]]
82
+ end
83
+ end
84
+
85
+ end
metadata ADDED
@@ -0,0 +1,100 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: faster_s3
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Pat Leamon
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-11-07 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: bundler
16
+ requirement: &70297353186560 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ~>
20
+ - !ruby/object:Gem::Version
21
+ version: '1.3'
22
+ type: :development
23
+ prerelease: false
24
+ version_requirements: *70297353186560
25
+ - !ruby/object:Gem::Dependency
26
+ name: rake
27
+ requirement: &70297353185680 !ruby/object:Gem::Requirement
28
+ none: false
29
+ requirements:
30
+ - - ! '>='
31
+ - !ruby/object:Gem::Version
32
+ version: '0'
33
+ type: :development
34
+ prerelease: false
35
+ version_requirements: *70297353185680
36
+ - !ruby/object:Gem::Dependency
37
+ name: aws-sdk
38
+ requirement: &70297353184260 !ruby/object:Gem::Requirement
39
+ none: false
40
+ requirements:
41
+ - - ! '>='
42
+ - !ruby/object:Gem::Version
43
+ version: '0'
44
+ type: :runtime
45
+ prerelease: false
46
+ version_requirements: *70297353184260
47
+ - !ruby/object:Gem::Dependency
48
+ name: parallel
49
+ requirement: &70297353183640 !ruby/object:Gem::Requirement
50
+ none: false
51
+ requirements:
52
+ - - ! '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ type: :runtime
56
+ prerelease: false
57
+ version_requirements: *70297353183640
58
+ description: Download files from s3 in parallel
59
+ email:
60
+ - patrick@redbubble.com
61
+ executables: []
62
+ extensions: []
63
+ extra_rdoc_files: []
64
+ files:
65
+ - .gitignore
66
+ - .ruby-gemset
67
+ - .ruby-version
68
+ - Gemfile
69
+ - LICENSE.txt
70
+ - README.md
71
+ - Rakefile
72
+ - faster_s3.gemspec
73
+ - lib/faster_s3.rb
74
+ - lib/faster_s3/version.rb
75
+ homepage: ''
76
+ licenses:
77
+ - MIT
78
+ post_install_message:
79
+ rdoc_options: []
80
+ require_paths:
81
+ - lib
82
+ required_ruby_version: !ruby/object:Gem::Requirement
83
+ none: false
84
+ requirements:
85
+ - - ! '>='
86
+ - !ruby/object:Gem::Version
87
+ version: '0'
88
+ required_rubygems_version: !ruby/object:Gem::Requirement
89
+ none: false
90
+ requirements:
91
+ - - ! '>='
92
+ - !ruby/object:Gem::Version
93
+ version: '0'
94
+ requirements: []
95
+ rubyforge_project:
96
+ rubygems_version: 1.8.10
97
+ signing_key:
98
+ specification_version: 3
99
+ summary: Faster s3 downloads
100
+ test_files: []