Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(Coconut): Improve Error Handling and Add GET/POST methods #5

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
167 changes: 107 additions & 60 deletions lib/coconutrb.rb
Original file line number Diff line number Diff line change
Expand Up @@ -13,106 +13,102 @@ class Error < RuntimeError; end
def self.submit(config_content, api_key=nil)
api_key ||= API_KEY
uri = URI("#{COCONUT_URL}/v1/job")
headers = {"User-Agent" => USER_AGENT, "Content-Type" => "text/plain", "Accept" => "application/json"}

req = Net::HTTP::Post.new(uri.path, headers)
req.basic_auth api_key, ''
req.body = config_content

response = Net::HTTP.start(uri.hostname, uri.port, :use_ssl => uri.scheme.include?("https")) do |http|
http.request(req)
end

return MultiJson.decode(response.body)
post(uri.path, config_content, api_key)
end

def self.submit!(config_content, opts={})
result = submit(config_content, opts)
if result["status"] == "error"
if (result.has_key?("error") && !result["error"].empty?) || unsuccessful_status(response['status_code'])
raise Error, "#{result["message"]} (#{result["error_code"]})"
else
return result
end
end

def self.unsuccessful_status(status)
!status.between?(200, 299)
end

def self.get(path, api_key=nil)
api_key ||= API_KEY
uri = URI("#{COCONUT_URL}#{path}")
req = Net::HTTP::Get.new(uri.path, default_headers)
req.basic_auth(api_key, '')
call(uri, req)
end

def self.default_headers
headers = {"User-Agent" => USER_AGENT, "Content-Type" => "text/plain", "Accept" => "application/json"}
end

req = Net::HTTP::Get.new(uri.path, headers)
req.basic_auth api_key, ''
def self.post(path, config_content, api_key=nil)
api_key ||= API_KEY
uri = URI("#{COCONUT_URL}#{path}")
req = Net::HTTP::Post.new(uri.path, default_headers)
req.basic_auth(api_key, '')
req.body = config_content
call(uri, req)
end

response = Net::HTTP.start(uri.hostname, uri.port, :use_ssl => uri.scheme.include?("https")) do |http|
http.request(req)
def self.parse_response(response)
response_code = response.code.to_i
begin
json = MultiJson.decode(response.body)
not_successful_response = (json['status'] == "error" || !response_code.between?(200, 299))
if not_successful_response
{"status" => response.code, "error" => json["message"],
"error_code" => json["error_code"],
"status_code" => response_code
}
else
json.merge({"status_code" => response_code})
end
rescue => e
{"status" => response.code, "error" => e.to_s, "status_code" => response_code}
end
end

if response.code.to_i != 200
return nil
else
return MultiJson.decode(response.body)
def self.call(uri, req)
response = Net::HTTP.start(uri.hostname, uri.port, :use_ssl => uri.scheme.include?("https")) do |http|
http.request(req)
end
parse_response(response)
end


def self.config(options={})
if conf_file = options[:conf]
raise Error, "Config file `#{conf_file}' not found" if ! File.exists?(conf_file)
conf = File.read(conf_file).strip.split("\n")
if options[:conf]
raise Error, "Config file `#{options[:conf]}' not found" if !File.exists?(options[:conf])
conf = File.read(options[:conf]).strip.split("\n")
else
conf = []
end
conf = add_vars_to_conf(options, conf)
conf = add_source_to_conf(options, conf)
conf = add_webhook_to_conf(options, conf)
conf = add_api_version_to_conf(options, conf)
conf = add_outputs_to_conf(options, conf)
conf = sort_conf(conf)
end

if vars = options[:vars]
vars.each do |name,value|
conf << "var #{name} = #{value}"
end
end

if source = options[:source]
conf << "set source = #{source}"
end

if webhook = options[:webhook]
if webhook.is_a?(Hash)
webhook = hash_params_to_string(webhook)
end

conf << "set webhook = #{webhook}"
end

if api_version = options[:api_version]
conf << "set api_version = #{api_version}"
end

if outputs = options[:outputs]
outputs.each do |format, cdn|
if cdn.is_a?(Hash)
cdn = hash_params_to_string(cdn)
end

conf << "-> #{format} = #{cdn}"
end
end

def self.sort_conf(conf)
new_conf = []

new_conf.concat conf.select{|l| l.start_with?("var")}.sort
new_conf << ""
new_conf.concat conf.select{|l| l.start_with?("set")}.sort
new_conf << ""
new_conf.concat conf.select{|l| l.start_with?("->")}.sort

return new_conf.join("\n")
new_conf.join("\n")
end

def self.hash_params_to_string(params)
params.map{|k,v|
params.map do |k,v|
if k.to_s == "url"
"#{v}"
else
"#{k}=#{v}"
end
}.join(", ")
end.join(", ")
end

class Job
Expand All @@ -132,4 +128,55 @@ def self.get_metadata_for(jid, source_or_output, api_key=nil)
Coconut.get("/v1/metadata/jobs/#{jid}/#{source_or_output}", api_key)
end
end

