ruby-uploader 0.1.0 → 0.2.0beta1
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/.gitignore +2 -0
- data/.rubocop.yml +6 -0
- data/.travis.yml +9 -0
- data/Gemfile +4 -0
- data/README.md +62 -4
- data/lib/ruby-uploader/put.rb +56 -0
- data/lib/ruby-uploader/upload.rb +57 -0
- data/lib/ruby-uploader/version.rb +1 -1
- data/lib/ruby-uploader.rb +1 -0
- data/ruby-uploader.gemspec +2 -2
- data/samples/upload_progressbar.rb +42 -0
- metadata +11 -7
- data/lib/ruby-uploader/uploader.rb +0 -111
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: fd101106d2a196a4187ee88b081104e82a89fcbf
|
4
|
+
data.tar.gz: fa919f1520c308250e993ae9e819e74a8c0165a8
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5b035118f2a4f99eb92183303e33ed4a8f2562a5ac0965829428c7f6297f34eb1884f3a6d40bb0af5e1f21168e08563a7d51f0ebb1756be357b9f3c9789e9e20
|
7
|
+
data.tar.gz: 9df18c686fca68a7522c3e663246b514a414091f8e7c2e06514d057b73060b9cf64608af9b192523dceae9abf90fcbdb23c499692c7988f879aad2fcd4a1eccf
|
data/.rubocop.yml
CHANGED
data/.travis.yml
ADDED
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -1,5 +1,8 @@
|
|
1
1
|
# Ruby Uploader
|
2
2
|
|
3
|
+
[](https://travis-ci.org/ggiamarchi/ruby-uploader)
|
4
|
+
[](http://badge.fury.io/rb/ruby-uploader)
|
5
|
+
|
3
6
|
This library provides a simple HTTP uploader based on chunks transfer. It supports handlers,
|
4
7
|
useful to make custom request configuration and to read the progression of the file transfer.
|
5
8
|
|
@@ -15,19 +18,27 @@ gem install ruby-uploader
|
|
15
18
|
Below, the most basic example do not require any configuration
|
16
19
|
|
17
20
|
```ruby
|
18
|
-
require 'ruby-uploader
|
21
|
+
require 'ruby-uploader'
|
19
22
|
|
20
23
|
uploader = Uploader::Upload.new(URI('https://server/path/to/upload'), 'myfile.bin')
|
21
24
|
|
22
25
|
uploader.execute
|
23
26
|
```
|
24
27
|
|
25
|
-
|
28
|
+
or with the more user friendly block syntax
|
26
29
|
|
27
30
|
```ruby
|
28
|
-
|
31
|
+
Uploader::Upload.new(URI('https://server/path/to/upload'), 'myfile.bin') do
|
32
|
+
execute
|
33
|
+
end
|
34
|
+
```
|
29
35
|
|
30
|
-
|
36
|
+
Optionally, headers can be set using a Hash parameter
|
37
|
+
|
38
|
+
```ruby
|
39
|
+
Uploader::Upload.new(URI('https://server/path/to/upload'), 'myfile.bin', { 'custom-header' => 'value' }) do
|
40
|
+
execute
|
41
|
+
end
|
31
42
|
```
|
32
43
|
|
33
44
|
For more configuration capabilities, see the Handlers section
|
@@ -106,3 +117,50 @@ end
|
|
106
117
|
|
107
118
|
uploader.add_handler :after, AfterRequest.new
|
108
119
|
```
|
120
|
+
|
121
|
+
## Putting all together
|
122
|
+
|
123
|
+
An uploader with one handler of each kind that just do log.
|
124
|
+
|
125
|
+
```ruby
|
126
|
+
require 'ruby-uploader'
|
127
|
+
require 'logger'
|
128
|
+
|
129
|
+
class Handler
|
130
|
+
def initialize
|
131
|
+
@logger = Logger.new(STDOUT)
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
class BeforeRequest < Handler
|
136
|
+
def execute(request)
|
137
|
+
@logger.info('start processing request')
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
class AfterResponse < Handler
|
142
|
+
def execute(response)
|
143
|
+
@logger.info('finished processing request')
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
class BeforeChunk < Handler
|
148
|
+
def execute(buf, count, total_count, content_length)
|
149
|
+
puts "start processing chunk #{count} of #{total_count}"
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
class AfterChunk < Handler
|
154
|
+
def execute(buf, count, total_count, content_length)
|
155
|
+
puts "finished processing chunk #{count} of #{total_count}"
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
Uploader::Upload.new(URI('https://server/path/to/upload'), 'myfile.bin') do
|
160
|
+
add_handler :before, BeforeRequest.new
|
161
|
+
add_handler :after, AfterResponse.new
|
162
|
+
add_handler :before_chunk, BeforeChunk.new
|
163
|
+
add_handler :after_chunk, AfterChunk.new
|
164
|
+
execute
|
165
|
+
end
|
166
|
+
```
|
@@ -0,0 +1,56 @@
|
|
1
|
+
require 'net/http'
|
2
|
+
require 'uri'
|
3
|
+
|
4
|
+
module Uploader
|
5
|
+
class Put < Net::HTTP::Put
|
6
|
+
def initialize(path, headers, handlers)
|
7
|
+
@handlers = handlers
|
8
|
+
super path, headers
|
9
|
+
end
|
10
|
+
|
11
|
+
private
|
12
|
+
|
13
|
+
def send_request_with_body_stream(sock, ver, path, f)
|
14
|
+
write_header sock, ver, path
|
15
|
+
wait_for_continue sock, ver if sock.continue_timeout
|
16
|
+
chunker = Chunker.new(sock, self['Content-Length'], @handlers)
|
17
|
+
IO.copy_stream(f, chunker)
|
18
|
+
chunker.finish
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
class Chunker
|
23
|
+
def initialize(sock, content_length, handlers)
|
24
|
+
@sock = sock
|
25
|
+
@prev = nil
|
26
|
+
@count = 0
|
27
|
+
@total_count = nil
|
28
|
+
@content_length = content_length.to_i
|
29
|
+
@handlers = handlers
|
30
|
+
end
|
31
|
+
|
32
|
+
def write(buf)
|
33
|
+
@total_count = @content_length / buf.bytesize.to_i if @total_count.nil?
|
34
|
+
|
35
|
+
@handlers[:before_chunk].each do |handler|
|
36
|
+
handler.execute buf, @count, @total_count, @content_length
|
37
|
+
end
|
38
|
+
|
39
|
+
@sock.write("#{buf.bytesize.to_s(16)}\r\n")
|
40
|
+
rv = @sock.write(buf)
|
41
|
+
@sock.write("\r\n")
|
42
|
+
|
43
|
+
@handlers[:after_chunk].each do |handler|
|
44
|
+
handler.execute buf, @count, @total_count, @content_length
|
45
|
+
end
|
46
|
+
|
47
|
+
@count += 1
|
48
|
+
|
49
|
+
rv
|
50
|
+
end
|
51
|
+
|
52
|
+
def finish
|
53
|
+
@sock.write("0\r\n\r\n")
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
require 'ruby-uploader/put'
|
2
|
+
|
3
|
+
module Uploader
|
4
|
+
class Upload
|
5
|
+
def initialize(url, path, headers = nil, &block)
|
6
|
+
@url = url
|
7
|
+
@headers = headers
|
8
|
+
@path = path
|
9
|
+
@response = nil
|
10
|
+
@handlers = {
|
11
|
+
before: [],
|
12
|
+
after: [],
|
13
|
+
before_chunk: [],
|
14
|
+
after_chunk: []
|
15
|
+
}
|
16
|
+
instance_eval(&block) if block_given?
|
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
|
+
end
|
57
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
require 'ruby-uploader/upload'
|
data/ruby-uploader.gemspec
CHANGED
@@ -8,8 +8,8 @@ Gem::Specification.new do |gem|
|
|
8
8
|
gem.authors = ['Guillaume Giamarchi']
|
9
9
|
gem.email = ['guillaume.giamarchi@gmail.com']
|
10
10
|
gem.licenses = ['MIT']
|
11
|
-
gem.description = 'Ruby HTTP chunked uploader with
|
12
|
-
gem.summary = 'Ruby HTTP chunked uploader with
|
11
|
+
gem.description = 'Ruby HTTP chunked uploader with transfer progress'
|
12
|
+
gem.summary = 'Ruby HTTP chunked uploader with transfer progress'
|
13
13
|
gem.homepage = 'https://github.com/ggiamarchi/ruby-uploader'
|
14
14
|
gem.files = `git ls-files`.split($INPUT_RECORD_SEPARATOR)
|
15
15
|
gem.require_paths = ['lib']
|
@@ -0,0 +1,42 @@
|
|
1
|
+
#
|
2
|
+
# Sample upload code that shows a progressbar
|
3
|
+
# using the library 'ruby-progressbar'
|
4
|
+
#
|
5
|
+
# Usage:
|
6
|
+
# ruby upload_progressbar.rb http://server file_to_upload
|
7
|
+
#
|
8
|
+
|
9
|
+
url = ARGV[0]
|
10
|
+
path = ARGV[1]
|
11
|
+
|
12
|
+
require 'ruby-uploader'
|
13
|
+
require 'logger'
|
14
|
+
require 'ruby-progressbar'
|
15
|
+
|
16
|
+
class BeforeChunk
|
17
|
+
def initialize(holder)
|
18
|
+
@holder = holder
|
19
|
+
end
|
20
|
+
|
21
|
+
def execute(_, count, total_count, _)
|
22
|
+
return unless count == 0
|
23
|
+
@holder[:progressbar] = ProgressBar.create(starting_at: 0, total: total_count + 1)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
class AfterChunk
|
28
|
+
def initialize(holder)
|
29
|
+
@holder = holder
|
30
|
+
end
|
31
|
+
|
32
|
+
def execute(_, _, _, _)
|
33
|
+
@holder[:progressbar].increment
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
Uploader::Upload.new(URI(url), path) do
|
38
|
+
holder = {}
|
39
|
+
add_handler :before_chunk, BeforeChunk.new(holder)
|
40
|
+
add_handler :after_chunk, AfterChunk.new(holder)
|
41
|
+
execute
|
42
|
+
end
|
metadata
CHANGED
@@ -1,16 +1,16 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ruby-uploader
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0beta1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Guillaume Giamarchi
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-11-
|
11
|
+
date: 2014-11-30 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
|
-
description: Ruby HTTP chunked uploader with
|
13
|
+
description: Ruby HTTP chunked uploader with transfer progress
|
14
14
|
email:
|
15
15
|
- guillaume.giamarchi@gmail.com
|
16
16
|
executables: []
|
@@ -19,13 +19,17 @@ extra_rdoc_files: []
|
|
19
19
|
files:
|
20
20
|
- .gitignore
|
21
21
|
- .rubocop.yml
|
22
|
+
- .travis.yml
|
22
23
|
- Gemfile
|
23
24
|
- LICENSE.txt
|
24
25
|
- README.md
|
25
26
|
- Rakefile
|
26
|
-
- lib/ruby-uploader
|
27
|
+
- lib/ruby-uploader.rb
|
28
|
+
- lib/ruby-uploader/put.rb
|
29
|
+
- lib/ruby-uploader/upload.rb
|
27
30
|
- lib/ruby-uploader/version.rb
|
28
31
|
- ruby-uploader.gemspec
|
32
|
+
- samples/upload_progressbar.rb
|
29
33
|
homepage: https://github.com/ggiamarchi/ruby-uploader
|
30
34
|
licenses:
|
31
35
|
- MIT
|
@@ -41,13 +45,13 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
41
45
|
version: '0'
|
42
46
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
43
47
|
requirements:
|
44
|
-
- - '
|
48
|
+
- - '>'
|
45
49
|
- !ruby/object:Gem::Version
|
46
|
-
version:
|
50
|
+
version: 1.3.1
|
47
51
|
requirements: []
|
48
52
|
rubyforge_project:
|
49
53
|
rubygems_version: 2.0.14
|
50
54
|
signing_key:
|
51
55
|
specification_version: 4
|
52
|
-
summary: Ruby HTTP chunked uploader with
|
56
|
+
summary: Ruby HTTP chunked uploader with transfer progress
|
53
57
|
test_files: []
|
@@ -1,111 +0,0 @@
|
|
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
|