microget 1.0.0 → 1.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.
- checksums.yaml +4 -4
- data/Gemfile +1 -1
- data/lib/microget.rb +13 -8
- data/lib/microget/server_runner.rb +60 -0
- data/microget.gemspec +72 -0
- data/spec/helper.rb +0 -1
- data/spec/microget_with_real_server_spec.rb +4 -2
- data/spec/streaming_app.ru +4 -0
- metadata +12 -6
- data/spec/server_runner.rb +0 -57
- data/spec/spec_helper.rb +0 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 10904aa7598a374362dd5086d3b033a8f5a296a1
|
4
|
+
data.tar.gz: f61403282080b0722189d571436a8c6dfa89189a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 141b9588147336dc6656f8c49ab6c3c438ea551baaec13cfd2edab42509406ba4ca60fd6aaf37e8b0f37722c220daf4d7b6a04b4bae567a1bba70bf19caec793
|
7
|
+
data.tar.gz: 8a2b5cd9b07e850f23ed17f5990a20054193c9effcee6ec66983c6758f615dc5b9c96d6534aa165f7d9a9cfc1dd52816c816160a4177406a19c7c73e2ae2c895
|
data/Gemfile
CHANGED
data/lib/microget.rb
CHANGED
@@ -3,7 +3,9 @@ require 'socket'
|
|
3
3
|
|
4
4
|
# An no-nonsense, pedal-to-the-metal unbuffered HTTP streaming client for doing GETs of large bodies, fast.
|
5
5
|
module Microget
|
6
|
-
|
6
|
+
autoload :ServerRunner, File.dirname(__FILE__) + '/microget/server_runner'
|
7
|
+
|
8
|
+
VERSION = '1.1.0'
|
7
9
|
|
8
10
|
extend self
|
9
11
|
|
@@ -26,6 +28,8 @@ module Microget
|
|
26
28
|
raise ('Only plain HTTP is supported (%s)' % uri) unless uri.scheme == 'http'
|
27
29
|
raise "Unknown host" unless uri.host
|
28
30
|
|
31
|
+
# Some reading on what might be usable here:
|
32
|
+
# http://www.mikeperham.com/2009/03/15/socket-timeouts-in-ruby/
|
29
33
|
socket = TCPSocket.open(uri.host, uri.port || 80)
|
30
34
|
socket.write("GET #{uri.request_uri} HTTP/1.1\r\n")
|
31
35
|
|
@@ -65,24 +69,25 @@ module Microget
|
|
65
69
|
def perform_get(uri, request_headers: {}, chunk_size: 1024 * 1024 * 5)
|
66
70
|
status_code, header_hash, socket = get_status_headers_and_body_socket(uri, request_headers: request_headers)
|
67
71
|
body_bytes_received = 0
|
72
|
+
|
73
|
+
# Yield the status and headers once with an empty response
|
74
|
+
# so that the client can bail out of the request even before the body
|
75
|
+
# starts to arrive
|
76
|
+
return body_bytes_received unless yield(status_code, header_hash, '')
|
77
|
+
|
68
78
|
# ...and then just read the body, without any buffering, using a non-blocking read
|
69
79
|
while !socket.eof?
|
70
80
|
begin
|
71
81
|
data = socket.read_nonblock(chunk_size)
|
72
82
|
body_bytes_received += data.bytesize
|
73
|
-
|
83
|
+
continue_reading = yield(status_code, header_hash, data)
|
84
|
+
return body_bytes_received unless continue_reading
|
74
85
|
rescue IO::WaitReadable
|
75
86
|
IO.select([socket], [], SOCKET_TIMEOUT)
|
76
87
|
retry
|
77
88
|
end
|
78
89
|
end
|
79
90
|
|
80
|
-
# Yield the status and headers once with an empty response
|
81
|
-
# so that the client gets at least something.
|
82
|
-
if body_bytes_received.zero?
|
83
|
-
yield(status_code, header_hash, '')
|
84
|
-
end
|
85
|
-
|
86
91
|
body_bytes_received
|
87
92
|
ensure
|
88
93
|
socket.close if socket && !socket.closed?
|
@@ -0,0 +1,60 @@
|
|
1
|
+
require 'net/http'
|
2
|
+
|
3
|
+
# A simplistic runner for external web servers within a separate process.
|
4
|
+
class Microget::ServerRunner < Struct.new(:name, :command, :port, :rackup_file_path)
|
5
|
+
SHOULD_CONNECT_WITHIN = 2
|
6
|
+
|
7
|
+
def command
|
8
|
+
super % [port, rackup_file_path]
|
9
|
+
end
|
10
|
+
|
11
|
+
def start!
|
12
|
+
# Boot Puma in a forked process
|
13
|
+
@pid = fork do
|
14
|
+
$stderr.puts "Spinning up with #{command.inspect}"
|
15
|
+
|
16
|
+
# Do not pollute the test suite output with the Puma logs,
|
17
|
+
# save the stuff to logfiles instead
|
18
|
+
$stdout.reopen(File.open('server_runner_%s_stdout.log' % name, 'a'))
|
19
|
+
$stderr.reopen(File.open('server_runner_%s_stderr.log' % name, 'a'))
|
20
|
+
|
21
|
+
# Since we have to do with timing tolerances, having the output drip in ASAP is useful
|
22
|
+
$stdout.sync = true
|
23
|
+
$stderr.sync = true
|
24
|
+
exec(command)
|
25
|
+
end
|
26
|
+
|
27
|
+
Thread.abort_on_exception = true
|
28
|
+
|
29
|
+
t = Time.now
|
30
|
+
# Wait for Puma to be online, poll the alive URL until it stops responding
|
31
|
+
loop do
|
32
|
+
sleep 0.5
|
33
|
+
begin
|
34
|
+
alive_check_url = "http://0.0.0.0:%d/" % port
|
35
|
+
response = Net::HTTP.get_response(URI(alive_check_url))
|
36
|
+
@running = true
|
37
|
+
break
|
38
|
+
rescue Errno::ECONNREFUSED
|
39
|
+
if (Time.now - t) > SHOULD_CONNECT_WITHIN # Timeout when starting
|
40
|
+
raise "Could not get the server started in 2 seconds, something might be misconfigured"
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
trap("TERM") { stop! }
|
46
|
+
end
|
47
|
+
|
48
|
+
def running?
|
49
|
+
!!@running
|
50
|
+
end
|
51
|
+
|
52
|
+
def stop!
|
53
|
+
return unless @pid
|
54
|
+
|
55
|
+
# Tell the webserver to quit, twice (we do not care if there are running responses)
|
56
|
+
%W( TERM TERM KILL ).each {|sig| Process.kill(sig, @pid); sleep 0.5 }
|
57
|
+
@pid = nil
|
58
|
+
@running = false
|
59
|
+
end
|
60
|
+
end
|
data/microget.gemspec
ADDED
@@ -0,0 +1,72 @@
|
|
1
|
+
# Generated by jeweler
|
2
|
+
# DO NOT EDIT THIS FILE DIRECTLY
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
|
4
|
+
# -*- encoding: utf-8 -*-
|
5
|
+
# stub: microget 1.1.0 ruby lib
|
6
|
+
|
7
|
+
Gem::Specification.new do |s|
|
8
|
+
s.name = "microget"
|
9
|
+
s.version = "1.1.0"
|
10
|
+
|
11
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
12
|
+
s.require_paths = ["lib"]
|
13
|
+
s.authors = ["Julik Tarkhanov"]
|
14
|
+
s.date = "2015-11-04"
|
15
|
+
s.description = "Pedal-to-the-metal HTTP client for GET requests"
|
16
|
+
s.email = "me@julik.nl"
|
17
|
+
s.extra_rdoc_files = [
|
18
|
+
"LICENSE.txt",
|
19
|
+
"README.md"
|
20
|
+
]
|
21
|
+
s.files = [
|
22
|
+
".document",
|
23
|
+
".rspec",
|
24
|
+
".yardopts",
|
25
|
+
"Gemfile",
|
26
|
+
"LICENSE.txt",
|
27
|
+
"README.md",
|
28
|
+
"Rakefile",
|
29
|
+
"lib/microget.rb",
|
30
|
+
"lib/microget/server_runner.rb",
|
31
|
+
"microget.gemspec",
|
32
|
+
"spec/helper.rb",
|
33
|
+
"spec/microget_spec.rb",
|
34
|
+
"spec/microget_with_real_server_spec.rb",
|
35
|
+
"spec/streaming_app.ru"
|
36
|
+
]
|
37
|
+
s.homepage = "http://github.com/julik/microget"
|
38
|
+
s.licenses = ["MIT"]
|
39
|
+
s.rubygems_version = "2.2.2"
|
40
|
+
s.summary = "Designed for slow and/or large response bodies"
|
41
|
+
|
42
|
+
if s.respond_to? :specification_version then
|
43
|
+
s.specification_version = 4
|
44
|
+
|
45
|
+
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
46
|
+
s.add_development_dependency(%q<puma>, [">= 0"])
|
47
|
+
s.add_development_dependency(%q<yard>, [">= 0"])
|
48
|
+
s.add_development_dependency(%q<rspec>, ["< 3.3", "~> 3.2.0"])
|
49
|
+
s.add_development_dependency(%q<rdoc>, ["~> 3.12"])
|
50
|
+
s.add_development_dependency(%q<bundler>, ["~> 1.0"])
|
51
|
+
s.add_development_dependency(%q<jeweler>, ["~> 2.0.1"])
|
52
|
+
s.add_development_dependency(%q<simplecov>, [">= 0"])
|
53
|
+
else
|
54
|
+
s.add_dependency(%q<puma>, [">= 0"])
|
55
|
+
s.add_dependency(%q<yard>, [">= 0"])
|
56
|
+
s.add_dependency(%q<rspec>, ["< 3.3", "~> 3.2.0"])
|
57
|
+
s.add_dependency(%q<rdoc>, ["~> 3.12"])
|
58
|
+
s.add_dependency(%q<bundler>, ["~> 1.0"])
|
59
|
+
s.add_dependency(%q<jeweler>, ["~> 2.0.1"])
|
60
|
+
s.add_dependency(%q<simplecov>, [">= 0"])
|
61
|
+
end
|
62
|
+
else
|
63
|
+
s.add_dependency(%q<puma>, [">= 0"])
|
64
|
+
s.add_dependency(%q<yard>, [">= 0"])
|
65
|
+
s.add_dependency(%q<rspec>, ["< 3.3", "~> 3.2.0"])
|
66
|
+
s.add_dependency(%q<rdoc>, ["~> 3.12"])
|
67
|
+
s.add_dependency(%q<bundler>, ["~> 1.0"])
|
68
|
+
s.add_dependency(%q<jeweler>, ["~> 2.0.1"])
|
69
|
+
s.add_dependency(%q<simplecov>, [">= 0"])
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
data/spec/helper.rb
CHANGED
@@ -3,9 +3,8 @@ require_relative 'helper'
|
|
3
3
|
describe "Microget running against a real server" do
|
4
4
|
before :all do
|
5
5
|
rack_app = File.expand_path(File.join(__dir__, 'streaming_app.ru'))
|
6
|
-
@server = ServerRunner.new("bundle exec puma --port %d %s", 9393, rack_app)
|
6
|
+
@server = Microget::ServerRunner.new(:puma, "bundle exec puma --port %d %s", 9393, rack_app)
|
7
7
|
@server.start!
|
8
|
-
sleep 0.5 until @server.running?
|
9
8
|
end
|
10
9
|
|
11
10
|
after :all do
|
@@ -49,6 +48,9 @@ describe "Microget running against a real server" do
|
|
49
48
|
t = Time.now
|
50
49
|
end
|
51
50
|
|
51
|
+
first_chunk_and_delta = time_deltas_and_chunks.shift
|
52
|
+
expect(first_chunk_and_delta[1]).to be_empty # First chunk is empty to allow header/status checks
|
53
|
+
|
52
54
|
time_deltas_and_chunks.each do |(delta, chunk_contents)|
|
53
55
|
expect(chunk_contents).to include('Message number ')
|
54
56
|
expect(delta).to be_within(0.2).of(1.0) # The server "drips" down one message every second, approximately
|
data/spec/streaming_app.ru
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: microget
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Julik Tarkhanov
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-11-
|
11
|
+
date: 2015-11-04 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: puma
|
@@ -42,16 +42,22 @@ dependencies:
|
|
42
42
|
name: rspec
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
44
44
|
requirements:
|
45
|
+
- - "<"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '3.3'
|
45
48
|
- - "~>"
|
46
49
|
- !ruby/object:Gem::Version
|
47
|
-
version: 3.
|
50
|
+
version: 3.2.0
|
48
51
|
type: :development
|
49
52
|
prerelease: false
|
50
53
|
version_requirements: !ruby/object:Gem::Requirement
|
51
54
|
requirements:
|
55
|
+
- - "<"
|
56
|
+
- !ruby/object:Gem::Version
|
57
|
+
version: '3.3'
|
52
58
|
- - "~>"
|
53
59
|
- !ruby/object:Gem::Version
|
54
|
-
version: 3.
|
60
|
+
version: 3.2.0
|
55
61
|
- !ruby/object:Gem::Dependency
|
56
62
|
name: rdoc
|
57
63
|
requirement: !ruby/object:Gem::Requirement
|
@@ -124,11 +130,11 @@ files:
|
|
124
130
|
- README.md
|
125
131
|
- Rakefile
|
126
132
|
- lib/microget.rb
|
133
|
+
- lib/microget/server_runner.rb
|
134
|
+
- microget.gemspec
|
127
135
|
- spec/helper.rb
|
128
136
|
- spec/microget_spec.rb
|
129
137
|
- spec/microget_with_real_server_spec.rb
|
130
|
-
- spec/server_runner.rb
|
131
|
-
- spec/spec_helper.rb
|
132
138
|
- spec/streaming_app.ru
|
133
139
|
homepage: http://github.com/julik/microget
|
134
140
|
licenses:
|
data/spec/server_runner.rb
DELETED
@@ -1,57 +0,0 @@
|
|
1
|
-
require 'net/http'
|
2
|
-
|
3
|
-
class ServerRunner < Struct.new(:command, :port, :rackup_file_path)
|
4
|
-
def command
|
5
|
-
super % [port, rackup_file_path]
|
6
|
-
end
|
7
|
-
|
8
|
-
def start!
|
9
|
-
# Boot Puma in a forked process
|
10
|
-
@pid = fork do
|
11
|
-
$stderr.puts "Spinning up with #{command.inspect}"
|
12
|
-
# Do not pollute the RSpec output with the Puma logs,
|
13
|
-
# save the stuff to logfiles instead
|
14
|
-
# $stdout.reopen(File.open('server_runner_stdout.log' % name, 'a'))
|
15
|
-
# $stderr.reopen(File.open('server_runner_stderr.log' % name, 'a'))
|
16
|
-
|
17
|
-
# Since we have to do with timing tolerances, having the output drip in ASAP is useful
|
18
|
-
$stdout.sync = true
|
19
|
-
$stderr.sync = true
|
20
|
-
exec(command)
|
21
|
-
end
|
22
|
-
|
23
|
-
Thread.abort_on_exception = true
|
24
|
-
|
25
|
-
Thread.new do
|
26
|
-
t = Time.now
|
27
|
-
# Wait for Puma to be online, poll the alive URL until it stops responding
|
28
|
-
loop do
|
29
|
-
sleep 0.5
|
30
|
-
begin
|
31
|
-
alive_check_url = "http://0.0.0.0:%d/alive" % port
|
32
|
-
response = Net::HTTP.get_response(URI(alive_check_url))
|
33
|
-
@running = true
|
34
|
-
break
|
35
|
-
rescue Errno::ECONNREFUSED
|
36
|
-
if Time.now - t > 2 # Timeout when starting
|
37
|
-
raise "Could not get the server started in 2 seconds, something might be misconfigured"
|
38
|
-
end
|
39
|
-
end
|
40
|
-
end
|
41
|
-
end
|
42
|
-
|
43
|
-
trap("TERM") { stop! }
|
44
|
-
end
|
45
|
-
|
46
|
-
def running?
|
47
|
-
!!@running
|
48
|
-
end
|
49
|
-
|
50
|
-
def stop!
|
51
|
-
return unless @pid
|
52
|
-
|
53
|
-
# Tell the webserver to quit, twice (we do not care if there are running responses)
|
54
|
-
%W( TERM TERM KILL ).each {|sig| Process.kill(sig, @pid); sleep 0.5 }
|
55
|
-
@pid = nil
|
56
|
-
end
|
57
|
-
end
|