powertrack_v2 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 224bad738e8ef15952bc6252b362d516de828de4
4
+ data.tar.gz: a0a7bf95a7223c9f1f18f9ae4134582549ee5f54
5
+ SHA512:
6
+ metadata.gz: 6a668a7da86f731575c161b2a3709e43ed10f4f820d0bd3bcee9ff74ca361c2ee3349eba4a0b6c53a61c7ae3a758d9343efcef734b833ef84b18a88781d89f6b
7
+ data.tar.gz: c377b9e8b4ccc673adbed23ab7dab9e2922f273698692c94d87b0c3b48beb7f5ec1686614f9f1c4d8d45c62d88e2a9b73a71c9f2e8d0fa4a81428b1fe5d124e0
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+ Copyright (c) 2016 NUVI
3
+
4
+ Permission is hereby granted, free of charge, to any person obtaining a copy of
5
+ this software and associated documentation files (the "Software"), to deal in
6
+ the Software without restriction, including without limitation the rights to
7
+ use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
8
+ the Software, and to permit persons to whom the Software is furnished to do so,
9
+ subject to the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be included in all
12
+ copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
16
+ FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
17
+ COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
18
+ IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
19
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20
+
21
+
data/README.md ADDED
@@ -0,0 +1,100 @@
1
+ PowerTrackV2
2
+ =
3
+
4
+ A Ruby client for managing PowerTrack 2.0 rules, as well as streaming.
5
+
6
+ Authentication
7
+ ==
8
+
9
+ First, authentication is managed through environment variables. If you're
10
+ unfamiliar with this practice, check out [The Rubyist's Guide to Environment
11
+ Variables](http://blog.honeybadger.io/ruby-guide-environment-variables/).
12
+
13
+ In your shell:
14
+
15
+ ```bash
16
+ export POWERTRACK_USERNAME=<your_username>
17
+ export POWERTRACK_PASSWORD=<your_password>
18
+ ```
19
+
20
+ Rule Management
21
+ ==
22
+
23
+ To add rules to your stream:
24
+
25
+ ```ruby
26
+ require 'powertrack_v2'
27
+
28
+ url = PowerTrackV2.rules_url(publisher, account_name, stream_label)
29
+
30
+ rules = [
31
+ PowerTrackV2::Rule.new('rule_value', 'optional_rule_tag'),
32
+ PowerTrackV2::Rule.new('another_value')
33
+ ]
34
+
35
+ response_body = PowerTrackV2.add_rules(url, rules)
36
+ ```
37
+
38
+ To remove rules from your stream:
39
+
40
+ ```ruby
41
+ require 'powertrack_v2'
42
+
43
+ url = PowerTrackV2.rules_url(publisher, account_name, stream_label)
44
+
45
+ rules = [
46
+ Rule.new('rule_value', 'optional_rule_tag'),
47
+ Rule.new('another_value')
48
+ ]
49
+
50
+ response_body = PowerTrackV2.remove_rules(url, rules)
51
+ ```
52
+
53
+ To get all rules for your stream:
54
+
55
+ ```ruby
56
+ require 'powertrack_v2'
57
+
58
+ url = PowerTrackV2.rules_url(publisher, account_name, stream_label)
59
+
60
+ response_body = PowerTrackV2.get_rules(url, rules)
61
+ ```
62
+
63
+ Streaming
64
+ ==
65
+
66
+ To stream from powertrack:
67
+
68
+ ```ruby
69
+ require 'powertrack_v2'
70
+
71
+ url = PowerTrackV2.stream_url(publisher, account, stream_label)
72
+
73
+ PowerTrackV2.stream(url) do |activity|
74
+ puts activity # or whatever you want to do with it.
75
+ end
76
+ ```
77
+
78
+ Some things to note about streaming:
79
+
80
+ 1. The stream function is infinitely blocking, so your streamer should be a
81
+ separate process from your rule manager process.
82
+ 1. Your block is called for every published activity.
83
+ 1. The published activity is a raw, unprocessed response from PowerTrack. This
84
+ library makes no assumptions about what you want to do with the data being
85
+ streamed in, and leaves processing up to you.
86
+ 1. If the connection drops, this library will automatically reconnect using an
87
+ exponential backoff algorithm.
88
+ 1. PowerTrack sends a "\\r\\n" heartbeat every few seconds. By default, the
89
+ streamer discards it so you don't have to worry about it. If you want it to
90
+ pass you the heartbeat, simply add an option to the stream function:
91
+
92
+ ```ruby
93
+ require 'powertrack_v2'
94
+
95
+ url = PowerTrackV2.stream_url(publisher, account, stream_label)
96
+
97
+ PowerTrackV2.stream(url, ignore_heartbeat: false) do |activity|
98
+ puts activity # or whatever you want to do with it.
99
+ end
100
+ ```
@@ -0,0 +1,28 @@
1
+ module PowerTrackV2
2
+ module Errors
3
+ class BadRequestError < StandardError; end
4
+ class UnauthorizedError < StandardError; end
5
+ class NoSuchResourceError < StandardError; end
6
+ class RateLimitedError < StandardError; end
7
+ class ServiceUnavailableError < StandardError; end
8
+ class UnexpectedStatusError < StandardError; end
9
+
10
+ class InvalidRuleError < StandardError; end
11
+ class TooManyRulesError < StandardError; end
12
+
13
+ ERROR_MAP = {
14
+ 400 => BadRequestError,
15
+ 401 => UnauthorizedError,
16
+ 404 => NoSuchResourceError,
17
+ 429 => RateLimitedError,
18
+ 503 => ServiceUnavailableError
19
+ }
20
+
21
+ def self.raise_error_for_code(code)
22
+ message = code.to_s
23
+
24
+ raise ERROR_MAP[code], message if ERROR_MAP[code]
25
+ raise UnexpectedStatusError, message
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,62 @@
1
+ require 'base64'
2
+ require 'httpclient'
3
+ require 'exponential_backoff'
4
+
5
+ module PowerTrackV2
6
+ module HTTP
7
+ def self.auth_digest(username, password)
8
+ ::Base64.strict_encode64("#{username}:#{password}")
9
+ end
10
+
11
+ def self.auth_header(auth_digest)
12
+ {'Authorization' => "Basic #{auth_digest}"}
13
+ end
14
+
15
+ def self.headers(headers = {})
16
+ username = ENV['POWERTRACK_USERNAME']
17
+ password = ENV['POWERTRACK_PASSWORD']
18
+
19
+ digest = auth_digest(username, password)
20
+ headers.merge auth_header(digest)
21
+ end
22
+
23
+ def self.get(url, headers={})
24
+ ::HTTPClient.get(url, nil, headers)
25
+ end
26
+
27
+ def self.post(url, body, headers={})
28
+ ::HTTPClient.post(url, body, headers)
29
+ end
30
+
31
+ def self.stream(url, headers = {}, opts = { ignore_heartbeat: true }, &block)
32
+ http = ::HTTPClient.new
33
+ backoff = ::ExponentialBackoff.new(1, 120)
34
+
35
+ while true
36
+ begin
37
+ connection = connect(url, headers)
38
+ stream_from(connection, opts, backoff, &block)
39
+ rescue StandardError => e
40
+ sleep(backoff.next_interval)
41
+ end
42
+ end
43
+ end
44
+
45
+ private
46
+
47
+ def self.connect(url, headers)
48
+ http = ::HTTPClient.new
49
+ http.get_async(url, nil, headers)
50
+ end
51
+
52
+ def self.stream_from(connection, opts, backoff, &block)
53
+ ignore_heartbeat = opts[:ignore_heartbeat]
54
+ content = connection.pop.content
55
+ backoff.clear
56
+ until connection.finished?
57
+ next_response = content.gets
58
+ block.call(next_response) unless ignore_heartbeat && next_response == "\r\n"
59
+ end
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,78 @@
1
+ require 'powertrack_v2/http'
2
+ require 'powertrack_v2/errors'
3
+ require 'multi_json'
4
+
5
+ module PowerTrackV2
6
+ class Rule
7
+ MAX_TAG_LENGTH = 255
8
+ MAX_VALUE_LENGTH = 2048
9
+
10
+ attr_accessor :value, :tag
11
+
12
+ def initialize(value, tag=nil)
13
+ @value = value
14
+ @tag = tag
15
+ end
16
+
17
+ def as_json
18
+ hash = {
19
+ value: @value
20
+ }
21
+ hash[:tag] = @tag if @tag && !@tag.empty?
22
+ hash
23
+ end
24
+
25
+ def valid?
26
+ return false if @value.nil? || @value.length > MAX_VALUE_LENGTH
27
+ return false if @tag && @tag.length > MAX_TAG_LENGTH
28
+ true
29
+ end
30
+
31
+ def self.url(publisher, account, stream_label)
32
+ "https://gnip-api.#{publisher}.com/rules/powertrack/accounts/#{account}/publishers/#{publisher}/#{stream_label}.json"
33
+ end
34
+
35
+ def self.get(url, optional_headers={})
36
+ headers = PowerTrackV2::HTTP.headers(optional_headers)
37
+ response = PowerTrackV2::HTTP.get(url, headers)
38
+ handle_response(response)
39
+ end
40
+
41
+ def self.handle_response(response)
42
+ return response.body if response.status == 200 || response.status < 300
43
+ return PowerTrackV2::Errors.raise_error_for_code(response.status)
44
+ end
45
+
46
+ DEFAULT_POST_HEADERS = {
47
+ 'Content-Type' => 'application/json'
48
+ }
49
+
50
+ def self.post(url, rules, optional_headers={})
51
+ validate(rules)
52
+
53
+ base_headers = DEFAULT_POST_HEADERS.merge(optional_headers)
54
+ headers = PowerTrackV2::HTTP.headers(base_headers)
55
+
56
+ body = prepare_rules(rules)
57
+
58
+ response = PowerTrackV2::HTTP.post(url, body, headers)
59
+ handle_response(response)
60
+ end
61
+
62
+ def self.delete(url, rules, optional_headers={})
63
+ post(url + '?_method=delete', rules, optional_headers)
64
+ end
65
+
66
+ def self.validate(rules)
67
+ raise ::PowerTrackV2::Errors::TooManyRulesError if rules.length > 5000
68
+ raise ::PowerTrackV2::Errors::InvalidRuleError unless rules.all? &:valid?
69
+ end
70
+
71
+ private
72
+
73
+ def self.prepare_rules(rules)
74
+ rules = rules.map {|rule| rule.as_json}
75
+ ::MultiJson.dump({rules: rules})
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,12 @@
1
+ module PowerTrackV2
2
+ module Stream
3
+ def self.url(publisher, account, stream_label)
4
+ "https://gnip-stream.#{publisher}.com/stream/powertrack/accounts/#{account}/publishers/#{publisher}/#{stream_label}.json"
5
+ end
6
+
7
+ def self.stream(url, opts = { ignore_heartbeat: true }, &block)
8
+ headers = PowerTrackV2::HTTP.headers
9
+ PowerTrackV2::HTTP.stream(url, headers, opts, &block)
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,30 @@
1
+ require 'powertrack_v2/rule'
2
+ require 'powertrack_v2/stream'
3
+ require 'powertrack_v2/http'
4
+ require 'powertrack_v2/errors'
5
+
6
+ module PowerTrackV2
7
+ def self.stream_url(publisher, account, stream_label)
8
+ PowerTrackV2::Stream.url(publisher, account, stream_label)
9
+ end
10
+
11
+ def self.rules_url(publisher, account, stream_label)
12
+ PowerTrackV2::Rule.url(publisher, account, stream_label)
13
+ end
14
+
15
+ def self.add_rules(url, rules, optional_headers = {})
16
+ PowerTrackV2::Rule.post(url, rules, optional_headers)
17
+ end
18
+
19
+ def self.remove_rules(url, rules, optional_headers = {})
20
+ PowerTrackV2::Rule.delete(url, rules, optional_headers)
21
+ end
22
+
23
+ def self.get_rules(url, optional_headers = {})
24
+ PowerTrackV2::Rule.get(url, optional_headers)
25
+ end
26
+
27
+ def self.stream(url, opts = { ignore_heartbeat: true }, &block)
28
+ PowerTrackV2::Stream.stream(url, opts, &block)
29
+ end
30
+ end
metadata ADDED
@@ -0,0 +1,192 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: powertrack_v2
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Cody Poll
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2016-04-05 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ requirement: !ruby/object:Gem::Requirement
15
+ requirements:
16
+ - - "~>"
17
+ - !ruby/object:Gem::Version
18
+ version: '2.7'
19
+ - - ">="
20
+ - !ruby/object:Gem::Version
21
+ version: 2.7.0
22
+ name: httpclient
23
+ prerelease: false
24
+ type: :runtime
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ requirements:
27
+ - - "~>"
28
+ - !ruby/object:Gem::Version
29
+ version: '2.7'
30
+ - - ">="
31
+ - !ruby/object:Gem::Version
32
+ version: 2.7.0
33
+ - !ruby/object:Gem::Dependency
34
+ requirement: !ruby/object:Gem::Requirement
35
+ requirements:
36
+ - - "~>"
37
+ - !ruby/object:Gem::Version
38
+ version: '2.16'
39
+ - - ">="
40
+ - !ruby/object:Gem::Version
41
+ version: 2.16.0
42
+ name: march_hare
43
+ prerelease: false
44
+ type: :runtime
45
+ version_requirements: !ruby/object:Gem::Requirement
46
+ requirements:
47
+ - - "~>"
48
+ - !ruby/object:Gem::Version
49
+ version: '2.16'
50
+ - - ">="
51
+ - !ruby/object:Gem::Version
52
+ version: 2.16.0
53
+ - !ruby/object:Gem::Dependency
54
+ requirement: !ruby/object:Gem::Requirement
55
+ requirements:
56
+ - - "~>"
57
+ - !ruby/object:Gem::Version
58
+ version: 0.0.2
59
+ name: exponential-backoff
60
+ prerelease: false
61
+ type: :runtime
62
+ version_requirements: !ruby/object:Gem::Requirement
63
+ requirements:
64
+ - - "~>"
65
+ - !ruby/object:Gem::Version
66
+ version: 0.0.2
67
+ - !ruby/object:Gem::Dependency
68
+ requirement: !ruby/object:Gem::Requirement
69
+ requirements:
70
+ - - "~>"
71
+ - !ruby/object:Gem::Version
72
+ version: '1.11'
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: 1.11.2
76
+ name: multi_json
77
+ prerelease: false
78
+ type: :runtime
79
+ version_requirements: !ruby/object:Gem::Requirement
80
+ requirements:
81
+ - - "~>"
82
+ - !ruby/object:Gem::Version
83
+ version: '1.11'
84
+ - - ">="
85
+ - !ruby/object:Gem::Version
86
+ version: 1.11.2
87
+ - !ruby/object:Gem::Dependency
88
+ requirement: !ruby/object:Gem::Requirement
89
+ requirements:
90
+ - - "~>"
91
+ - !ruby/object:Gem::Version
92
+ version: 0.10.3
93
+ name: pry
94
+ prerelease: false
95
+ type: :development
96
+ version_requirements: !ruby/object:Gem::Requirement
97
+ requirements:
98
+ - - "~>"
99
+ - !ruby/object:Gem::Version
100
+ version: 0.10.3
101
+ - !ruby/object:Gem::Dependency
102
+ requirement: !ruby/object:Gem::Requirement
103
+ requirements:
104
+ - - "~>"
105
+ - !ruby/object:Gem::Version
106
+ version: 0.2.4
107
+ name: pry-nav
108
+ prerelease: false
109
+ type: :development
110
+ version_requirements: !ruby/object:Gem::Requirement
111
+ requirements:
112
+ - - "~>"
113
+ - !ruby/object:Gem::Version
114
+ version: 0.2.4
115
+ - !ruby/object:Gem::Dependency
116
+ requirement: !ruby/object:Gem::Requirement
117
+ requirements:
118
+ - - "~>"
119
+ - !ruby/object:Gem::Version
120
+ version: '1.8'
121
+ - - ">="
122
+ - !ruby/object:Gem::Version
123
+ version: 1.8.3
124
+ name: json_pure
125
+ prerelease: false
126
+ type: :development
127
+ version_requirements: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - "~>"
130
+ - !ruby/object:Gem::Version
131
+ version: '1.8'
132
+ - - ">="
133
+ - !ruby/object:Gem::Version
134
+ version: 1.8.3
135
+ - !ruby/object:Gem::Dependency
136
+ requirement: !ruby/object:Gem::Requirement
137
+ requirements:
138
+ - - "~>"
139
+ - !ruby/object:Gem::Version
140
+ version: '5.8'
141
+ - - ">="
142
+ - !ruby/object:Gem::Version
143
+ version: 5.8.4
144
+ name: minitest
145
+ prerelease: false
146
+ type: :development
147
+ version_requirements: !ruby/object:Gem::Requirement
148
+ requirements:
149
+ - - "~>"
150
+ - !ruby/object:Gem::Version
151
+ version: '5.8'
152
+ - - ">="
153
+ - !ruby/object:Gem::Version
154
+ version: 5.8.4
155
+ description: A simple library for streaming from Powertrack 2.0, as well as managing rules for your stream.
156
+ email: developers@nuviapp.com
157
+ executables: []
158
+ extensions: []
159
+ extra_rdoc_files: []
160
+ files:
161
+ - LICENSE
162
+ - README.md
163
+ - lib/powertrack_v2.rb
164
+ - lib/powertrack_v2/errors.rb
165
+ - lib/powertrack_v2/http.rb
166
+ - lib/powertrack_v2/rule.rb
167
+ - lib/powertrack_v2/stream.rb
168
+ homepage: http://github.com/nuvi/powertrack_v2
169
+ licenses:
170
+ - MIT
171
+ metadata: {}
172
+ post_install_message:
173
+ rdoc_options: []
174
+ require_paths:
175
+ - lib
176
+ required_ruby_version: !ruby/object:Gem::Requirement
177
+ requirements:
178
+ - - ">="
179
+ - !ruby/object:Gem::Version
180
+ version: '0'
181
+ required_rubygems_version: !ruby/object:Gem::Requirement
182
+ requirements:
183
+ - - ">="
184
+ - !ruby/object:Gem::Version
185
+ version: '0'
186
+ requirements: []
187
+ rubyforge_project:
188
+ rubygems_version: 2.4.8
189
+ signing_key:
190
+ specification_version: 4
191
+ summary: Powertrack 2.0 client for Ruby
192
+ test_files: []