ruby-uploader 0.1.0

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.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: b93b4e72c413098bf95988e6f3d5ba6ab4f89af0
4
+ data.tar.gz: 3ea0d6b6c6c68974fc6a82e8cc7517a43bca2032
5
+ SHA512:
6
+ metadata.gz: 89d5c96002f7a444ab483f36724995d37639c8c7f5e5e3b0ef77c3a691684f4fd6dcb136f286f3d0b6c12568f438a3dd7bdc1e30eee51871ff9338b3f93ba589
7
+ data.tar.gz: 19c0ef8fe7aefa7492d14ea980e2e9d80aec16558375914a67eda10260a726c5c5e63cf6836f40658de3a2764e0c0b780dda814702459b7bdd3b7ecf730d57d1
@@ -0,0 +1,4 @@
1
+ *.gem
2
+ *.swp
3
+ *.iml
4
+ Gemfile.lock
@@ -0,0 +1,8 @@
1
+ Style/Documentation:
2
+ Enabled: false
3
+
4
+ Style/LineLength:
5
+ Max: 120
6
+
7
+ Style/MethodLength:
8
+ Max: 35
data/Gemfile ADDED
@@ -0,0 +1,12 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
4
+
5
+ group :development do
6
+ gem 'rubocop', '0.23.0', require: false
7
+ gem 'rake'
8
+ end
9
+
10
+ group :debug do
11
+ gem 'byebug'
12
+ end
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 Guillaume Giamarchi
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.
@@ -0,0 +1,108 @@
1
+ # Ruby Uploader
2
+
3
+ This library provides a simple HTTP uploader based on chunks transfer. It supports handlers,
4
+ useful to make custom request configuration and to read the progression of the file transfer.
5
+
6
+ ## Quickstart
7
+
8
+ First, install `ruby-uploader`
9
+
10
+ ```
11
+ gem install ruby-uploader
12
+ ```
13
+
14
+ `ruby-uploader` set the necessary headers and configure the request to enable chunk transfer.
15
+ Below, the most basic example do not require any configuration
16
+
17
+ ```ruby
18
+ require 'ruby-uploader/uploader'
19
+
20
+ uploader = Uploader::Upload.new(URI('https://server/path/to/upload'), 'myfile.bin')
21
+
22
+ uploader.execute
23
+ ```
24
+
25
+ Optionally, headers can be set using a Hash parameter
26
+
27
+ ```ruby
28
+ uploader = Uploader::Upload.new(URI('https://server/path/to/upload'), 'myfile.bin', { 'custom-header' => 'value' })
29
+
30
+ uploader.execute
31
+ ```
32
+
33
+ For more configuration capabilities, see the Handlers section
34
+
35
+ ## Handlers
36
+
37
+ `ruby-uploader` support handlers at four different steps of the upload request process
38
+ * Before the request is fired
39
+ * Before each chunk is sent
40
+ * After each chunk has been sent
41
+ * After the HTTP response is received
42
+
43
+ Set a handler is done usine the method `add_handler` on the `Upload` object. several handlers
44
+ can be add on the uploader, even several of the same type.
45
+
46
+ ### Add a `:before` handler
47
+
48
+ This handler is triggered before the request is fired. It give access to the request object
49
+ which is an instance of type `Net::HTTPRequest` from the `net/http` standard API.
50
+
51
+ ```ruby
52
+ class BeforeRequest
53
+ def execute(request)
54
+ ...
55
+ end
56
+ end
57
+
58
+ uploader.add_handler :before, BeforeRequest.new
59
+ ```
60
+
61
+ ### Add a `:before_chunk` handler
62
+
63
+ This handler is triggered for each chunk, before it is sent to the server. It give access to the
64
+ following information :
65
+ * `chunk` - the chunk of data
66
+ * `count` - the number of the chunk (first chunk is `0`)
67
+ * `total_count` - total number of chunks to transfer
68
+ * `content_length` - the value of the corresponding HTTP header
69
+
70
+ ```ruby
71
+ class BeforeChunk
72
+ def execute(chunk, count, total_count, content_length)
73
+ ...
74
+ end
75
+ end
76
+
77
+ uploader.add_handler :before_chunk, BeforeChunk.new
78
+ ```
79
+
80
+ ### Add a `:after_chunk` handler
81
+
82
+ This handler is triggered for each chunk, after it has been sent to the server. Its structure is
83
+ identical to the one of the `before_chunk` handler
84
+
85
+ ```ruby
86
+ class AfterChunk
87
+ def execute(chunk, count, total_count, content_length)
88
+ ...
89
+ end
90
+ end
91
+
92
+ uploader.add_handler :after_chunk, AfterChunk.new
93
+ ```
94
+
95
+ ### Add a `:after` handler
96
+
97
+ This handler is triggered after the response is received for the server. It give access to the
98
+ response object which is an instance of type `Net::HTTPResponse` from the `net/http` standard API.
99
+
100
+ ```ruby
101
+ class AfterRequest
102
+ def execute(response)
103
+ ...
104
+ end
105
+ end
106
+
107
+ uploader.add_handler :after, AfterRequest.new
108
+ ```
@@ -0,0 +1,8 @@
1
+ require 'rubygems'
2
+ require 'bundler/setup'
3
+ require 'rubocop/rake_task'
4
+
5
+ Bundler::GemHelper.install_tasks
6
+ RuboCop::RakeTask.new
7
+
8
+ task default: %w(rubocop)
@@ -0,0 +1,111 @@
1
+ require 'net/http'
2
+ require 'uri'
3
+
4
+ module Uploader
5
+ class Upload
6
+ def initialize(url, path, headers = nil)
7
+ @url = url
8
+ @headers = headers
9
+ @path = path
10
+ @response = nil
11
+ @handlers = {
12
+ before: [],
13
+ after: [],
14
+ before_chunk: [],
15
+ after_chunk: []
16
+ }
17
+ end
18
+
19
+ def execute
20
+ Net::HTTP.start(@url.host, @url.port, use_ssl: @url.scheme == 'https') do |http|
21
+
22
+ headers = @headers ? default_headers.merge(@headers) : default_headers
23
+
24
+ request = Put.new(@url, headers, @handlers).tap do |r|
25
+ r.body_stream = File.open(@path)
26
+ end
27
+
28
+ @handlers[:before].each do |handler|
29
+ handler.execute request
30
+ end
31
+
32
+ @response = http.request(request)
33
+
34
+ @handlers[:after].each do |handler|
35
+ handler.execute @response
36
+ end
37
+
38
+ @response
39
+ end
40
+ end
41
+
42
+ def add_handler(phase, handler)
43
+ fail "Handler phase #{phase} does not exists" unless @handlers.key? phase
44
+ @handlers[phase] << handler
45
+ end
46
+
47
+ private
48
+
49
+ def default_headers
50
+ {
51
+ 'Content-Type' => 'application/octet-stream',
52
+ 'Content-Length' => File.stat(@path).size.to_s,
53
+ 'Transfer-Encoding' => 'chunked'
54
+ }
55
+ end
56
+
57
+ class Put < Net::HTTP::Put
58
+ def initialize(path, headers, handlers)
59
+ @handlers = handlers
60
+ super path, headers
61
+ end
62
+
63
+ private
64
+
65
+ def send_request_with_body_stream(sock, ver, path, f)
66
+ write_header sock, ver, path
67
+ wait_for_continue sock, ver if sock.continue_timeout
68
+ chunker = Chunker.new(sock, self['Content-Length'], @handlers)
69
+ IO.copy_stream(f, chunker)
70
+ chunker.finish
71
+ end
72
+
73
+ class Chunker
74
+ def initialize(sock, content_length, handlers)
75
+ @sock = sock
76
+ @prev = nil
77
+ @count = 0
78
+ @total_count = nil
79
+ @content_length = content_length.to_i
80
+ @handlers = handlers
81
+ end
82
+
83
+ def write(buf)
84
+ @total_count = @content_length / buf.bytesize.to_i if @total_count.nil?
85
+
86
+ @handlers[:before_chunk].each do |handler|
87
+ handler.execute buf, @count, @total_count, @content_length
88
+ end
89
+
90
+ puts "#{@count} / #{@total_count}"
91
+
92
+ @sock.write("#{buf.bytesize.to_s(16)}\r\n")
93
+ rv = @sock.write(buf)
94
+ @sock.write("\r\n")
95
+
96
+ @count += 1
97
+
98
+ @handlers[:after_chunk].each do |handler|
99
+ handler.execute buf, @count, @total_count, @content_length
100
+ end
101
+
102
+ rv
103
+ end
104
+
105
+ def finish
106
+ @sock.write("0\r\n\r\n")
107
+ end
108
+ end
109
+ end
110
+ end
111
+ end
@@ -0,0 +1,3 @@
1
+ module Uploader
2
+ VERSION = '0.1.0'
3
+ end
@@ -0,0 +1,16 @@
1
+ lib = File.expand_path('../lib', __FILE__)
2
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
3
+ require 'ruby-uploader/version'
4
+
5
+ Gem::Specification.new do |gem|
6
+ gem.name = 'ruby-uploader'
7
+ gem.version = Uploader::VERSION
8
+ gem.authors = ['Guillaume Giamarchi']
9
+ gem.email = ['guillaume.giamarchi@gmail.com']
10
+ gem.licenses = ['MIT']
11
+ gem.description = 'Ruby HTTP chunked uploader with transfert progress'
12
+ gem.summary = 'Ruby HTTP chunked uploader with transfert progress'
13
+ gem.homepage = 'https://github.com/ggiamarchi/ruby-uploader'
14
+ gem.files = `git ls-files`.split($INPUT_RECORD_SEPARATOR)
15
+ gem.require_paths = ['lib']
16
+ end
metadata ADDED
@@ -0,0 +1,53 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: ruby-uploader
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Guillaume Giamarchi
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-11-28 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description: Ruby HTTP chunked uploader with transfert progress
14
+ email:
15
+ - guillaume.giamarchi@gmail.com
16
+ executables: []
17
+ extensions: []
18
+ extra_rdoc_files: []
19
+ files:
20
+ - .gitignore
21
+ - .rubocop.yml
22
+ - Gemfile
23
+ - LICENSE.txt
24
+ - README.md
25
+ - Rakefile
26
+ - lib/ruby-uploader/uploader.rb
27
+ - lib/ruby-uploader/version.rb
28
+ - ruby-uploader.gemspec
29
+ homepage: https://github.com/ggiamarchi/ruby-uploader
30
+ licenses:
31
+ - MIT
32
+ metadata: {}
33
+ post_install_message:
34
+ rdoc_options: []
35
+ require_paths:
36
+ - lib
37
+ required_ruby_version: !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - '>='
40
+ - !ruby/object:Gem::Version
41
+ version: '0'
42
+ required_rubygems_version: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - '>='
45
+ - !ruby/object:Gem::Version
46
+ version: '0'
47
+ requirements: []
48
+ rubyforge_project:
49
+ rubygems_version: 2.0.14
50
+ signing_key:
51
+ specification_version: 4
52
+ summary: Ruby HTTP chunked uploader with transfert progress
53
+ test_files: []