Skip to content

Commit

Permalink
Add support to HTTP to raise connection errors with specific error cl…
Browse files Browse the repository at this point in the history
…ass.
  • Loading branch information
stefansundin committed Sep 20, 2017
1 parent b1648d2 commit 29cacf7
Show file tree
Hide file tree
Showing 17 changed files with 83 additions and 58 deletions.
14 changes: 7 additions & 7 deletions app.rb
Original file line number Diff line number Diff line change
Expand Up @@ -388,8 +388,8 @@
# The video/photo is probably uploaded by a regular Facebook user (i.e. not uploaded to a page), which we can't get info from via the API.
# Video example: https://www.facebook.com/ofer.dikovsky/videos/10154633221533413/
# Photo example: 1401133169914577
response = HTTP.get("https://www.facebook.com/#{id}")
response = HTTP.get(response.redirect_url) if response.redirect?
response = Facebook.get("https://www.facebook.com/#{id}")
response = Facebook.get(response.redirect_url) if response.redirect_same_origin?
if response.success?
if /hd_src_no_ratelimit:"(?<url>[^"]+)"/ =~ response.body
elsif /https:\/\/[^"]+_#{id}_[^"]+\.jpg[^"]+/o =~ response.body
Expand Down Expand Up @@ -580,7 +580,7 @@
else
"https://www.periscope.tv/#{CGI.escape(username)}"
end
response = HTTP.get(url)
response = Periscope.get(url)
return "That username does not exist." if response.code == 404
return "That broadcast has expired." if response.code == 410
raise PeriscopeError.new(response) if !response.success?
Expand Down Expand Up @@ -750,7 +750,7 @@
end

if clip_slug
response = HTTP.get("https://clips.twitch.tv/embed?clip=#{clip_slug}")
response = Twitch.get("https://clips.twitch.tv/embed?clip=#{clip_slug}")
return "Clip does not seem to exist." if response.code == 404
raise TwitchError.new(response) if !response.success?
url = response.body[/https:\/\/clips-media-assets\.twitch\.tv\/.+?\.mp4/]
Expand Down Expand Up @@ -798,7 +798,7 @@
end

if clip_slug
response = HTTP.get("https://clips.twitch.tv/embed?clip=#{clip_slug}")
response = Twitch.get("https://clips.twitch.tv/embed?clip=#{clip_slug}")
return "Clip does not seem to exist." if response.code == 404
raise TwitchError.new(response) if !response.success?
streams = response.body.scan(/https:\/\/clips-media-assets\.twitch\.tv\/.+?\.mp4/)
Expand All @@ -813,7 +813,7 @@
data = response.json
playlist_url = "http://usher.twitch.tv/vod/#{vod_id}?nauthsig=#{data["sig"]}&nauth=#{CGI.escape(data["token"])}"

response = HTTP.get(playlist_url)
response = Twitch.get(playlist_url)
streams = response.body.split("\n").reject { |line| line[0] == "#" } + [playlist_url]
elsif channel_name
response = Twitch.get("/api/channels/#{channel_name}/access_token")
Expand All @@ -824,7 +824,7 @@
token_data = JSON.parse(data["token"])
playlist_url = "http://usher.ttvnw.net/api/channel/hls/#{token_data["channel"]}.m3u8?token=#{CGI.escape(data["token"])}&sig=#{data["sig"]}&allow_source=true&allow_spectre=true"

response = HTTP.get(playlist_url)
response = Twitch.get(playlist_url)
return "Channel does not seem to be online." if response.code == 404
raise TwitchError.new(response) if !response.success?
streams = response.body.split("\n").reject { |line| line.start_with?("#") } + [playlist_url]
Expand Down
7 changes: 4 additions & 3 deletions app/dailymotion.rb
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
# https://developer.dailymotion.com/api

class DailymotionError < HTTPError; end

class Dailymotion < HTTP
BASE_URL = "https://api.dailymotion.com"
ERROR_CLASS = DailymotionError
end

class DailymotionError < HTTPError; end

error DailymotionError do |e|
status 503
"There was a problem talking to Dailymotion."
"There was a problem talking to Dailymotion. Please try again in a moment."
end
7 changes: 4 additions & 3 deletions app/facebook.rb
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
# https://developers.facebook.com/docs/graph-api/reference/

class FacebookError < HTTPError; end

class Facebook < HTTP
BASE_URL = "https://graph.facebook.com/v2.8"
PARAMS = "access_token=#{ENV["FACEBOOK_APP_ID"]}|#{ENV["FACEBOOK_APP_SECRET"]}"
ERROR_CLASS = FacebookError
end

class FacebookError < HTTPError; end

error FacebookError do |e|
status 503
"There was a problem talking to Facebook."
"There was a problem talking to Facebook. Please try again in a moment."
end
7 changes: 4 additions & 3 deletions app/google.rb
Original file line number Diff line number Diff line change
@@ -1,18 +1,19 @@
# https://developers.google.com/youtube/v3/docs/
# https://developers.google.com/+/web/api/rest/

class GoogleError < HTTPError; end

class Google < HTTP
BASE_URL = "https://www.googleapis.com"
PARAMS = "key=#{ENV["GOOGLE_API_KEY"]}"
ERROR_CLASS = GoogleError
end

class GoogleError < HTTPError; end

error GoogleError do |e|
status 503
if (e.data["error"]["errors"][0]["reason"] == "accessNotConfigured" rescue false)
"Please enable the appropriate API for this project in the Google Developer Console."
else
"There was a problem talking to Google."
"There was a problem talking to Google. Please try again in a moment."
end
end
7 changes: 4 additions & 3 deletions app/imgur.rb
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
# https://api.imgur.com/endpoints

class ImgurError < HTTPError; end

class Imgur < HTTP
BASE_URL = "https://api.imgur.com/3"
HEADERS = {
"Authorization": "Client-ID #{ENV["IMGUR_CLIENT_ID"]}",
}
ERROR_CLASS = ImgurError
end

class ImgurError < HTTPError; end

error ImgurError do |e|
status 503
"There was a problem talking to Imgur."
"There was a problem talking to Imgur. Please try again in a moment."
end
7 changes: 4 additions & 3 deletions app/instagram.rb
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
# https://www.instagram.com/developer/endpoints/

class InstagramError < HTTPError; end

class Instagram < HTTP
BASE_URL = "https://www.instagram.com"
PARAMS = "__a=1"
ERROR_CLASS = InstagramError
end

class InstagramError < HTTPError; end

error InstagramError do |e|
status 503
"There was a problem talking to Instagram."
"There was a problem talking to Instagram. Please try again in a moment."
end
7 changes: 4 additions & 3 deletions app/mixcloud.rb
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
# https://www.mixcloud.com/developers/

class MixcloudError < HTTPError; end

class Mixcloud < HTTP
BASE_URL = "https://api.mixcloud.com"
ERROR_CLASS = MixcloudError
end

class MixcloudError < HTTPError; end

error MixcloudError do |e|
status 503
"There was a problem talking to Mixcloud."
"There was a problem talking to Mixcloud. Please try again in a moment."
end
10 changes: 6 additions & 4 deletions app/periscope.rb
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
# No public API documentation

class PeriscopeError < HTTPError; end

class Periscope < HTTP
BASE_URL = "https://api.periscope.tv/api/v2"
ERROR_CLASS = PeriscopeError

def self.get_broadcasts(user_id)
response = HTTP.get("https://www.periscope.tv/cnn")
response = get("https://www.periscope.tv/cnn")
raise ERROR_CLASS.new(response) if !response.success?
doc = Nokogiri::HTML(response.body)
data = doc.at("div#page-container")["data-store"]
json = JSON.parse(data)
Expand All @@ -13,9 +17,7 @@ def self.get_broadcasts(user_id)
end
end

class PeriscopeError < HTTPError; end

error PeriscopeError do |e|
status 503
"There was a problem talking to Periscope."
"There was a problem talking to Periscope. Please try again in a moment."
end
7 changes: 4 additions & 3 deletions app/soundcloud.rb
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
# https://developers.soundcloud.com/docs/api/reference

class SoundcloudError < HTTPError; end

class Soundcloud < HTTP
BASE_URL = "https://api.soundcloud.com"
PARAMS = "client_id=#{ENV["SOUNDCLOUD_CLIENT_ID"]}"
ERROR_CLASS = SoundcloudError
end

class SoundcloudError < HTTPError; end

error SoundcloudError do |e|
status 503
"There was a problem talking to Soundcloud."
"There was a problem talking to SoundCloud. Please try again in a moment."
end
7 changes: 4 additions & 3 deletions app/speedrun.rb
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
# https://github.com/speedruncom/api/tree/master/version1

class SpeedrunError < HTTPError; end

class Speedrun < HTTP
BASE_URL = "https://www.speedrun.com/api/v1"
ERROR_CLASS = SpeedrunError

@@cache = {}

Expand Down Expand Up @@ -42,9 +45,7 @@ def self.resolve_id(type, id)
end
end

class SpeedrunError < HTTPError; end

error SpeedrunError do |e|
status 503
"There was a problem talking to speedrun.com."
"There was a problem talking to speedrun.com. Please try again in a moment."
end
7 changes: 4 additions & 3 deletions app/twitch.rb
Original file line number Diff line number Diff line change
@@ -1,16 +1,17 @@
# https://github.com/justintv/Twitch-API/

class TwitchError < HTTPError; end

class Twitch < HTTP
BASE_URL = "https://api.twitch.tv"
HEADERS = {
"Accept": "application/vnd.twitchtv.v3+json",
"Client-ID": ENV["TWITCH_CLIENT_ID"],
}
ERROR_CLASS = TwitchError
end

class TwitchError < HTTPError; end

error TwitchError do |e|
status 503
"There was a problem talking to Twitch."
"There was a problem talking to Twitch. Please try again in a moment."
end
7 changes: 4 additions & 3 deletions app/twitter.rb
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
# https://dev.twitter.com/rest/reference/get/statuses/user_timeline

class TwitterError < HTTPError; end

class Twitter < HTTP
BASE_URL = "https://api.twitter.com/1.1"
HEADERS = {
"Authorization": "Bearer #{ENV["TWITTER_ACCESS_TOKEN"]}",
}
ERROR_CLASS = TwitterError
end

class TwitterError < HTTPError; end

error TwitterError do |e|
status 503
"There was a problem talking to Twitter."
"There was a problem talking to Twitter. Please try again in a moment."
end
7 changes: 4 additions & 3 deletions app/ustream.rb
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
# http://ustream.github.io/api-docs/broadcasting-api/channel.html

class UstreamError < HTTPError; end

class Ustream < HTTP
BASE_URL = "https://api.ustream.tv"
ERROR_CLASS = UstreamError
end

class UstreamError < HTTPError; end

error UstreamError do |e|
status 503
"There was a problem talking to Ustream."
"There was a problem talking to Ustream. Please try again in a moment."
end
7 changes: 4 additions & 3 deletions app/vidme.rb
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
# https://docs.vid.me/

class VidmeError < HTTPError; end

class Vidme < HTTP
BASE_URL = "https://api.vid.me"
ERROR_CLASS = VidmeError
end

class VidmeError < HTTPError; end

error VidmeError do |e|
status 503
"There was a problem talking to Vidme."
"There was a problem talking to Vidme. Please try again in a moment."
end
7 changes: 4 additions & 3 deletions app/vimeo.rb
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
# https://developer.vimeo.com/api/start

class VimeoError < HTTPError; end

class Vimeo < HTTP
BASE_URL = "https://api.vimeo.com"
HEADERS = {
"Authorization": "bearer #{ENV["VIMEO_ACCESS_TOKEN"]}",
}
ERROR_CLASS = VimeoError
end

class VimeoError < HTTPError; end

error VimeoError do |e|
status 503
"There was a problem talking to Vimeo."
"There was a problem talking to Vimeo. Please try again in a moment."
end
1 change: 0 additions & 1 deletion config/initializers/05-string.rb
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
require "addressable/uri"
require "net/http"
require "resolv-replace.rb"

Expand Down
25 changes: 18 additions & 7 deletions config/initializers/90-http.rb
Original file line number Diff line number Diff line change
@@ -1,13 +1,10 @@
require "addressable/uri"

class HTTP
def self.get(url, options={headers: nil, query: nil})
if defined?(self::BASE_URL)
raise "url must start with /" if url[0] != "/"
if defined?(self::BASE_URL) and url[0] == "/"
url = self::BASE_URL+url
end

if defined?(self::PARAMS)
if defined?(self::PARAMS) and url[0] == "/"
if url["?"]
url += "&"+self::PARAMS
else
Expand All @@ -32,11 +29,14 @@ def self.get(url, options={headers: nil, query: nil})
}
Net::HTTP.start(uri.host, uri.port, opts) do |http|
headers = {}
headers.merge!(self::HEADERS) if defined?(self::HEADERS)
headers.merge!(self::HEADERS) if defined?(self::HEADERS) and url[0] == "/"
headers.merge!(opts[:headers]) if opts[:headers]
response = http.request_get(uri.request_uri, headers)
return HTTPResponse.new(response, uri.to_s)
end
rescue Net::OpenTimeout, Net::ReadTimeout, SocketError, Errno::ECONNREFUSED, Errno::ECONNRESET, OpenSSL::SSL::SSLError, EOFError => e
self::ERROR_CLASS ||= HTTPError
raise self::ERROR_CLASS.new(e)
end
end

Expand Down Expand Up @@ -94,6 +94,13 @@ def redirect_url
end
Addressable::URI.parse(url).normalize.to_s # Some redirects do not url encode properly, such as http://amzn.to/2aDg49F
end

def redirect_same_origin?
return false if !redirect?
uri = Addressable::URI.parse(@url).normalize
new_uri = Addressable::URI.parse(redirect_url).normalize
uri.origin == new_uri.origin
end
end

class HTTPError < StandardError
Expand All @@ -110,6 +117,10 @@ def data
end

def message
"#{@request.code}: #{@request.body}"
if @request.is_a?(HTTPResponse)
"#{@request.code}: #{@request.body}"
else
"#{self}: #{@request.message}"
end
end
end

0 comments on commit 29cacf7

Please sign in to comment.