Skip to content

Commit

Permalink
v2.0.0: Remove support for PowerTrack v1 since this version was sunse…
Browse files Browse the repository at this point in the history
…t in early January 2017
  • Loading branch information
Laurent Farcy committed Jan 5, 2018
1 parent 93b58ab commit c7e3036
Show file tree
Hide file tree
Showing 11 changed files with 121 additions and 389 deletions.
2 changes: 1 addition & 1 deletion Gemfile
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
source 'https://rubygems.org'

group :test do
gem 'yajl-ruby', '~> 1.0', require: 'yajl'
gem 'yajl-ruby', '~> 1.3.1', require: 'yajl'
end

# Specify your gem's dependencies in powertrack-rb.gemspec
Expand Down
9 changes: 6 additions & 3 deletions Gemfile.lock
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
PATH
remote: .
specs:
powertrack (1.3.1)
powertrack (2.0.0)
em-http-request (~> 1.1)
eventmachine (~> 1.0)
exponential-backoff (~> 0.0.2)
Expand Down Expand Up @@ -29,7 +29,7 @@ GEM
rake (10.4.2)
ruby-prof (0.15.8)
void_logger (0.1)
yajl-ruby (1.2.1)
yajl-ruby (1.3.1)

PLATFORMS
ruby
Expand All @@ -40,4 +40,7 @@ DEPENDENCIES
powertrack!
rake (~> 10.3)
ruby-prof (~> 0.15)
yajl-ruby (~> 1.0)
yajl-ruby (~> 1.3.1)

BUNDLED WITH
1.10.6
8 changes: 7 additions & 1 deletion History.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,10 @@
v1.3.0
v2.0.0
------

* Remove support for PowerTrack v1 since this version was sunset in early
January 2017

v1.3.1
------

* Add the PowerTrack::Stream.v2? instance method
Expand Down
12 changes: 8 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -128,16 +128,20 @@ replaying the same timeframe again and again when GNIP is unstable.
All the errors that come from PowerTrack are defined through an ad-hoc exception
class hierarchy. See ```lib/powertrack/errors.rb```.

## PowerTrack v1

The library was originally designed for PowerTrack v1. But this version of the
PowerTrack API was sunset in early January 2017.

Consequently, since v2.0, the library does not support v1 anymore.

## PowerTrack v2

