telestream_cloud 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/README.md +38 -29
- data/lib/telestream_cloud.rb +3 -1
- data/lib/telestream_cloud/parallel_uploader.rb +52 -0
- data/lib/telestream_cloud/upload_session.rb +26 -88
- data/lib/telestream_cloud/uploader.rb +123 -0
- data/lib/telestream_cloud/uploader/file_reader.rb +27 -0
- data/lib/telestream_cloud/version.rb +1 -1
- data/spec/uploader_spec.rb +143 -0
- data/telestream_cloud.gemspec +2 -2
- metadata +27 -22
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: bcd0c04f728a476514ec1af7312b4d3e27babfde
|
4
|
+
data.tar.gz: 253b327eea8a868994a8819b8bbd4b816061b182
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b71fa00a53c0b687bad6ae0ec2ce23b56a7ce8ef510211688985684321827f089cd76352c372b86a841a7999d57889c9f8479e71fae6e336b3a106eae46959aa
|
7
|
+
data.tar.gz: 1b0d873ec086449daa6057faf2b3b805b32bfa8c708fd76c08237718673db1cfd568b4074c201df123b283cd77dd91ec62106d3f6e8c6741652af294211293cd
|
data/README.md
CHANGED
@@ -17,17 +17,17 @@ TelestreamCloud gem provides an interface to access the [TelestreamCloud](http:/
|
|
17
17
|
You can just set the default Panda adapter if you are not happy with the current one.
|
18
18
|
|
19
19
|
TelestreamCloud.default_adapter = :excon
|
20
|
-
|
20
|
+
|
21
21
|
For rails 4, try the net_http adapter. This fixes disable_ssl_peer_verification related errors caused by the default adapter.
|
22
|
-
|
22
|
+
|
23
23
|
TelestreamCloud.default_adapter = :net_http
|
24
|
-
|
24
|
+
|
25
25
|
### Creating an instance of the client
|
26
26
|
```ruby
|
27
27
|
TelestreamCloud.configure do
|
28
28
|
access_key "your_access_key"
|
29
29
|
secret_key "your_secret_key"
|
30
|
-
# api_host "api.cloud.telestream.net" # this will be set
|
30
|
+
# api_host "api.cloud.telestream.net" # this will be set by default
|
31
31
|
end
|
32
32
|
```
|
33
33
|
or
|
@@ -80,7 +80,7 @@ end
|
|
80
80
|
|
81
81
|
# Accessing specific Factory
|
82
82
|
f1 = flip.factories.all[0]
|
83
|
-
# or
|
83
|
+
# or
|
84
84
|
f2 = flip.factories.find('factory_id')
|
85
85
|
```
|
86
86
|
|
@@ -93,7 +93,7 @@ videos.first.id
|
|
93
93
|
=> "abcde"
|
94
94
|
|
95
95
|
videos = factory.videos.all(:page => 2, :per_page => 20)
|
96
|
-
# or
|
96
|
+
# or
|
97
97
|
videos = factory.videos.page(1).per_page(20)
|
98
98
|
videos.size
|
99
99
|
=> 20
|
@@ -135,6 +135,35 @@ video.delete
|
|
135
135
|
=> true
|
136
136
|
```
|
137
137
|
|
138
|
+
### Parallel and fail-safe upload
|
139
|
+
|
140
|
+
```ruby
|
141
|
+
# Create video using parallel uploader
|
142
|
+
|
143
|
+
video = TelestreamCloud::ParallelUploader.upload(
|
144
|
+
file: File.new('movie.mp4'),
|
145
|
+
concurrency: 8,
|
146
|
+
profiles: 'webm'
|
147
|
+
)
|
148
|
+
|
149
|
+
# Create video using standard uploader
|
150
|
+
video = TelestreamCloud::Uploader.upload(
|
151
|
+
file: File.new("/path/to/my/movie.mp4"),
|
152
|
+
profiles: "h264,webm",
|
153
|
+
retries: 3
|
154
|
+
)
|
155
|
+
|
156
|
+
# You can also upload video manually
|
157
|
+
uploader = TelestreamCloud::Uploader.new(
|
158
|
+
file: File.new("/path/to/my/movie.mp4"),
|
159
|
+
profiles: "h264,webm",
|
160
|
+
)
|
161
|
+
|
162
|
+
uploader.upload(3)
|
163
|
+
uploader.status # => :success
|
164
|
+
video = uploader.video
|
165
|
+
```
|
166
|
+
|
138
167
|
### Encodings
|
139
168
|
|
140
169
|
```ruby
|
@@ -176,7 +205,7 @@ encoding.screenshots[0]
|
|
176
205
|
|
177
206
|
# Create new encoding for a video that already exists
|
178
207
|
encoding = factory.encodings.create(:video_id => 1234, :profile_id => 6789)
|
179
|
-
# or
|
208
|
+
# or
|
180
209
|
video.encodings.create(:profile_id => 6789)
|
181
210
|
|
182
211
|
# Delete encoding
|
@@ -303,12 +332,12 @@ TelestreamCloud.get('/videos.json')
|
|
303
332
|
"status"=>"success",
|
304
333
|
"width"=>300}]
|
305
334
|
|
306
|
-
# Getting video encodings
|
335
|
+
# Getting video encodings
|
307
336
|
TelestreamCloud.get('/videos/0ee6b656-0063-11df-a433-1231390041c1/encodings.json')
|
308
337
|
=> [{"encoder_id"=>nil,
|
309
338
|
"created_at"=>"2010/01/13 16:45:30 +0000",
|
310
339
|
"video_id"=>"0ee6b656-0063-11df-a433-1231390041c1",
|
311
|
-
"video_url"=>
|
340
|
+
"video_url"=>
|
312
341
|
"http://s3.amazonaws.com/panda-videos/0f815986-0063-11df-a433-1231390041c1.flv",
|
313
342
|
"started_encoding_at"=>"2010/01/13 16:47:35 +0000",
|
314
343
|
"updated_at"=>"2010/01/13 16:47:40 +0000",
|
@@ -333,25 +362,5 @@ bundler install
|
|
333
362
|
rake spec
|
334
363
|
```
|
335
364
|
|
336
|
-
### Resumable upload
|
337
|
-
```ruby
|
338
|
-
us = TelestreamCloud::UploadSession.new("movie.mp4", profiles: "webm")
|
339
|
-
|
340
|
-
retry_count = 0
|
341
|
-
begin
|
342
|
-
us.start()
|
343
|
-
rescue Exception => e
|
344
|
-
while retru_count < 5 and us.status != "success"
|
345
|
-
begin
|
346
|
-
sleep(5)
|
347
|
-
us.resume()
|
348
|
-
rescue Exception => e
|
349
|
-
retry_count += 1
|
350
|
-
end
|
351
|
-
end
|
352
|
-
end
|
353
|
-
```
|
354
|
-
|
355
|
-
|
356
365
|
|
357
366
|
Copyright (c) 2016 Telestream Cloud. See LICENSE for details.
|
data/lib/telestream_cloud.rb
CHANGED
@@ -27,4 +27,6 @@ require 'telestream_cloud/flip'
|
|
27
27
|
require 'telestream_cloud/telestream_cloud'
|
28
28
|
require 'telestream_cloud/faraday'
|
29
29
|
require 'telestream_cloud/upload_session'
|
30
|
-
|
30
|
+
require 'telestream_cloud/uploader'
|
31
|
+
require 'telestream_cloud/uploader/file_reader'
|
32
|
+
require 'telestream_cloud/parallel_uploader'
|
@@ -0,0 +1,52 @@
|
|
1
|
+
module TelestreamCloud
|
2
|
+
class ParallelUploader < Uploader
|
3
|
+
class ThreadPool
|
4
|
+
attr_reader :queue, :size, :worker
|
5
|
+
|
6
|
+
def initialize(size, &block)
|
7
|
+
@size = size
|
8
|
+
@queue = Queue.new
|
9
|
+
@worker = block
|
10
|
+
end
|
11
|
+
|
12
|
+
def <<(*args)
|
13
|
+
queue.push(args)
|
14
|
+
end
|
15
|
+
|
16
|
+
def join
|
17
|
+
size.times.map do
|
18
|
+
Thread.new(queue) do
|
19
|
+
begin
|
20
|
+
while args = queue.pop(true)
|
21
|
+
worker.call(*args)
|
22
|
+
end
|
23
|
+
rescue ThreadError
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end.map(&:join)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
attr_reader :concurrency
|
31
|
+
|
32
|
+
def initialize(options)
|
33
|
+
@concurrency = options.delete(:concurrency)
|
34
|
+
super
|
35
|
+
end
|
36
|
+
|
37
|
+
private
|
38
|
+
|
39
|
+
def upload_chunks(ids)
|
40
|
+
ids.each { |i| thread_pool << i }
|
41
|
+
thread_pool.join
|
42
|
+
end
|
43
|
+
|
44
|
+
def concurrency
|
45
|
+
[@concurrency || max_connections, max_connections].min
|
46
|
+
end
|
47
|
+
|
48
|
+
def thread_pool
|
49
|
+
@thread_pool ||= ThreadPool.new(concurrency, &method(:send_chunk))
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -1,102 +1,40 @@
|
|
1
|
-
|
1
|
+
module TelestreamCloud
|
2
|
+
class UploadSession
|
3
|
+
attr_reader :uploader
|
2
4
|
|
3
|
-
|
4
|
-
|
5
|
-
i = 0
|
6
|
-
until eof?
|
7
|
-
yield(read(CHUNK_SIZE), i)
|
8
|
-
i = i+1
|
5
|
+
def initialize(file_name, options = {})
|
6
|
+
@uploader = Uploader.new(options.merge(file: File.new(file_name)))
|
9
7
|
end
|
10
|
-
end
|
11
|
-
end
|
12
8
|
|
13
|
-
|
14
|
-
|
15
|
-
|
9
|
+
def error_message
|
10
|
+
uploader.error && uploader.error.message
|
11
|
+
end
|
12
|
+
|
13
|
+
def start(_ = nil)
|
14
|
+
uploader.upload
|
15
|
+
end
|
16
16
|
|
17
|
-
def
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
17
|
+
def status
|
18
|
+
uploader.status.to_s
|
19
|
+
end
|
20
|
+
|
21
|
+
def resume
|
22
|
+
start
|
23
|
+
end
|
24
24
|
|
25
|
-
|
26
|
-
|
27
|
-
@status = "initialized"
|
28
|
-
@video = nil
|
29
|
-
@error_message = nil
|
25
|
+
def video
|
26
|
+
uploader.video
|
30
27
|
end
|
31
28
|
|
32
|
-
def
|
33
|
-
|
34
|
-
@status = "uploading"
|
35
|
-
open(@file_name, "rb") do |f|
|
36
|
-
f.seek(pos)
|
37
|
-
f.each_chunk_with_index() { |chunk, i|
|
38
|
-
begin
|
39
|
-
index = i * CHUNK_SIZE
|
40
|
-
uri = URI.parse(URI.encode(@location.to_s))
|
41
|
-
https = Net::HTTP.new(uri.host, uri.port)
|
42
|
-
https.use_ssl = true
|
43
|
-
|
44
|
-
request = Net::HTTP::Post.new(uri.request_uri, initheader = {
|
45
|
-
'Content-Type' =>'application/octet-stream',
|
46
|
-
'Cache-Control' => 'no-cache',
|
47
|
-
'Content-Range' => "bytes #{pos+index}-#{pos+index+CHUNK_SIZE-1}/#{@file_size}",
|
48
|
-
'Content-Length' => "#{CHUNK_SIZE}"
|
49
|
-
})
|
50
|
-
request.body = chunk
|
51
|
-
|
52
|
-
response = https.request(request)
|
53
|
-
if response.code == '200'
|
54
|
-
@status = "uploaded"
|
55
|
-
@video = TelestreamCloud::Video.new(JSON.parse(response.body))
|
56
|
-
elsif response.code != '204'
|
57
|
-
@statys = "error"
|
58
|
-
break
|
59
|
-
end
|
60
|
-
rescue Exception => e
|
61
|
-
@status = "error"
|
62
|
-
@error_mesage = e.message
|
63
|
-
raise e
|
64
|
-
end
|
65
|
-
}
|
66
|
-
end
|
67
|
-
else
|
68
|
-
raise "Already started"
|
69
|
-
end
|
29
|
+
def file_name
|
30
|
+
uploader.reader.name
|
70
31
|
end
|
71
32
|
|
72
|
-
def
|
73
|
-
|
74
|
-
uri = URI.parse(URI.encode(@location.to_s))
|
75
|
-
https = Net::HTTP.new(uri.host, uri.port)
|
76
|
-
https.use_ssl = true
|
77
|
-
|
78
|
-
request = Net::HTTP::Post.new(uri.request_uri, initheader = {
|
79
|
-
'Content-Type' =>'application/octet-stream',
|
80
|
-
'Cache-Control' => 'no-cache',
|
81
|
-
'Content-Range' => "bytes */#{@file_size}",
|
82
|
-
'Content-Length' => "0"
|
83
|
-
})
|
84
|
-
response = https.request(request)
|
85
|
-
pos = response["Range"].split("-")[1]
|
86
|
-
@status = "initialized"
|
87
|
-
self.start(pos.to_i)
|
88
|
-
else
|
89
|
-
raise ("Already succeed")
|
90
|
-
end
|
33
|
+
def file_size
|
34
|
+
uploader.reader.size
|
91
35
|
end
|
92
36
|
|
93
|
-
def abort
|
94
|
-
if @status != "success"
|
95
|
-
@status = "aborted"
|
96
|
-
@error_message = nil
|
97
|
-
else
|
98
|
-
raise "Already succeed"
|
99
|
-
end
|
37
|
+
def abort
|
100
38
|
end
|
101
39
|
end
|
102
40
|
end
|
@@ -0,0 +1,123 @@
|
|
1
|
+
require 'pathname'
|
2
|
+
require 'json'
|
3
|
+
|
4
|
+
module TelestreamCloud
|
5
|
+
class Uploader
|
6
|
+
class UploadError < StandardError; end
|
7
|
+
class MissingPartError < StandardError; end
|
8
|
+
|
9
|
+
attr_reader :reader, :video, :status, :error
|
10
|
+
|
11
|
+
def self.upload(options)
|
12
|
+
retries = options.delete(:retries)
|
13
|
+
new(options).tap { |x| x.upload(*[retries].compact) }.video
|
14
|
+
end
|
15
|
+
|
16
|
+
def initialize(options)
|
17
|
+
file = options.delete(:file) { |key| fail KeyError, "key not found: #{key}" }
|
18
|
+
|
19
|
+
@reader = FileReader.new(file)
|
20
|
+
|
21
|
+
defaults = {
|
22
|
+
file_size: reader.size,
|
23
|
+
file_name: reader.name,
|
24
|
+
multi_chunk: true
|
25
|
+
}
|
26
|
+
|
27
|
+
@params = defaults.merge(options)
|
28
|
+
@status = :ready
|
29
|
+
end
|
30
|
+
|
31
|
+
def upload(retries = 5)
|
32
|
+
count = 0
|
33
|
+
begin
|
34
|
+
count += 1
|
35
|
+
upload!
|
36
|
+
fail MissingPartError unless success?
|
37
|
+
rescue => e
|
38
|
+
@error = e
|
39
|
+
retry if count < retries
|
40
|
+
self.status = :failed
|
41
|
+
end
|
42
|
+
|
43
|
+
success?
|
44
|
+
end
|
45
|
+
|
46
|
+
def success?
|
47
|
+
status == :success
|
48
|
+
end
|
49
|
+
|
50
|
+
private
|
51
|
+
|
52
|
+
def upload!
|
53
|
+
self.status = :uploading
|
54
|
+
upload_chunks(missing_parts)
|
55
|
+
end
|
56
|
+
|
57
|
+
def upload_chunks(ids)
|
58
|
+
ids.each(&method(:send_chunk))
|
59
|
+
end
|
60
|
+
|
61
|
+
def missing_parts
|
62
|
+
return (0...parts).to_a unless @session
|
63
|
+
upload_status['missing_parts']
|
64
|
+
end
|
65
|
+
|
66
|
+
def send_chunk(index)
|
67
|
+
range = (index * part_size...[(index + 1) * part_size, reader.size].min)
|
68
|
+
|
69
|
+
# TODO: remove when 1.9 dropped
|
70
|
+
unless range.respond_to?(:size)
|
71
|
+
def range.size; self.end - self.begin + (exclude_end? ? 0 : 1); end
|
72
|
+
end
|
73
|
+
|
74
|
+
response = http.put do |request|
|
75
|
+
request.headers['Content-Type'] = 'application/octet-stream'
|
76
|
+
request.headers['X-Part'] = "#{index}"
|
77
|
+
request.headers['Content-Length'] = "#{range.size}"
|
78
|
+
request.body = reader[range]
|
79
|
+
end
|
80
|
+
|
81
|
+
set_video(response)
|
82
|
+
response
|
83
|
+
end
|
84
|
+
|
85
|
+
def set_video(response)
|
86
|
+
return if response.status != 200 || response.body.empty?
|
87
|
+
@video = Video.new(JSON.parse(response.body))
|
88
|
+
self.status = :success
|
89
|
+
end
|
90
|
+
|
91
|
+
def status=(status)
|
92
|
+
@status = status
|
93
|
+
@error = nil if success?
|
94
|
+
@status
|
95
|
+
end
|
96
|
+
|
97
|
+
def http
|
98
|
+
@http ||= ::Faraday.new(url: URI(session['location'])) do |builder|
|
99
|
+
builder.request :multipart
|
100
|
+
builder.request :url_encoded
|
101
|
+
builder.adapter TelestreamCloud.default_adapter
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
def upload_status
|
106
|
+
JSON.parse(http.get.body)
|
107
|
+
end
|
108
|
+
|
109
|
+
def parts; session['parts'].to_i; end
|
110
|
+
def part_size; session['part_size'].to_i; end
|
111
|
+
def max_connections; session['max_connections'].to_i; end
|
112
|
+
|
113
|
+
def session
|
114
|
+
@session ||= TelestreamCloud.post('/videos/upload.json', @params)
|
115
|
+
|
116
|
+
if !@session || @session['error']
|
117
|
+
fail UploadError, @session && @session.values_at('error', 'message')
|
118
|
+
end
|
119
|
+
|
120
|
+
@session
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module TelestreamCloud
|
2
|
+
class Uploader
|
3
|
+
class FileReader
|
4
|
+
attr_reader :file
|
5
|
+
|
6
|
+
def initialize(file)
|
7
|
+
@file = file
|
8
|
+
@mutex = Mutex.new
|
9
|
+
end
|
10
|
+
|
11
|
+
def [](range)
|
12
|
+
@mutex.synchronize do
|
13
|
+
file.seek(range.begin)
|
14
|
+
file.read(range.size)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def size
|
19
|
+
@size ||= file.size
|
20
|
+
end
|
21
|
+
|
22
|
+
def name
|
23
|
+
Pathname.new(file.path).basename
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,143 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
2
|
+
|
3
|
+
shared_examples_for "uploader" do
|
4
|
+
let(:file_size) { 45_000_000 }
|
5
|
+
let(:file) do
|
6
|
+
double(:file,
|
7
|
+
path: '/foo/bar.mp4',
|
8
|
+
size: file_size
|
9
|
+
)
|
10
|
+
end
|
11
|
+
|
12
|
+
before(:each) do
|
13
|
+
TelestreamCloud.configure do
|
14
|
+
access_key "my_access_key"
|
15
|
+
secret_key "my_secret_key"
|
16
|
+
api_host "api.example.com"
|
17
|
+
factory_id 'my_cloud_id'
|
18
|
+
api_port 85
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
describe '#upload' do
|
23
|
+
let(:part_size) { 10_000_000 }
|
24
|
+
let(:session_url) { 'http://api.example.com:1234/upload/session?id=1234' }
|
25
|
+
|
26
|
+
let(:video_json) do
|
27
|
+
"{\"id\":\"12345\"}"
|
28
|
+
end
|
29
|
+
|
30
|
+
context 'with valid session' do
|
31
|
+
let(:session_json) do
|
32
|
+
"{\"id\":\"1234\",\"location\":\"#{session_url}\",\"parts\":\"5\",\"part_size\":\"#{part_size}\",\"max_connections\":\"16\"}"
|
33
|
+
end
|
34
|
+
|
35
|
+
before do
|
36
|
+
stub_request(:post, "http://api.example.com:85/v3.0/videos/upload.json")
|
37
|
+
.to_return(body: session_json)
|
38
|
+
|
39
|
+
expect(file).to receive(:read).with(part_size).and_return("chunk").exactly(4).times
|
40
|
+
expect(file).to receive(:read).with(file_size % part_size).and_return("chunk").once
|
41
|
+
|
42
|
+
5.times do |i|
|
43
|
+
expect(file).to receive(:seek).with(i * part_size)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
it 'uploads file' do
|
48
|
+
stub_request(:put, session_url).with(headers: { "X-Part" => /[0-3]/ })
|
49
|
+
|
50
|
+
stub_request(:put, session_url)
|
51
|
+
.with(headers: { "X-Part" => 4 }, body: "chunk")
|
52
|
+
.to_return(body: "{\"id\":\"12345\"}")
|
53
|
+
|
54
|
+
|
55
|
+
subject.upload
|
56
|
+
expect(subject).to be_success
|
57
|
+
expect(subject.video).not_to be_nil
|
58
|
+
expect(subject.video.id).to eq("12345")
|
59
|
+
end
|
60
|
+
|
61
|
+
it 'retries missing chunks' do
|
62
|
+
stub_request(:put, session_url)
|
63
|
+
stub_request(:put, session_url).with(headers: { "X-Part" => 3 })
|
64
|
+
.to_return({body: ""}).then.to_return({body: video_json})
|
65
|
+
|
66
|
+
stub_request(:get, session_url).to_return(body: JSON.generate(missing_parts: [3]))
|
67
|
+
|
68
|
+
expect(file).to receive(:read).with(part_size).and_return("chunk")
|
69
|
+
expect(file).to receive(:seek).with(3 * part_size)
|
70
|
+
|
71
|
+
subject.upload
|
72
|
+
|
73
|
+
expect(subject).to be_success
|
74
|
+
expect(subject.video).not_to be_nil
|
75
|
+
expect(subject.video.id).to eq("12345")
|
76
|
+
end
|
77
|
+
|
78
|
+
it 'fails after few tries' do
|
79
|
+
stub_request(:put, session_url)
|
80
|
+
stub_request(:get, session_url).to_return(body: JSON.generate(missing_parts: [3]))
|
81
|
+
|
82
|
+
expect(file).to receive(:read).with(part_size).and_return("chunk").exactly(4).times
|
83
|
+
expect(file).to receive(:seek).with(3 * part_size).exactly(4).times
|
84
|
+
|
85
|
+
subject.upload
|
86
|
+
|
87
|
+
expect(subject.status).to eq(:failed)
|
88
|
+
expect(subject.video).to be_nil
|
89
|
+
expect(subject.error).to be_a(TelestreamCloud::Uploader::MissingPartError)
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
context 'with invalid session' do
|
94
|
+
let(:session_json) do
|
95
|
+
"{\"error\":\"NotAuthorized\",\"message\":\"Message\"}"
|
96
|
+
end
|
97
|
+
|
98
|
+
it 'fails' do
|
99
|
+
stub_request(:post, "http://api.example.com:85/v3.0/videos/upload.json")
|
100
|
+
.to_return(body: session_json)
|
101
|
+
|
102
|
+
subject.upload
|
103
|
+
|
104
|
+
expect(subject.status).to eq(:failed)
|
105
|
+
expect(subject.error).to be_a(TelestreamCloud::Uploader::UploadError)
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
describe '.upload' do
|
111
|
+
it 'calls #upload' do
|
112
|
+
video = double(:video)
|
113
|
+
expect_any_instance_of(subject.class).to receive(:upload)
|
114
|
+
expect_any_instance_of(subject.class).to receive(:video).and_return(video)
|
115
|
+
|
116
|
+
expect(subject.class.upload(file: file)).to eq(video)
|
117
|
+
end
|
118
|
+
|
119
|
+
it 'calls #upload with retries options' do
|
120
|
+
video = double(:video)
|
121
|
+
expect_any_instance_of(subject.class).to receive(:upload).with(5)
|
122
|
+
expect_any_instance_of(subject.class).to receive(:video).and_return(video)
|
123
|
+
|
124
|
+
expect(subject.class.upload(file: file, retries: 5)).to eq(video)
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
describe TelestreamCloud::Uploader do
|
130
|
+
subject do
|
131
|
+
TelestreamCloud::Uploader.new(file: file)
|
132
|
+
end
|
133
|
+
|
134
|
+
it_behaves_like "uploader"
|
135
|
+
end
|
136
|
+
|
137
|
+
describe TelestreamCloud::ParallelUploader do
|
138
|
+
subject do
|
139
|
+
TelestreamCloud::ParallelUploader.new(file: file)
|
140
|
+
end
|
141
|
+
|
142
|
+
it_behaves_like "uploader"
|
143
|
+
end
|
data/telestream_cloud.gemspec
CHANGED
@@ -8,7 +8,7 @@ Gem::Specification.new do |s|
|
|
8
8
|
s.platform = Gem::Platform::RUBY
|
9
9
|
s.authors = ["Telestream Cloud"]
|
10
10
|
s.email = ["cloudsupport@telestream.net"]
|
11
|
-
s.homepage = "
|
11
|
+
s.homepage = "https://github.com/Telestream/telestream-cloud-ruby-sdk"
|
12
12
|
s.summary = %q{Telestream Cloud Client}
|
13
13
|
s.description = %q{Telestream Cloud Client}
|
14
14
|
|
@@ -20,7 +20,7 @@ Gem::Specification.new do |s|
|
|
20
20
|
s.add_development_dependency "timecop"
|
21
21
|
s.add_development_dependency "rspec", ">= 2.8.0"
|
22
22
|
s.add_development_dependency "webmock", ">= 1.8.2"
|
23
|
-
|
23
|
+
|
24
24
|
s.rubyforge_project = "telestream_cloud"
|
25
25
|
|
26
26
|
s.files = `git ls-files`.split("\n")
|
metadata
CHANGED
@@ -1,111 +1,111 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: telestream_cloud
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Telestream Cloud
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-
|
11
|
+
date: 2016-07-07 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: ruby-hmac
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
|
-
- -
|
17
|
+
- - ">="
|
18
18
|
- !ruby/object:Gem::Version
|
19
19
|
version: 0.3.2
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
|
-
- -
|
24
|
+
- - ">="
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: 0.3.2
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: faraday
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
|
-
- -
|
31
|
+
- - ">="
|
32
32
|
- !ruby/object:Gem::Version
|
33
33
|
version: 0.7.0
|
34
34
|
type: :runtime
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
|
-
- -
|
38
|
+
- - ">="
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: 0.7.0
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: multi_json
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
44
44
|
requirements:
|
45
|
-
- -
|
45
|
+
- - ">="
|
46
46
|
- !ruby/object:Gem::Version
|
47
47
|
version: 1.2.0
|
48
48
|
type: :runtime
|
49
49
|
prerelease: false
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
51
51
|
requirements:
|
52
|
-
- -
|
52
|
+
- - ">="
|
53
53
|
- !ruby/object:Gem::Version
|
54
54
|
version: 1.2.0
|
55
55
|
- !ruby/object:Gem::Dependency
|
56
56
|
name: rake
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
58
58
|
requirements:
|
59
|
-
- -
|
59
|
+
- - ">="
|
60
60
|
- !ruby/object:Gem::Version
|
61
61
|
version: '0'
|
62
62
|
type: :development
|
63
63
|
prerelease: false
|
64
64
|
version_requirements: !ruby/object:Gem::Requirement
|
65
65
|
requirements:
|
66
|
-
- -
|
66
|
+
- - ">="
|
67
67
|
- !ruby/object:Gem::Version
|
68
68
|
version: '0'
|
69
69
|
- !ruby/object:Gem::Dependency
|
70
70
|
name: timecop
|
71
71
|
requirement: !ruby/object:Gem::Requirement
|
72
72
|
requirements:
|
73
|
-
- -
|
73
|
+
- - ">="
|
74
74
|
- !ruby/object:Gem::Version
|
75
75
|
version: '0'
|
76
76
|
type: :development
|
77
77
|
prerelease: false
|
78
78
|
version_requirements: !ruby/object:Gem::Requirement
|
79
79
|
requirements:
|
80
|
-
- -
|
80
|
+
- - ">="
|
81
81
|
- !ruby/object:Gem::Version
|
82
82
|
version: '0'
|
83
83
|
- !ruby/object:Gem::Dependency
|
84
84
|
name: rspec
|
85
85
|
requirement: !ruby/object:Gem::Requirement
|
86
86
|
requirements:
|
87
|
-
- -
|
87
|
+
- - ">="
|
88
88
|
- !ruby/object:Gem::Version
|
89
89
|
version: 2.8.0
|
90
90
|
type: :development
|
91
91
|
prerelease: false
|
92
92
|
version_requirements: !ruby/object:Gem::Requirement
|
93
93
|
requirements:
|
94
|
-
- -
|
94
|
+
- - ">="
|
95
95
|
- !ruby/object:Gem::Version
|
96
96
|
version: 2.8.0
|
97
97
|
- !ruby/object:Gem::Dependency
|
98
98
|
name: webmock
|
99
99
|
requirement: !ruby/object:Gem::Requirement
|
100
100
|
requirements:
|
101
|
-
- -
|
101
|
+
- - ">="
|
102
102
|
- !ruby/object:Gem::Version
|
103
103
|
version: 1.8.2
|
104
104
|
type: :development
|
105
105
|
prerelease: false
|
106
106
|
version_requirements: !ruby/object:Gem::Requirement
|
107
107
|
requirements:
|
108
|
-
- -
|
108
|
+
- - ">="
|
109
109
|
- !ruby/object:Gem::Version
|
110
110
|
version: 1.8.2
|
111
111
|
description: Telestream Cloud Client
|
@@ -115,8 +115,8 @@ executables: []
|
|
115
115
|
extensions: []
|
116
116
|
extra_rdoc_files: []
|
117
117
|
files:
|
118
|
-
- .gitignore
|
119
|
-
- .rspec
|
118
|
+
- ".gitignore"
|
119
|
+
- ".rspec"
|
120
120
|
- Gemfile
|
121
121
|
- LICENSE
|
122
122
|
- README.md
|
@@ -137,6 +137,7 @@ files:
|
|
137
137
|
- lib/telestream_cloud/modules/router.rb
|
138
138
|
- lib/telestream_cloud/modules/updatable.rb
|
139
139
|
- lib/telestream_cloud/modules/video_state.rb
|
140
|
+
- lib/telestream_cloud/parallel_uploader.rb
|
140
141
|
- lib/telestream_cloud/proxies/encoding_scope.rb
|
141
142
|
- lib/telestream_cloud/proxies/profile_scope.rb
|
142
143
|
- lib/telestream_cloud/proxies/proxy.rb
|
@@ -149,6 +150,8 @@ files:
|
|
149
150
|
- lib/telestream_cloud/resources/video.rb
|
150
151
|
- lib/telestream_cloud/telestream_cloud.rb
|
151
152
|
- lib/telestream_cloud/upload_session.rb
|
153
|
+
- lib/telestream_cloud/uploader.rb
|
154
|
+
- lib/telestream_cloud/uploader/file_reader.rb
|
152
155
|
- lib/telestream_cloud/version.rb
|
153
156
|
- spec/cloud_spec.rb
|
154
157
|
- spec/encoding_spec.rb
|
@@ -156,9 +159,10 @@ files:
|
|
156
159
|
- spec/panda_spec.rb
|
157
160
|
- spec/profile_spec.rb
|
158
161
|
- spec/spec_helper.rb
|
162
|
+
- spec/uploader_spec.rb
|
159
163
|
- spec/video_spec.rb
|
160
164
|
- telestream_cloud.gemspec
|
161
|
-
homepage:
|
165
|
+
homepage: https://github.com/Telestream/telestream-cloud-ruby-sdk
|
162
166
|
licenses: []
|
163
167
|
metadata: {}
|
164
168
|
post_install_message:
|
@@ -167,17 +171,17 @@ require_paths:
|
|
167
171
|
- lib
|
168
172
|
required_ruby_version: !ruby/object:Gem::Requirement
|
169
173
|
requirements:
|
170
|
-
- -
|
174
|
+
- - ">="
|
171
175
|
- !ruby/object:Gem::Version
|
172
176
|
version: '0'
|
173
177
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
174
178
|
requirements:
|
175
|
-
- -
|
179
|
+
- - ">="
|
176
180
|
- !ruby/object:Gem::Version
|
177
181
|
version: '0'
|
178
182
|
requirements: []
|
179
183
|
rubyforge_project: telestream_cloud
|
180
|
-
rubygems_version: 2.
|
184
|
+
rubygems_version: 2.5.1
|
181
185
|
signing_key:
|
182
186
|
specification_version: 4
|
183
187
|
summary: Telestream Cloud Client
|
@@ -188,4 +192,5 @@ test_files:
|
|
188
192
|
- spec/panda_spec.rb
|
189
193
|
- spec/profile_spec.rb
|
190
194
|
- spec/spec_helper.rb
|
195
|
+
- spec/uploader_spec.rb
|
191
196
|
- spec/video_spec.rb
|