active_encode 0.1.1 → 0.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/.travis.yml +3 -2
- data/Gemfile +35 -0
- data/README.md +15 -14
- data/Rakefile +5 -10
- data/active_encode.gemspec +8 -5
- data/app/jobs/active_encode/polling_job.rb +20 -0
- data/app/models/active_encode/encode_record.rb +5 -0
- data/db/migrate/20180822021048_create_active_encode_encode_records.rb +13 -0
- data/lib/active_encode.rb +1 -0
- data/lib/active_encode/base.rb +6 -2
- data/lib/active_encode/callbacks.rb +18 -35
- data/lib/active_encode/core.rb +64 -20
- data/lib/active_encode/engine.rb +7 -0
- data/lib/active_encode/engine_adapter.rb +2 -2
- data/lib/active_encode/engine_adapters/active_job_adapter.rb +7 -3
- data/lib/active_encode/engine_adapters/elastic_transcoder_adapter.rb +15 -15
- data/lib/active_encode/engine_adapters/inline_adapter.rb +6 -1
- data/lib/active_encode/engine_adapters/matterhorn_adapter.rb +18 -18
- data/lib/active_encode/engine_adapters/shingoncoder_adapter.rb +13 -9
- data/lib/active_encode/engine_adapters/test_adapter.rb +19 -12
- data/lib/active_encode/engine_adapters/zencoder_adapter.rb +10 -10
- data/lib/active_encode/global_id.rb +16 -0
- data/lib/active_encode/input.rb +9 -0
- data/lib/active_encode/output.rb +9 -0
- data/lib/active_encode/persistence.rb +45 -0
- data/lib/active_encode/polling.rb +24 -0
- data/lib/active_encode/status.rb +2 -6
- data/lib/active_encode/technical_metadata.rb +16 -1
- data/lib/active_encode/version.rb +1 -1
- data/spec/fixtures/elastic_transcoder/job_canceled.json +1 -1
- data/spec/fixtures/elastic_transcoder/job_completed.json +1 -1
- data/spec/fixtures/elastic_transcoder/job_created.json +1 -1
- data/spec/fixtures/elastic_transcoder/job_failed.json +1 -1
- data/spec/fixtures/elastic_transcoder/job_progressing.json +1 -1
- data/spec/integration/elastic_transcoder_adapter_spec.rb +87 -167
- data/spec/integration/matterhorn_adapter_spec.rb +34 -79
- data/spec/integration/shingoncoder_adapter_spec.rb +1 -1
- data/spec/integration/zencoder_adapter_spec.rb +1 -1
- data/spec/rails_helper.rb +22 -0
- data/spec/shared_specs/engine_adapter_specs.rb +124 -0
- data/spec/test_app_templates/lib/generators/test_app_generator.rb +15 -0
- data/spec/units/callbacks_spec.rb +16 -17
- data/spec/units/core_spec.rb +121 -2
- data/spec/units/engine_adapter_spec.rb +0 -12
- data/spec/units/global_id_spec.rb +49 -0
- data/spec/units/input_spec.rb +12 -0
- data/spec/units/output_spec.rb +12 -0
- data/spec/units/persistence_spec.rb +57 -0
- data/spec/units/polling_job_spec.rb +86 -0
- data/spec/units/polling_spec.rb +22 -0
- data/spec/units/status_spec.rb +21 -2
- metadata +89 -20
@@ -10,7 +10,7 @@ module ActiveEncode
|
|
10
10
|
|
11
11
|
included do
|
12
12
|
class_attribute :_engine_adapter, instance_accessor: false, instance_predicate: false
|
13
|
-
self.engine_adapter = :
|
13
|
+
self.engine_adapter = :test
|
14
14
|
end
|
15
15
|
|
16
16
|
# Includes the setter method for changing the active engine adapter.
|
@@ -38,7 +38,7 @@ module ActiveEncode
|
|
38
38
|
end
|
39
39
|
end
|
40
40
|
|
41
|
-
ENGINE_ADAPTER_METHODS = %i[create find
|
41
|
+
ENGINE_ADAPTER_METHODS = %i[create find cancel].freeze
|
42
42
|
|
43
43
|
def engine_adapter?(object)
|
44
44
|
ENGINE_ADAPTER_METHODS.all? { |meth| object.respond_to?(meth) }
|
@@ -1,13 +1,17 @@
|
|
1
1
|
module ActiveEncode
|
2
2
|
module EngineAdapters
|
3
3
|
class ActiveJobAdapter
|
4
|
-
def
|
4
|
+
def initialize
|
5
|
+
ActiveSupport::Deprecation.warn("The ActiveJobAdapter is deprecated and will be removed in ActiveEncode 0.3.")
|
6
|
+
end
|
5
7
|
|
6
|
-
def
|
8
|
+
def create(_input_url, _options) end
|
9
|
+
|
10
|
+
def find(_id) end
|
7
11
|
|
8
12
|
def list(*_filters) end
|
9
13
|
|
10
|
-
def cancel(
|
14
|
+
def cancel(_id end
|
11
15
|
|
12
16
|
def purge(_encode) end
|
13
17
|
|
@@ -2,20 +2,20 @@ module ActiveEncode
|
|
2
2
|
module EngineAdapters
|
3
3
|
class ElasticTranscoderAdapter
|
4
4
|
# TODO: add a stub for an input helper (supplied by an initializer) that transforms encode.input into a zencoder accepted url
|
5
|
-
def create(
|
5
|
+
def create(input_url, options = {})
|
6
6
|
job = client.create_job(
|
7
|
-
input: { key:
|
8
|
-
pipeline_id:
|
9
|
-
output_key_prefix:
|
10
|
-
outputs:
|
11
|
-
user_metadata:
|
7
|
+
input: { key: input_url },
|
8
|
+
pipeline_id: options[:pipeline_id],
|
9
|
+
output_key_prefix: options[:output_key_prefix],
|
10
|
+
outputs: options[:outputs],
|
11
|
+
user_metadata: options[:user_metadata]
|
12
12
|
).job
|
13
13
|
|
14
|
-
build_encode(
|
14
|
+
build_encode(job)
|
15
15
|
end
|
16
16
|
|
17
17
|
def find(id, opts = {})
|
18
|
-
build_encode(get_job_details(id)
|
18
|
+
build_encode(get_job_details(id))
|
19
19
|
end
|
20
20
|
|
21
21
|
# TODO: implement list_jobs_by_pipeline and list_jobs_by_status
|
@@ -24,9 +24,9 @@ module ActiveEncode
|
|
24
24
|
end
|
25
25
|
|
26
26
|
# Can only cancel jobs with status = "Submitted"
|
27
|
-
def cancel(
|
28
|
-
response = client.cancel_job(id:
|
29
|
-
build_encode(get_job_details(
|
27
|
+
def cancel(id)
|
28
|
+
response = client.cancel_job(id: id)
|
29
|
+
build_encode(get_job_details(id)) if response.successful?
|
30
30
|
end
|
31
31
|
|
32
32
|
def purge(_encode)
|
@@ -48,9 +48,9 @@ module ActiveEncode
|
|
48
48
|
client.read_job(id: job_id).job
|
49
49
|
end
|
50
50
|
|
51
|
-
def build_encode(job
|
51
|
+
def build_encode(job)
|
52
52
|
return nil if job.nil?
|
53
|
-
encode =
|
53
|
+
encode = ActiveEncode::Base.new(convert_input(job), convert_options(job))
|
54
54
|
encode.id = job.id
|
55
55
|
encode.state = convert_state(job)
|
56
56
|
encode.current_operations = convert_current_operations(job)
|
@@ -66,7 +66,7 @@ module ActiveEncode
|
|
66
66
|
|
67
67
|
def convert_time(time_millis)
|
68
68
|
return nil if time_millis.nil?
|
69
|
-
Time.at(time_millis / 1000)
|
69
|
+
Time.at(time_millis / 1000)
|
70
70
|
end
|
71
71
|
|
72
72
|
def convert_state(job)
|
@@ -91,7 +91,7 @@ module ActiveEncode
|
|
91
91
|
case job.status
|
92
92
|
when "Submitted"
|
93
93
|
10
|
94
|
-
when "Progressing"
|
94
|
+
when "Progressing", "Canceled", "Error"
|
95
95
|
50
|
96
96
|
when "Complete"
|
97
97
|
100
|
@@ -4,7 +4,12 @@ module ActiveEncode
|
|
4
4
|
class_attribute :encodes, instance_accessor: false, instance_predicate: false
|
5
5
|
InlineAdapter.encodes ||= {}
|
6
6
|
|
7
|
-
def
|
7
|
+
def initialize
|
8
|
+
ActiveSupport::Deprecation.warn("The InlineAdapter is deprecated and will be removed in ActiveEncode 0.3.")
|
9
|
+
end
|
10
|
+
|
11
|
+
def create(input_url, options = {})
|
12
|
+
encode = ActiveEncode::Base.new(input_url, options)
|
8
13
|
encode.id = SecureRandom.uuid
|
9
14
|
self.class.encodes[encode.id] = encode
|
10
15
|
# start encode
|
@@ -5,27 +5,27 @@ module ActiveEncode
|
|
5
5
|
class MatterhornAdapter
|
6
6
|
DEFAULT_ARGS = { 'flavor' => 'presenter/source' }.freeze
|
7
7
|
|
8
|
-
def create(
|
9
|
-
workflow_id =
|
10
|
-
workflow_om = if encode.input.is_a? Hash
|
11
|
-
|
12
|
-
|
13
|
-
Rubyhorn.client.addMediaPackageWithUrl(DEFAULT_ARGS.merge('workflow' => workflow_id, 'url' =>
|
14
|
-
end
|
15
|
-
build_encode(get_workflow(workflow_om)
|
8
|
+
def create(input_url, options = {})
|
9
|
+
workflow_id = options[:preset] || "full"
|
10
|
+
# workflow_om = if encode.input.is_a? Hash
|
11
|
+
# create_multiple_files(encode.input, workflow_id)
|
12
|
+
# else
|
13
|
+
workflow_om = Rubyhorn.client.addMediaPackageWithUrl(DEFAULT_ARGS.merge('workflow' => workflow_id, 'url' => input_url, 'filename' => File.basename(input_url), 'title' => File.basename(input_url)))
|
14
|
+
# end
|
15
|
+
build_encode(get_workflow(workflow_om))
|
16
16
|
end
|
17
17
|
|
18
18
|
def find(id, opts = {})
|
19
|
-
build_encode(fetch_workflow(id)
|
19
|
+
build_encode(fetch_workflow(id))
|
20
20
|
end
|
21
21
|
|
22
22
|
def list(*_filters)
|
23
23
|
raise NotImplementedError # TODO: implement this
|
24
24
|
end
|
25
25
|
|
26
|
-
def cancel(
|
27
|
-
workflow_om = Rubyhorn.client.stop(
|
28
|
-
build_encode(get_workflow(workflow_om)
|
26
|
+
def cancel(id)
|
27
|
+
workflow_om = Rubyhorn.client.stop(id)
|
28
|
+
build_encode(get_workflow(workflow_om))
|
29
29
|
end
|
30
30
|
|
31
31
|
def purge(encode)
|
@@ -41,7 +41,7 @@ module ActiveEncode
|
|
41
41
|
end
|
42
42
|
purged_workflow = purge_outputs(get_workflow(workflow_om))
|
43
43
|
# Rubyhorn.client.delete_instance(encode.id) #Delete is not working so workflow instances can always be retrieved later!
|
44
|
-
build_encode(purged_workflow
|
44
|
+
build_encode(purged_workflow)
|
45
45
|
end
|
46
46
|
|
47
47
|
def remove_output(encode, output_id)
|
@@ -79,9 +79,9 @@ module ActiveEncode
|
|
79
79
|
end
|
80
80
|
end
|
81
81
|
|
82
|
-
def build_encode(workflow
|
82
|
+
def build_encode(workflow)
|
83
83
|
return nil if workflow.nil?
|
84
|
-
encode =
|
84
|
+
encode = ActiveEncode::Base.new(convert_input(workflow), convert_options(workflow))
|
85
85
|
encode.id = convert_id(workflow)
|
86
86
|
encode.state = convert_state(workflow)
|
87
87
|
encode.current_operations = convert_current_operations(workflow)
|
@@ -146,17 +146,17 @@ module ActiveEncode
|
|
146
146
|
|
147
147
|
def convert_created_at(workflow)
|
148
148
|
created_at = workflow.xpath('mediapackage/@start').last.to_s
|
149
|
-
created_at.present? ? Time.parse(created_at)
|
149
|
+
created_at.present? ? Time.parse(created_at) : nil
|
150
150
|
end
|
151
151
|
|
152
152
|
def convert_updated_at(workflow)
|
153
153
|
updated_at = workflow.xpath('//operation[@state!="INSTANTIATED"]/completed/text()').last.to_s
|
154
|
-
updated_at.present? ? Time.strptime(updated_at, "%Q")
|
154
|
+
updated_at.present? ? Time.strptime(updated_at, "%Q") : nil
|
155
155
|
end
|
156
156
|
|
157
157
|
def convert_finished_at(workflow)
|
158
158
|
finished_at = workflow.xpath('//operation[@state!="INSTANTIATED"]/completed/text()').last.to_s
|
159
|
-
finished_at.present? ? Time.strptime(finished_at, "%Q")
|
159
|
+
finished_at.present? ? Time.strptime(finished_at, "%Q") : nil
|
160
160
|
end
|
161
161
|
|
162
162
|
def convert_options(workflow)
|
@@ -4,23 +4,27 @@ require 'active_support/core_ext'
|
|
4
4
|
module ActiveEncode
|
5
5
|
module EngineAdapters
|
6
6
|
class ShingoncoderAdapter < ZencoderAdapter
|
7
|
+
def initialize
|
8
|
+
ActiveSupport::Deprecation.warn("The ShingoncoderAdapter is deprecated and will be removed in ActiveEncode 0.3.")
|
9
|
+
end
|
10
|
+
|
7
11
|
# @param [ActiveEncode::Base] encode
|
8
|
-
def create(
|
9
|
-
response = Shingoncoder::Job.create(input:
|
10
|
-
build_encode(job_details(response.body["id"])
|
12
|
+
def create(input_url, options = {})
|
13
|
+
response = Shingoncoder::Job.create(input: input_url)
|
14
|
+
build_encode(job_details(response.body["id"]))
|
11
15
|
end
|
12
16
|
|
13
17
|
# @param [Fixnum] id
|
14
18
|
# @param [Hash] opts
|
15
19
|
# @option opts :cast the class to cast the encoding job to.
|
16
20
|
def find(id, opts = {})
|
17
|
-
build_encode(job_details(id)
|
21
|
+
build_encode(job_details(id))
|
18
22
|
end
|
19
23
|
|
20
24
|
# @param [ActiveEncode::Base] encode
|
21
|
-
def cancel(
|
22
|
-
response = Shingoncoder::Job.cancel(
|
23
|
-
build_encode(job_details(
|
25
|
+
def cancel(id)
|
26
|
+
response = Shingoncoder::Job.cancel(id)
|
27
|
+
build_encode(job_details(id)) if response.success?
|
24
28
|
end
|
25
29
|
|
26
30
|
private
|
@@ -38,9 +42,9 @@ module ActiveEncode
|
|
38
42
|
|
39
43
|
# @param [Shingoncoder::Response] job_details
|
40
44
|
# @param [Class] cast the class of object to instantiate and return
|
41
|
-
def build_encode(job_details
|
45
|
+
def build_encode(job_details)
|
42
46
|
return nil if job_details.nil?
|
43
|
-
encode =
|
47
|
+
encode = ActiveEncode::Base.new(convert_input(job_details), convert_options(job_details))
|
44
48
|
encode.id = job_details.body["job"]["id"].to_s
|
45
49
|
encode.state = convert_state(job_details)
|
46
50
|
progress = job_progress(encode.id)
|
@@ -5,25 +5,32 @@ module ActiveEncode
|
|
5
5
|
@encodes = {}
|
6
6
|
end
|
7
7
|
|
8
|
-
def create(
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
8
|
+
def create(input_url, options = {})
|
9
|
+
new_encode = ActiveEncode::Base.new(input_url, options)
|
10
|
+
new_encode.id = SecureRandom.uuid
|
11
|
+
new_encode.state = :running
|
12
|
+
new_encode.created_at = Time.now
|
13
|
+
new_encode.updated_at = Time.now
|
14
|
+
@encodes[new_encode.id] = new_encode
|
15
|
+
new_encode
|
13
16
|
end
|
14
17
|
|
15
18
|
def find(id, _opts = {})
|
16
|
-
@encodes[id]
|
19
|
+
new_encode = @encodes[id]
|
20
|
+
# Update the updated_at time to simulate changes
|
21
|
+
new_encode.updated_at = Time.now
|
22
|
+
new_encode
|
17
23
|
end
|
18
24
|
|
19
|
-
def
|
20
|
-
|
25
|
+
def cancel(id)
|
26
|
+
new_encode = @encodes[id]
|
27
|
+
new_encode.state = :cancelled
|
28
|
+
new_encode.updated_at = Time.now
|
29
|
+
new_encode
|
21
30
|
end
|
22
31
|
|
23
|
-
def
|
24
|
-
|
25
|
-
e.state = :cancelled
|
26
|
-
e
|
32
|
+
def list(*_filters)
|
33
|
+
raise NotImplementedError
|
27
34
|
end
|
28
35
|
|
29
36
|
def purge(encode)
|
@@ -1,23 +1,23 @@
|
|
1
1
|
module ActiveEncode
|
2
2
|
module EngineAdapters
|
3
3
|
class ZencoderAdapter
|
4
|
-
# TODO: add a stub for an input helper (supplied by an initializer) that transforms encode.input into a zencoder accepted url
|
5
|
-
def create(
|
6
|
-
response = Zencoder::Job.create(input:
|
7
|
-
build_encode(get_job_details(response.body["id"])
|
4
|
+
# TODO: add a stub for an input helper (supplied by an initializer) that transforms encode.input.url into a zencoder accepted url
|
5
|
+
def create(input_url, options = {})
|
6
|
+
response = Zencoder::Job.create(input: input_url.to_s)
|
7
|
+
build_encode(get_job_details(response.body["id"]))
|
8
8
|
end
|
9
9
|
|
10
10
|
def find(id, opts = {})
|
11
|
-
build_encode(get_job_details(id)
|
11
|
+
build_encode(get_job_details(id))
|
12
12
|
end
|
13
13
|
|
14
14
|
def list(*_filters)
|
15
15
|
raise NotImplementedError
|
16
16
|
end
|
17
17
|
|
18
|
-
def cancel(
|
19
|
-
response = Zencoder::Job.cancel(
|
20
|
-
build_encode(get_job_details(
|
18
|
+
def cancel(id)
|
19
|
+
response = Zencoder::Job.cancel(id)
|
20
|
+
build_encode(get_job_details(id)) if response.success?
|
21
21
|
end
|
22
22
|
|
23
23
|
def purge(_encode)
|
@@ -38,9 +38,9 @@ module ActiveEncode
|
|
38
38
|
Zencoder::Job.progress(job_id)
|
39
39
|
end
|
40
40
|
|
41
|
-
def build_encode(job_details
|
41
|
+
def build_encode(job_details)
|
42
42
|
return nil if job_details.nil?
|
43
|
-
encode =
|
43
|
+
encode = ActiveEncode::Base.new(convert_input(job_details), convert_options(job_details))
|
44
44
|
encode.id = job_details.body["job"]["id"].to_s
|
45
45
|
encode.state = convert_state(job_details)
|
46
46
|
job_progress = get_job_progress(encode.id)
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'globalid'
|
2
|
+
|
3
|
+
module ActiveEncode
|
4
|
+
module GlobalID
|
5
|
+
extend ActiveSupport::Concern
|
6
|
+
include ::GlobalID::Identification
|
7
|
+
|
8
|
+
def ==(other)
|
9
|
+
other.is_a?(ActiveEncode::Base) && to_global_id == other.to_global_id
|
10
|
+
end
|
11
|
+
|
12
|
+
def to_global_id(options = {})
|
13
|
+
super(app: 'ActiveEncode')
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
require 'active_support'
|
2
|
+
|
3
|
+
module ActiveEncode
|
4
|
+
module Persistence
|
5
|
+
extend ActiveSupport::Concern
|
6
|
+
|
7
|
+
included do
|
8
|
+
after_find do |encode|
|
9
|
+
persist(persistence_model_attributes(encode))
|
10
|
+
end
|
11
|
+
|
12
|
+
after_create do |encode|
|
13
|
+
persist(persistence_model_attributes(encode))
|
14
|
+
end
|
15
|
+
|
16
|
+
after_cancel do |encode|
|
17
|
+
persist(persistence_model_attributes(encode))
|
18
|
+
end
|
19
|
+
|
20
|
+
after_reload do |encode|
|
21
|
+
persist(persistence_model_attributes(encode))
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
def persist(encode_attributes)
|
28
|
+
model = ActiveEncode::EncodeRecord.find_or_initialize_by(global_id: encode_attributes[:global_id])
|
29
|
+
model.update(encode_attributes) # Don't fail if persisting doesn't succeed?
|
30
|
+
end
|
31
|
+
|
32
|
+
def persistence_model_attributes(encode)
|
33
|
+
{
|
34
|
+
global_id: encode.to_global_id.to_s,
|
35
|
+
state: encode.state,
|
36
|
+
adapter: encode.class.engine_adapter.class.name,
|
37
|
+
title: encode.input.url.to_s,
|
38
|
+
# FIXME: Need to ensure that these values come through or else validations will fail
|
39
|
+
created_at: encode.created_at,
|
40
|
+
updated_at: encode.updated_at,
|
41
|
+
raw_object: encode.to_json
|
42
|
+
}
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'active_support'
|
2
|
+
require 'active_model/callbacks'
|
3
|
+
|
4
|
+
module ActiveEncode
|
5
|
+
module Polling
|
6
|
+
extend ActiveSupport::Concern
|
7
|
+
|
8
|
+
POLLING_WAIT_TIME = 10.seconds.freeze
|
9
|
+
|
10
|
+
CALLBACKS = [
|
11
|
+
:after_status_update, :after_error, :after_cancelled, :after_complete
|
12
|
+
].freeze
|
13
|
+
|
14
|
+
included do
|
15
|
+
extend ActiveModel::Callbacks
|
16
|
+
|
17
|
+
define_model_callbacks :status_update, :error, :cancelled, :complete, only: :after
|
18
|
+
|
19
|
+
after_create do |encode|
|
20
|
+
ActiveEncode::PollingJob.set(wait: POLLING_WAIT_TIME).perform_later(encode)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|