The library provides early support for PowerTrack API version 2. Please read
The library provides support for PowerTrack API version 2. Please read
[PowerTrack API v2](http://support.gnip.com/apis/powertrack2.0/index.html) and
the [Migration Guide](http://support.gnip.com/apis/powertrack2.0/transition.html)
for details about this new major release.

Set the ```:v2```option to ```true``` when building a ```PowerTrack::Stream```
object to enable this feature. The library uses v1 by default.

Everything should work the same for v2 as for v1 except

o ```PowerTrack::Stream.add_rule``` and ```PowerTrack::Stream.delete_rule```
Expand Down
87 changes: 14 additions & 73 deletions lib/powertrack/rules/rule.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,8 @@ class Rule
# The maximum length of a rule tag.
MAX_TAG_LENGTH = 255

# The maximum lengh of the value of a standard rule
MAX_STD_RULE_VALUE_LENGTH = 1024

# The maximum lengh of the value of a long rule
MAX_LONG_RULE_VALUE_LENGTH = 2048
# The maximum lengh of the value of a rule
MAX_RULE_VALUE_LENGTH = 2048

# The maximum number of positive terms in a single rule value
MAX_POSITIVE_TERMS = 30
Expand All @@ -20,58 +17,29 @@ class Rule
MAX_NEGATIVE_TERMS = 50

# The maximum size of the HTTP body accepted by PowerTrack /rules calls (in bytes)
# 1 MB for v1, 5MB for v2
MAX_RULES_BODY_SIZE = {
v1: 1024**2,
v2: 5*1024**2
}
# 5MB since v2
MAX_RULES_BODY_SIZE = 5*1024**2

# The default rule features
DEFAULT_RULE_FEATURES = {
# no id by default
id: nil,
# no tag by default
tag: nil,
# long determined by value length
long: nil,
# v1 by default
v2: false
tag: nil
}.freeze

attr_reader :value, :id, :tag, :error

# Builds a new rule based on a value and some optional features
# (:id, :tag, :long, :v2).
#
# By default, the constructor assesses if it's a long rule or not
# based on the length of the value. But the 'long' feature can be
# explicitly specified with the :long feature. Finally, if :v2 is
# true the rule is always considered long.
# (:id, :tag).
def initialize(value, features=nil)
@value = value || ''
features = DEFAULT_RULE_FEATURES.merge(features || {})
@tag = features[:tag]
@id = features[:id]
# only accept boolean values
_v2 = features[:v2]
@v2 = (_v2 == !!_v2) ? _v2 : false
# check if long is a boolean
_long = features[:long]
# v2 rules are always long
@long = (@v2 ? true : (_long == !!_long ? _long : @value.size > MAX_STD_RULE_VALUE_LENGTH))
@error = nil
end

# Returns true if the rule is long.
def long?
@long
end

# Returns true if the rule is v2.
def v2?
@v2
end

# Returns true if the rule is valid, false otherwise. The validation error
# can be through the error method.
def valid?
Expand All @@ -82,23 +50,12 @@ def valid?
:too_long_value?,
:contains_empty_source?,
:contains_negated_or?,
:too_long_tag?
:too_long_tag?,
:contains_explicit_and?,
:contains_lowercase_or?,
:contains_explicit_not?
]

if @v2
validation_rules += [
:contains_explicit_and?,
:contains_lowercase_or?,
:contains_explicit_not?
]
else
# no more restriction on the number of positive and negative terms in v2
validation_rules += [
:too_many_positive_terms?,
:too_many_negative_terms?
]
end

validation_rules.each do |validator|
# stop when 1 validator fails
if self.send(validator)
Expand Down Expand Up @@ -132,8 +89,7 @@ def to_s
def ==(other)
other.class == self.class &&
other.value == @value &&
other.tag == @tag &&
other.long? == self.long?
other.tag == @tag
end

alias eql? ==
Expand All @@ -142,13 +98,12 @@ def ==(other)
# rules as Hash keys.
def hash
# let's assume a nil value for @value or @tag is not different from the empty value
"v:#{@value},t:#{@tag},l:#{@long}".hash
"v:#{@value},t:#{@tag}".hash
end

# Returns the maximum length of the rule value according to the type of the
# rule (long or standard).
# Returns the maximum length of the rule value.
def max_value_length
long? ? MAX_LONG_RULE_VALUE_LENGTH : MAX_STD_RULE_VALUE_LENGTH
MAX_RULE_VALUE_LENGTH
end

protected
Expand Down Expand Up @@ -178,20 +133,6 @@ def contains_explicit_not?
!@value[/(^| )NOT /].nil?
end

# Does the rule value contain too many positive terms ?
def too_many_positive_terms?
return false if long?
# negative look-behind; see http://www.rexegg.com/regex-disambiguation.html
# exclude the OR operator from the terms being counted
@value.scan(/(?<!-)(\b[\w:]+|\"[\-\s\w:]+\"\b)/).select { |match| match.first != 'OR' }.size > MAX_POSITIVE_TERMS
end

# Does the rule value contain too many negative terms ?
def too_many_negative_terms?
return false if long?
@value.scan(/(^| )\-(\w|\([^(]*\)|\"[^"]*\")/).size > MAX_NEGATIVE_TERMS
end

# Does the rule value contain an empty source ?
def contains_empty_source?
!@value[/source\:\s/].nil?
Expand Down
77 changes: 22 additions & 55 deletions lib/powertrack/streaming/stream.rb
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,9 @@ class Stream
# Includes a logger, void by default
include VoidLogger::LoggerMixin

# The format of the URLs to connect to the various stream services
FEATURE_URL_FORMAT = {
# [ hostname, account, source, mode, label, feature ]
v1: "https://%s.gnip.com/accounts/%s/publishers/%s/%s/track/%s%s.json".freeze,
# [ hostname, domain, feature, stream type, account, source, label, sub-feature ]
v2: "https://gnip-%s.%s.com/%s/%s/accounts/%s/publishers/%s/%s%s.json".freeze
}.freeze
# The format of the URL to connect to the stream service
# [ hostname, domain, feature, stream type, account, source, label, sub-feature ]
FEATURE_URL_FORMAT = 'https://gnip-%s.%s.com/%s/%s/accounts/%s/publishers/%s/%s%s.json'.freeze

# The default timeout on a connection to PowerTrack. Can be overriden per call.
DEFAULT_CONNECTION_TIMEOUT = 30
Expand All @@ -34,14 +30,10 @@ class Stream

# The default options for using the stream.
DEFAULT_STREAM_OPTIONS = {
# enable PowerTrack v2 API (using v1 by default)
v2: false,
# override the default connection timeout
connect_timeout: DEFAULT_CONNECTION_TIMEOUT,
# override the default inactivity timeout
inactivity_timeout: DEFAULT_INACTIVITY_TIMEOUT,
# use a client id if you want to leverage the Backfill feature in v1
client_id: nil,
# enable the replay mode to get activities over the last 5 days
# see http://support.gnip.com/apis/replay/api_reference.html
replay: false
Expand All @@ -67,13 +59,6 @@ def initialize(username, password, account_name, data_source, label, options=nil
@label = label
@options = DEFAULT_STREAM_OPTIONS.merge(options || {})
@replay = !!@options[:replay]
@client_id = @options[:client_id]
@v2 = !!@options[:v2]
end

# Returns true if the stream uses PowerTrack v2
def v2?
@v2
end

# Adds many rules to your PowerTrack stream’s ruleset.
Expand All @@ -95,11 +80,11 @@ def add_rules(*rules)
# See http://support.gnip.com/apis/powertrack/api_reference.html#DeleteRules
def delete_rules(*rules)
# v2 does not use DELETE anymore
delete_verb = @v2 ? :post : :delete
delete_verb = :post
# flatten the rules in case it was provided as an array
delete_options = { body: MultiJson.encode('rules' => rules.flatten) }
# v2 uses a query parameter
delete_options[:query] = { '_method' => 'delete' } if @v2
delete_options[:query] = { '_method' => 'delete' }

make_rules_request(delete_verb, delete_options)
end
Expand Down Expand Up @@ -149,7 +134,7 @@ def list_rules(options=nil)
from: nil,
# the ending date to which the activities will be recovered (replay mode only)
to: nil,
# specify a number of minutes to leverage the Backfill feature (v2 only)
# specify a number of minutes to leverage the Backfill feature
backfill_minutes: nil,
# called for each message received, except heartbeats
on_message: nil,
Expand Down Expand Up @@ -181,39 +166,21 @@ def track(options=nil)

# Returns the URL of the stream for a given feature.
def feature_url(hostname, feature=nil, sub_feature=nil)
_url = nil
if @v2
feature ||= @replay ? 'replay' : hostname
sub_feature = sub_feature ? "/#{sub_feature}" : ''
stream_type = (feature == 'rules' && @replay ? 'powertrack-replay' : 'powertrack')
# replay streaming is on gnip.com while replay rules are on twitter.com...
domain = (feature == 'replay' && @replay ? 'gnip' : 'twitter')

_url = FEATURE_URL_FORMAT[:v2] %
[ hostname,
domain,
feature,
stream_type,
@account_name,
@data_source,
@label,
sub_feature ]
else
feature = feature ? "/#{feature}" : ''
mode = @replay ? 'replay' : 'streams'

_url = FEATURE_URL_FORMAT[:v1] %
[ hostname,
@account_name,
@data_source,
mode,
@label,
feature ]

_url += "?client=#{@client_id}" if @client_id
end

_url
feature ||= @replay ? 'replay' : hostname
sub_feature = sub_feature ? "/#{sub_feature}" : ''
stream_type = (feature == 'rules' && @replay ? 'powertrack-replay' : 'powertrack')
# replay streaming is on gnip.com while replay rules are on twitter.com...
domain = (feature == 'replay' && @replay ? 'gnip' : 'twitter')

FEATURE_URL_FORMAT %
[ hostname,
domain,
feature,
stream_type,
@account_name,
@data_source,
@label,
sub_feature ]
end

# Returns the HTTP header that turns on GZip-based compression if required.
Expand Down Expand Up @@ -396,7 +363,7 @@ def track_once(options, retrier)
logger.info "Replay mode enabled from '#{from}' to '#{to}'"
end

if @v2 && backfill_minutes
if backfill_minutes
get_opts[:query]['backfillMinutes'] = backfill_minutes
end

Expand Down
2 changes: 1 addition & 1 deletion lib/powertrack/version.rb
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
module PowerTrack
VERSION = '1.3.1'.freeze
VERSION = '2.0.0'.freeze
end
5 changes: 2 additions & 3 deletions test/minitest_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -30,14 +30,13 @@ def powertrack_config
end

# Returns a brand-new stream based on the config found in test/powertrack.yml.
def new_stream(v2=false, replay=false)
def new_stream(replay=false)
PowerTrack::Stream.new(
powertrack_config[:username],
powertrack_config[:password],
powertrack_config[:account_name],
powertrack_config[:data_source],
replay ? 'prod' : powertrack_config[:stream_label],
replay: replay,
v2: v2)
replay: replay)
end
end
Loading

0 comments on commit c7e3036

Please sign in to comment.