faraday_middleware-reddit 0.2.1 → 0.3.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/.rubocop.yml +2 -0
- data/lib/faraday_middleware/reddit.rb +6 -4
- data/lib/faraday_middleware/reddit/request/authentication.rb +51 -37
- data/lib/faraday_middleware/reddit/use/force_json.rb +2 -0
- data/lib/faraday_middleware/reddit/use/modhash.rb +36 -30
- data/lib/faraday_middleware/reddit/use/rate_limit.rb +35 -31
- data/lib/faraday_middleware/reddit/version.rb +3 -1
- data/spec/helper.rb +2 -0
- metadata +10 -19
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: bb5d504dc531f50831b4b47a26b6a18599e23116
|
4
|
+
data.tar.gz: cc735e9f121b089f0b6d5f6fab22581b1baa0468
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: f8fe0ab6c2532f336dc901309782a7dd9cd3e25f568eb5cf73cc5e9dbd8455da32dbaa7d3d1a0d5bf5b3ce3c137b6f7a2312170f02badead8aa35a0f4f425469
|
7
|
+
data.tar.gz: b18fdbb8d7575f5a0d0d461e6b7a50d0fb101c2511f2e9151a83f3300850c8ab9f47c13ebb99aa5d274fe00ceb152b11f9b0a968898b1a127f9f59893e59c5b2
|
data/.rubocop.yml
ADDED
@@ -1,3 +1,5 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
1
3
|
require 'faraday'
|
2
4
|
|
3
5
|
module FaradayMiddleware
|
@@ -9,11 +11,11 @@ module FaradayMiddleware
|
|
9
11
|
|
10
12
|
if Faraday::Middleware.respond_to? :register_middleware
|
11
13
|
Faraday::Request.register_middleware \
|
12
|
-
:
|
14
|
+
reddit_authentication: -> { Authentication }
|
13
15
|
Faraday::Middleware.register_middleware \
|
14
|
-
:
|
15
|
-
:
|
16
|
-
:
|
16
|
+
reddit_force_json: -> { ForceJson },
|
17
|
+
reddit_modhash: -> { Modhash },
|
18
|
+
reddit_rate_limit: -> { RateLimit }
|
17
19
|
end
|
18
20
|
end
|
19
21
|
end
|
@@ -1,48 +1,62 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
1
3
|
require 'faraday'
|
2
4
|
|
3
|
-
module FaradayMiddleware
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
5
|
+
module FaradayMiddleware
|
6
|
+
module Reddit
|
7
|
+
# Request middleware that automatically handles user login.
|
8
|
+
#
|
9
|
+
# Requires that either a `user` and `password` are provided or a
|
10
|
+
# pre-generated `cookie`. Performs an additional login request when no
|
11
|
+
# valid login cookie is available.
|
12
|
+
class Authentication < Faraday::Middleware
|
13
|
+
AUTH_URL = 'https://ssl.reddit.com/post/login'.freeze
|
14
|
+
|
15
|
+
dependency do
|
16
|
+
require 'json' unless defined?(::JSON)
|
17
|
+
end
|
15
18
|
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
19
|
+
def initialize(app, options)
|
20
|
+
super(app)
|
21
|
+
@options = options
|
22
|
+
@user = @options[:user]
|
23
|
+
@passwd = @options[:password]
|
24
|
+
@rem = @options[:remember]
|
25
|
+
@access_token = @options[:access_token]
|
26
|
+
@cookie = @options[:cookie]
|
23
27
|
|
24
|
-
|
25
|
-
|
28
|
+
unless (@options[:user] && @options[:password]) || @options[:cookie] || @options[:access_token]
|
29
|
+
fail ArgumentError, 'Either `user` and `password`, `cookie`, or `access_token` need to be provided as options to the :reddit_authentication middleware'
|
30
|
+
end
|
26
31
|
end
|
27
|
-
end
|
28
32
|
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
33
|
+
def call(env)
|
34
|
+
if @access_token
|
35
|
+
apply_access_token(env)
|
36
|
+
elsif @cookie
|
37
|
+
apply_cookie(env)
|
38
|
+
else
|
39
|
+
authenticate(env)
|
40
|
+
end
|
34
41
|
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
42
|
+
@app.call(env)
|
43
|
+
end
|
44
|
+
|
45
|
+
def apply_access_token(env)
|
46
|
+
env.url.scheme = 'https'
|
47
|
+
env.url.port = 443
|
48
|
+
env.url.host = 'oauth.reddit.com'
|
49
|
+
env[:request_headers]['Authorization'] = "bearer #{@access_token}"
|
50
|
+
end
|
51
|
+
|
52
|
+
def apply_cookie(env)
|
53
|
+
upstream_cookies = env[:request_headers]['Cookie']
|
54
|
+
env[:request_headers]['Cookie'] = upstream_cookies ? "#{upstream_cookies}; #{@cookie}" : @cookie
|
55
|
+
end
|
39
56
|
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
"#{upstream_cookies}; #{@cookie}"
|
44
|
-
else
|
45
|
-
@cookie
|
57
|
+
def authenticate(env)
|
58
|
+
response = Faraday.post AUTH_URL, user: @user, passwd: @passwd, rem: @rem, api_type: 'json'
|
59
|
+
@cookie = response.headers['set-cookie']
|
46
60
|
end
|
47
61
|
end
|
48
62
|
end
|
@@ -1,41 +1,47 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
1
3
|
require 'faraday'
|
2
4
|
|
3
|
-
module FaradayMiddleware
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
5
|
+
module FaradayMiddleware
|
6
|
+
module Reddit
|
7
|
+
# Middleware that keeps track of and sets modhash-related HTTP headers.
|
8
|
+
#
|
9
|
+
# Reddit uses modhashes as a form of XSS protection and requires them for
|
10
|
+
# most POST and PUT requests. Modhashes are currently provided in response
|
11
|
+
# to listing GET requests.
|
12
|
+
class Modhash < Faraday::Middleware
|
13
|
+
dependency do
|
14
|
+
require 'json' unless defined?(::JSON)
|
15
|
+
end
|
13
16
|
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
17
|
+
def initialize(app, options = nil)
|
18
|
+
super(app)
|
19
|
+
@options = options || {}
|
20
|
+
@modhash = @options[:modhash]
|
21
|
+
end
|
19
22
|
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
23
|
+
def call(env)
|
24
|
+
@modhash = env[:modhash] if env[:modhash]
|
25
|
+
env[:request_headers]['X-Modhash'] = @modhash if @modhash
|
26
|
+
@app.call(env).on_complete do |response_env|
|
27
|
+
update_modhash(response_env)
|
28
|
+
end
|
25
29
|
end
|
26
|
-
end
|
27
30
|
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
31
|
+
def from_json(data)
|
32
|
+
if data.is_a?(String) && !data.strip.empty? && data.include?('modhash')
|
33
|
+
JSON.parse(data)
|
34
|
+
else
|
35
|
+
data
|
36
|
+
end
|
33
37
|
end
|
34
|
-
end
|
35
38
|
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
+
def update_modhash(env)
|
40
|
+
body = from_json(env[:body])
|
41
|
+
@modhash = body['data']['modhash'] if body['data']
|
42
|
+
rescue JSON::JSONError
|
43
|
+
# Ignore -- modhash can be acquired lazily.
|
44
|
+
end
|
39
45
|
end
|
40
46
|
end
|
41
47
|
end
|
@@ -1,46 +1,50 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
1
3
|
require 'faraday'
|
2
4
|
|
3
|
-
module FaradayMiddleware
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
5
|
+
module FaradayMiddleware
|
6
|
+
module Reddit
|
7
|
+
# Middleware for automatic rate limiting.
|
8
|
+
#
|
9
|
+
# Logs reddit's ratelimit HTTP headers and applies a caching strategy
|
10
|
+
# based on them. The default strategy is to block for x-ratelimit-reset /
|
11
|
+
# x-ratelimit_remaining.
|
12
|
+
class RateLimit < Faraday::Middleware
|
13
|
+
def initialize(app, options = nil)
|
14
|
+
super(app)
|
15
|
+
@options = options || {}
|
16
|
+
@strategy = @options[:strategy] || -> { burst_strategy }
|
17
|
+
|
18
|
+
# Default rate limit settings.
|
19
|
+
@ratelimit_remaining = 30
|
20
|
+
@ratelimit_used = 0
|
21
|
+
@ratelimit_reset = 60
|
22
|
+
@ratelimit_cap = 30
|
23
|
+
end
|
21
24
|
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
25
|
+
def call(env)
|
26
|
+
if @ratelimit_remaining <= 0 || env[:status] == 429
|
27
|
+
sleep(@ratelimit_reset)
|
28
|
+
else
|
29
|
+
@strategy.call
|
30
|
+
end
|
31
|
+
|
32
|
+
@app.call(env).on_complete { |response_env| on_complete_callback(response_env) }
|
27
33
|
end
|
28
34
|
|
29
|
-
|
35
|
+
def on_complete_callback(env)
|
30
36
|
@ratelimit_remaining = env[:response_headers]['x-ratelimit-remaining'].to_i
|
31
37
|
@ratelimit_used = env[:response_headers]['x-ratelimit-used'].to_i
|
32
38
|
@ratelimit_reset = env[:response_headers]['x-ratelimit-reset'].to_i
|
33
39
|
@ratelimit_cap = @ratelimit_remaining + @ratelimit_used
|
34
40
|
end
|
35
|
-
end
|
36
41
|
|
37
|
-
|
38
|
-
|
39
|
-
|
42
|
+
def linear_strategy
|
43
|
+
sleep @ratelimit_reset.to_f / [1, @ratelimit_remaining].max
|
44
|
+
end
|
40
45
|
|
41
|
-
|
42
|
-
|
43
|
-
linear_strategy
|
46
|
+
def burst_strategy(threshold = 0.5)
|
47
|
+
linear_strategy if (@ratelimit_used / @ratelimit_cap.to_f) > threshold
|
44
48
|
end
|
45
49
|
end
|
46
50
|
end
|
data/spec/helper.rb
CHANGED
metadata
CHANGED
@@ -1,20 +1,18 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: faraday_middleware-reddit
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
5
|
-
prerelease:
|
4
|
+
version: 0.3.0
|
6
5
|
platform: ruby
|
7
6
|
authors:
|
8
7
|
- Daniel O'Brien
|
9
8
|
autorequire:
|
10
9
|
bindir: bin
|
11
10
|
cert_chain: []
|
12
|
-
date: 2014-04-
|
11
|
+
date: 2014-04-25 00:00:00.000000000 Z
|
13
12
|
dependencies:
|
14
13
|
- !ruby/object:Gem::Dependency
|
15
14
|
name: bundler
|
16
15
|
requirement: !ruby/object:Gem::Requirement
|
17
|
-
none: false
|
18
16
|
requirements:
|
19
17
|
- - ~>
|
20
18
|
- !ruby/object:Gem::Version
|
@@ -22,7 +20,6 @@ dependencies:
|
|
22
20
|
type: :development
|
23
21
|
prerelease: false
|
24
22
|
version_requirements: !ruby/object:Gem::Requirement
|
25
|
-
none: false
|
26
23
|
requirements:
|
27
24
|
- - ~>
|
28
25
|
- !ruby/object:Gem::Version
|
@@ -30,23 +27,20 @@ dependencies:
|
|
30
27
|
- !ruby/object:Gem::Dependency
|
31
28
|
name: rake
|
32
29
|
requirement: !ruby/object:Gem::Requirement
|
33
|
-
none: false
|
34
30
|
requirements:
|
35
|
-
- -
|
31
|
+
- - '>='
|
36
32
|
- !ruby/object:Gem::Version
|
37
33
|
version: '0'
|
38
34
|
type: :development
|
39
35
|
prerelease: false
|
40
36
|
version_requirements: !ruby/object:Gem::Requirement
|
41
|
-
none: false
|
42
37
|
requirements:
|
43
|
-
- -
|
38
|
+
- - '>='
|
44
39
|
- !ruby/object:Gem::Version
|
45
40
|
version: '0'
|
46
41
|
- !ruby/object:Gem::Dependency
|
47
42
|
name: faraday
|
48
43
|
requirement: !ruby/object:Gem::Requirement
|
49
|
-
none: false
|
50
44
|
requirements:
|
51
45
|
- - ~>
|
52
46
|
- !ruby/object:Gem::Version
|
@@ -54,7 +48,6 @@ dependencies:
|
|
54
48
|
type: :runtime
|
55
49
|
prerelease: false
|
56
50
|
version_requirements: !ruby/object:Gem::Requirement
|
57
|
-
none: false
|
58
51
|
requirements:
|
59
52
|
- - ~>
|
60
53
|
- !ruby/object:Gem::Version
|
@@ -62,7 +55,6 @@ dependencies:
|
|
62
55
|
- !ruby/object:Gem::Dependency
|
63
56
|
name: faraday_middleware
|
64
57
|
requirement: !ruby/object:Gem::Requirement
|
65
|
-
none: false
|
66
58
|
requirements:
|
67
59
|
- - ~>
|
68
60
|
- !ruby/object:Gem::Version
|
@@ -70,7 +62,6 @@ dependencies:
|
|
70
62
|
type: :runtime
|
71
63
|
prerelease: false
|
72
64
|
version_requirements: !ruby/object:Gem::Requirement
|
73
|
-
none: false
|
74
65
|
requirements:
|
75
66
|
- - ~>
|
76
67
|
- !ruby/object:Gem::Version
|
@@ -83,6 +74,7 @@ extensions: []
|
|
83
74
|
extra_rdoc_files: []
|
84
75
|
files:
|
85
76
|
- .gitignore
|
77
|
+
- .rubocop.yml
|
86
78
|
- Gemfile
|
87
79
|
- LICENSE
|
88
80
|
- README.md
|
@@ -98,27 +90,26 @@ files:
|
|
98
90
|
homepage: ''
|
99
91
|
licenses:
|
100
92
|
- Apache 2.0
|
93
|
+
metadata: {}
|
101
94
|
post_install_message:
|
102
95
|
rdoc_options: []
|
103
96
|
require_paths:
|
104
97
|
- lib
|
105
98
|
required_ruby_version: !ruby/object:Gem::Requirement
|
106
|
-
none: false
|
107
99
|
requirements:
|
108
|
-
- -
|
100
|
+
- - '>='
|
109
101
|
- !ruby/object:Gem::Version
|
110
102
|
version: '0'
|
111
103
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
112
|
-
none: false
|
113
104
|
requirements:
|
114
|
-
- -
|
105
|
+
- - '>='
|
115
106
|
- !ruby/object:Gem::Version
|
116
107
|
version: '0'
|
117
108
|
requirements: []
|
118
109
|
rubyforge_project:
|
119
|
-
rubygems_version:
|
110
|
+
rubygems_version: 2.2.2
|
120
111
|
signing_key:
|
121
|
-
specification_version:
|
112
|
+
specification_version: 4
|
122
113
|
summary: A collection of Faraday middleware for use with the Reddit API.
|
123
114
|
test_files:
|
124
115
|
- spec/helper.rb
|