rstreamor 0.2.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 +7 -0
- data/.gitignore +10 -0
- data/.rspec +2 -0
- data/.travis.yml +3 -0
- data/Gemfile +4 -0
- data/README.md +45 -0
- data/Rakefile +2 -0
- data/bin/console +14 -0
- data/bin/setup +7 -0
- data/lib/rstreamor.rb +8 -0
- data/lib/rstreamor/file.rb +22 -0
- data/lib/rstreamor/request.rb +39 -0
- data/lib/rstreamor/response.rb +34 -0
- data/lib/rstreamor/stream.rb +27 -0
- data/lib/rstreamor/version.rb +3 -0
- data/rstreamor.gemspec +32 -0
- metadata +108 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: b2917bc3f4ceb7e49d8bf2ce9a8a8a784800261e
|
4
|
+
data.tar.gz: bdaab2583015a8f27ccf380153131fd63292e19c
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 68af7208404956aa3790a5b348b2b1c64cb3110e8b1c4c0b56f3777b08166a1fb135a091669d87215b1e48b55fb8229c24fce12552a997d4decb7c7836bf9d61
|
7
|
+
data.tar.gz: 125a769788b7ce6018e6088aca988dc83df98d3a3045c4aca94f08aed404b9751ef7f7d3651af02f0fa9eae89f3c61873cf4a9750f462c7f7d95d3eeaba1e4ac
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/README.md
ADDED
@@ -0,0 +1,45 @@
|
|
1
|
+
# Rstreamor
|
2
|
+
Development in progress...
|
3
|
+
|
4
|
+
# Get Rstreamor
|
5
|
+
###### Directly from GitHub
|
6
|
+
```ruby
|
7
|
+
gem 'regressor', git: 'https://github.com/ndea/rstreamor.git', branch: 'master'
|
8
|
+
```
|
9
|
+
###### Rubygems
|
10
|
+
# Install
|
11
|
+
```ruby
|
12
|
+
bundle install
|
13
|
+
```
|
14
|
+
# Usage
|
15
|
+
Given you have a controller with a streaming action (here it's the show action) simply use following code:
|
16
|
+
```ruby
|
17
|
+
class VideosController < ApplicationController
|
18
|
+
include Rstreamor
|
19
|
+
def show
|
20
|
+
stream @resource.file
|
21
|
+
end
|
22
|
+
end
|
23
|
+
```
|
24
|
+
Please note that the file method of @resource is a mounted uploader of carrierwave.
|
25
|
+
|
26
|
+
Rstreamor takes care of the rest.
|
27
|
+
If you dont use Carrierwave as a file make sure your file has the following methods:
|
28
|
+
- #data
|
29
|
+
- #content_type
|
30
|
+
|
31
|
+
# What is a range request?
|
32
|
+
Byte serving is the process of sending only a portion of an HTTP/1.1 message from a server to a client. Byte serving begins when an HTTP server advertises its willingness to serve partial requests using the Accept-Ranges response header. A client then requests a specific part of a file from the server using the Range request header. If the range is valid, the server sends it to the client with a 206 Partial Content status code and a Content-Range header listing the range sent. Clients which request byte-serving might do so in cases in which a large file has been only partially delivered and a limited portion of the file is needed in a particular range. Byte Serving is therefore a method of bandwidth optimization. [Wikipedia](https://en.wikipedia.org/wiki/Byte_serving)
|
33
|
+
|
34
|
+
### HTML5 video / audio streaming
|
35
|
+
Consider you have a large video or audio file on your server which needs to be served partially to your client. You don't want to send the whole file in one response (unless you want to download the file). Instead the client needs only partial content which he can view and request other partial content if needed. Rstreamor provides this byte serving mechanism defined in HTTP/1.1.
|
36
|
+
|
37
|
+
###### Example
|
38
|
+
###### Limitations
|
39
|
+
# Contributing
|
40
|
+
|
41
|
+
1. Fork it ( https://github.com/ndea/regressor/fork )
|
42
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
43
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
44
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
45
|
+
5. Create a new Pull Request
|
data/Rakefile
ADDED
data/bin/console
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "bundler/setup"
|
4
|
+
require "rstreamor"
|
5
|
+
|
6
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
7
|
+
# with your gem easier. You can also use a different console, if you like.
|
8
|
+
|
9
|
+
# (If you use this, don't forget to add pry to your Gemfile!)
|
10
|
+
# require "pry"
|
11
|
+
# Pry.start
|
12
|
+
|
13
|
+
require "irb"
|
14
|
+
IRB.start
|
data/bin/setup
ADDED
data/lib/rstreamor.rb
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
module Rstreamor
|
2
|
+
class File
|
3
|
+
attr_accessor :file
|
4
|
+
|
5
|
+
def initialize(file)
|
6
|
+
self.file = file
|
7
|
+
end
|
8
|
+
|
9
|
+
def data
|
10
|
+
self.file.data
|
11
|
+
end
|
12
|
+
|
13
|
+
def content_type
|
14
|
+
self.file.content_type
|
15
|
+
end
|
16
|
+
|
17
|
+
def size
|
18
|
+
data.size
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
module Rstreamor
|
2
|
+
class Request
|
3
|
+
attr_accessor :request, :file
|
4
|
+
|
5
|
+
def initialize(request, file)
|
6
|
+
self.request = request
|
7
|
+
self.file = file
|
8
|
+
end
|
9
|
+
|
10
|
+
def ranges
|
11
|
+
self.request.headers['HTTP_RANGE'].gsub('bytes=', '').split('-')
|
12
|
+
end
|
13
|
+
|
14
|
+
def upper_bound
|
15
|
+
ranges[1] ? ranges[1].to_i : self.file.data.size
|
16
|
+
end
|
17
|
+
|
18
|
+
def lower_bound
|
19
|
+
ranges[0] ? ranges[0].to_i : 0
|
20
|
+
end
|
21
|
+
|
22
|
+
def range_header?
|
23
|
+
self.request.headers['HTTP_RANGE'].present?
|
24
|
+
end
|
25
|
+
|
26
|
+
def file_content_type
|
27
|
+
self.file.content_type
|
28
|
+
end
|
29
|
+
|
30
|
+
def slice_file
|
31
|
+
self.file.data.byteslice(lower_bound, upper_bound)
|
32
|
+
end
|
33
|
+
|
34
|
+
def file_size
|
35
|
+
self.file.size
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module Rstreamor
|
2
|
+
class Response
|
3
|
+
attr_accessor :request
|
4
|
+
|
5
|
+
def initialize(request)
|
6
|
+
self.request = request
|
7
|
+
end
|
8
|
+
|
9
|
+
def response_code
|
10
|
+
self.request.range_header? ? 206 : 200
|
11
|
+
end
|
12
|
+
|
13
|
+
def content_length
|
14
|
+
if self.request.range_header?
|
15
|
+
(self.request.upper_bound - self.request.lower_bound).to_s
|
16
|
+
else
|
17
|
+
self.request.file.data.size
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def content_range
|
22
|
+
"bytes #{self.request.lower_bound}-#{self.request.upper_bound - 1}/#{self.request.file.data.size}"
|
23
|
+
end
|
24
|
+
|
25
|
+
def accept_ranges
|
26
|
+
'bytes'
|
27
|
+
end
|
28
|
+
|
29
|
+
def cache_control
|
30
|
+
'no-cache'
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module Rstreamor
|
2
|
+
module Stream
|
3
|
+
def stream(file)
|
4
|
+
request_builder = Rstreamor::Request.new(request, file)
|
5
|
+
response_builder = Rstreamor::Response.new(request_builder)
|
6
|
+
set_response_header(request_builder, response_builder)
|
7
|
+
stream_file(request_builder, response_builder)
|
8
|
+
end
|
9
|
+
|
10
|
+
private
|
11
|
+
|
12
|
+
def stream_file(request_builder, response_builder)
|
13
|
+
content = request_builder.slice_file
|
14
|
+
send_data content, type: request_builder.file_content_type, disposition: 'inline', status: response_builder.response_code
|
15
|
+
end
|
16
|
+
|
17
|
+
def set_response_header(request_builder, response_builder)
|
18
|
+
response.headers['Content-Type'] = request_builder.file_content_type
|
19
|
+
response.headers['Content-Length'] = response_builder.content_length
|
20
|
+
if request_builder.range_header?
|
21
|
+
response.headers['Accept-Ranges'] = 'bytes'
|
22
|
+
response.headers['Cache-Control'] = 'no-cache'
|
23
|
+
response.headers['Content-Range'] = response_builder.content_range
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
data/rstreamor.gemspec
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'rstreamor/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = 'rstreamor'
|
8
|
+
spec.version = Rstreamor::VERSION
|
9
|
+
spec.authors = ['Erwin Schens']
|
10
|
+
spec.email = ['erwinschens@uni-koblenz.de']
|
11
|
+
|
12
|
+
spec.summary = %q{Stream files using HTTP range requests.}
|
13
|
+
spec.description = %q{
|
14
|
+
Rstreamor gives you the power to stream your files using the HTTP range requests defined in the HTTP/1.1.
|
15
|
+
Range requests are an optional feature of HTTP,
|
16
|
+
designed so that recipients not implementing this feature
|
17
|
+
(or not supporting it for the target resource) can respond as if
|
18
|
+
it is a normal GET request without impacting interoperability.
|
19
|
+
Partial responses are indicated by a distinct status code to not be mistaken for full responses by caches that might not implement the feature.
|
20
|
+
}
|
21
|
+
spec.homepage = 'https://github.com/ndea/rstreamor'
|
22
|
+
spec.license = 'MIT'
|
23
|
+
|
24
|
+
spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
25
|
+
spec.bindir = 'exe'
|
26
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
27
|
+
spec.require_paths = ['lib']
|
28
|
+
|
29
|
+
spec.add_development_dependency 'bundler', '~> 1.8'
|
30
|
+
spec.add_development_dependency 'rake', '~> 10.0'
|
31
|
+
spec.add_development_dependency 'rspec', '~> 3.3.0'
|
32
|
+
end
|
metadata
ADDED
@@ -0,0 +1,108 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: rstreamor
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.2.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Erwin Schens
|
8
|
+
autorequire:
|
9
|
+
bindir: exe
|
10
|
+
cert_chain: []
|
11
|
+
date: 2015-08-03 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.8'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.8'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '10.0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '10.0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rspec
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: 3.3.0
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: 3.3.0
|
55
|
+
description: "\n Rstreamor gives you the power to stream your
|
56
|
+
files using the HTTP range requests defined in the HTTP/1.1.\n Range
|
57
|
+
requests are an optional feature of HTTP,\n designed so that
|
58
|
+
recipients not implementing this feature\n (or not supporting
|
59
|
+
it for the target resource) can respond as if\n it is a normal
|
60
|
+
GET request without impacting interoperability.\n Partial
|
61
|
+
responses are indicated by a distinct status code to not be mistaken for full responses
|
62
|
+
by caches that might not implement the feature.\n "
|
63
|
+
email:
|
64
|
+
- erwinschens@uni-koblenz.de
|
65
|
+
executables: []
|
66
|
+
extensions: []
|
67
|
+
extra_rdoc_files: []
|
68
|
+
files:
|
69
|
+
- ".gitignore"
|
70
|
+
- ".rspec"
|
71
|
+
- ".travis.yml"
|
72
|
+
- Gemfile
|
73
|
+
- README.md
|
74
|
+
- Rakefile
|
75
|
+
- bin/console
|
76
|
+
- bin/setup
|
77
|
+
- lib/rstreamor.rb
|
78
|
+
- lib/rstreamor/file.rb
|
79
|
+
- lib/rstreamor/request.rb
|
80
|
+
- lib/rstreamor/response.rb
|
81
|
+
- lib/rstreamor/stream.rb
|
82
|
+
- lib/rstreamor/version.rb
|
83
|
+
- rstreamor.gemspec
|
84
|
+
homepage: https://github.com/ndea/rstreamor
|
85
|
+
licenses:
|
86
|
+
- MIT
|
87
|
+
metadata: {}
|
88
|
+
post_install_message:
|
89
|
+
rdoc_options: []
|
90
|
+
require_paths:
|
91
|
+
- lib
|
92
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - ">="
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0'
|
97
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
98
|
+
requirements:
|
99
|
+
- - ">="
|
100
|
+
- !ruby/object:Gem::Version
|
101
|
+
version: '0'
|
102
|
+
requirements: []
|
103
|
+
rubyforge_project:
|
104
|
+
rubygems_version: 2.4.6
|
105
|
+
signing_key:
|
106
|
+
specification_version: 4
|
107
|
+
summary: Stream files using HTTP range requests.
|
108
|
+
test_files: []
|