private
def self.add_vars_to_conf(options, conf)
return conf if !options[:vars]
vars = options[:vars]
vars.each do |name,value|
conf << "var #{name} = #{value}"
end
conf
end

def self.add_source_to_conf(options, conf)
return conf if !options[:source]
if options[:source]
conf << "set source = #{options[:source]}"
end
conf
end

def self.add_webhook_to_conf(options, conf)
return conf if !options[:webhook]
webhook_copy = options[:webhook]
if webhook_copy
if webhook_copy.is_a?(Hash)
webhook_copy = hash_params_to_string(webhook_copy)
end
conf << "set webhook = #{webhook_copy}"
end
conf
end

def self.add_api_version_to_conf(options, conf)
return conf if !options[:api_version]
if options[:api_version]
conf << "set api_version = #{options[:api_version]}"
end
conf
end

def self.add_outputs_to_conf(options, conf)
return conf if !options[:outputs]
if options[:outputs]
options[:outputs].each do |format, cdn|
if cdn.is_a?(Hash)
cdn = hash_params_to_string(cdn)
end
conf << "-> #{format} = #{cdn}"
end
end
conf
end
end
39 changes: 21 additions & 18 deletions test/coconutrb_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ def test_submit_job
)

job = Coconut.submit(conf)
assert_equal "processing", job["status"]
assert job["id"] > 0
assert_equal("processing", job["status"])
assert(job["id"] > 0)
end

def test_submit_bad_config_should_raise
Expand All @@ -37,8 +37,8 @@ def test_submit_config_with_api_key
)

job = Coconut.submit(conf, "k-4d204a7fd1fc67fc00e87d3c326d9b75")
assert_equal "error", job["status"]
assert_equal "authentication_failed", job["error_code"]
assert_equal("Authentication failed, check your API key", job["error"])
assert_equal("authentication_failed", job["error_code"])
end

def test_submit_bad_config_should_not_raise
Expand All @@ -47,8 +47,9 @@ def test_submit_bad_config_should_not_raise
)

job = Coconut.submit(conf)
assert_equal "error", job["status"]
assert_equal "config_not_valid", job["error_code"]
assert_equal("400", job['status'])
assert_equal("The config file must specify the `source' video location, a `webhook` URL and at least 1 output", job["error"])
assert_equal("config_not_valid", job["error_code"])
end

def test_generate_full_config_with_no_file
Expand Down Expand Up @@ -80,7 +81,7 @@ def test_generate_full_config_with_no_file
"-> webm = $s3/vid.webm"
].join("\n")

assert_equal generated, config
assert_equal(generated, config)
end

def test_generate_config_with_file
Expand All @@ -103,7 +104,7 @@ def test_generate_config_with_file
"-> mp4 = $s3/$vid.mp4",
].join("\n")

assert_equal generated, config
assert_equal(generated, config)

File.delete("coconut.conf")
end
Expand All @@ -116,8 +117,8 @@ def test_submit_file
:source => "https://s3-eu-west-1.amazonaws.com/files.coconut.co/test.mp4",
:vars => {:vid => 1234, :user => 5098}
)
assert_equal "processing", job["status"]
assert job["id"] > 0
assert_equal("processing", job["status"])
assert(job["id"] > 0)

File.delete("coconut.conf")
end
Expand All @@ -127,9 +128,9 @@ def test_set_api_key_in_job_options
:api_key => "k-4d204a7fd1fc67fc00e87d3c326d9b75",
:source => "https://s3-eu-west-1.amazonaws.com/files.coconut.co/test.mp4",
)

assert_equal "error", job["status"]
assert_equal "authentication_failed", job["error_code"]
assert_equal("401", job["status"])
assert_equal("Authentication failed, check your API key", job["error"])
assert_equal("authentication_failed", job["error_code"])
end

def test_get_job_info
Expand All @@ -142,11 +143,13 @@ def test_get_job_info
job = Coconut.submit(conf)

info = Coconut::Job.get(job["id"])
assert_equal info["id"], job["id"]
assert_equal(info["id"], job["id"])
end

def test_get_not_found_job_returns_nil
assert_nil Coconut::Job.get(1000)
job = Coconut::Job.get(1000)
assert_equal('404', job['status'])
assert_equal('compile error', job['error'])
end

def test_set_api_version
Expand All @@ -166,7 +169,7 @@ def test_set_api_version
"-> mp4 = $s3/vid.mp4",
].join("\n")

assert_equal generated, config
assert_equal(generated, config)
end

def test_get_all_metadata
Expand All @@ -180,7 +183,7 @@ def test_get_all_metadata
sleep 4

metadata = Coconut::Job.get_all_metadata(job["id"])
assert_not_nil metadata
assert_not_nil(metadata)
end

def test_get_metadata_for_source
Expand All @@ -194,7 +197,7 @@ def test_get_metadata_for_source
sleep 4

metadata = Coconut::Job.get_metadata_for(job["id"], :source)
assert_not_nil metadata
assert_not_nil(metadata)
end

def test_cdn_parameters_as_hash
Expand Down