Skip to content
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
139 changes: 70 additions & 69 deletions lib/salesmachine/api/client.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,20 +12,20 @@ class Client
# public: Creates a new client
#
# attrs - Hash
# :api_key - String of your project's api_key
# :api_token - String of your project's api_token
# :max_queue_size - Fixnum of the max calls to remain queued (optional)
# :on_error - Proc which handles error calls from the API
def initialize attrs = {}
symbolize_keys! attrs

@queue = Queue.new
@api_key = attrs[:api_key]
@api_token = attrs[:api_token]
@max_queue_size = attrs[:max_queue_size] || Config::Queue::MAX_SIZE
@options = attrs
@worker_mutex = Mutex.new
@worker = Worker.new @queue, @api_key, @options
@worker = Worker.new @queue, @api_token, @options

check_api_key!
check_api_token!

at_exit { @worker_thread && @worker_thread[:should_exit] = true }
end
Expand All @@ -46,23 +46,23 @@ def flush
# attrs - Hash
def track attrs
symbolize_keys! attrs
check_contact_id! attrs
check_contact_uid! attrs

event = attrs[:event]
event_uid = attrs[:event_uid]
params = attrs[:params] || {}
created_at = attrs[:created_at] || Time.new

check_timestamp! created_at

if event.nil? || event.empty?
fail ArgumentError, 'Must supply event as a non-empty string'
if event_uid.nil? || event_uid.empty?
fail ArgumentError, 'Must supply event_uid as a non-empty string'
end

fail ArgumentError, 'Params must be a Hash' unless params.is_a? Hash
isoify_dates! params

enqueue({
:event => event,
:event_uid => event_uid,
:contact_uid => attrs[:contact_uid],
:params => params,
:created_at => datetime_in_iso8601(created_at),
Expand All @@ -75,35 +75,39 @@ def track attrs
# attrs - Hash
def email attrs
symbolize_keys! attrs
check_contact_id! attrs
check_contact_uid! attrs

email = attrs[:email]
params = attrs[:params] || {}
created_at = attrs[:created_at] || Time.new

check_timestamp! created_at

if email.nil? || evemailent.empty?
if email.nil? || email.empty?
fail ArgumentError, 'Must supply email template as a non-empty string'
end

fail ArgumentError, 'Params must be a Hash' unless params.is_a? Hash
isoify_dates! params

enqueue({
:event => event,
msg = enqueue({
:email => email,
:contact_uid => attrs[:contact_uid],
:params => params,
:created_at => datetime_in_iso8601(created_at),
:method => 'email'
})

flush if msg
msg
end


def contact attrs
symbolize_keys! attrs
check_contact_id! attrs
check_contact_uid! attrs

contact_uid = attrs[:contact_uid]
params = attrs[:params] || {}
created_at = attrs[:created_at] || Time.new

Expand All @@ -113,7 +117,7 @@ def contact attrs
isoify_dates! params

enqueue({
:contact_uid => attrs[:contact_uid],
:contact_uid => contact_uid,
:params => params,
:created_at => datetime_in_iso8601(created_at),
:method => 'contact'
Expand All @@ -123,7 +127,7 @@ def contact attrs

def account(attrs)
symbolize_keys! attrs
fail ArgumentError, 'Must supply a contact_uid' unless attrs[:account_uid]
fail ArgumentError, 'Must supply a account_uid' unless attrs[:account_uid]

account_uid = attrs[:account_uid]
params = attrs[:params] || {}
Expand All @@ -144,7 +148,7 @@ def account(attrs)

def pageview(attrs)
symbolize_keys! attrs
check_contact_id! attrs
check_contact_uid! attrs

params = attrs[:params] || {}
created_at = attrs[:created_at] || Time.new
Expand All @@ -156,80 +160,77 @@ def pageview(attrs)

enqueue({
:contact_uid => attrs[:contact_uid],
:event => "pageview",
:event_uid => "pageview",
:params => attrs[:params],
:created_at => datetime_in_iso8601(created_at),
:method => 'pageview'
:method => 'event'
})
end

# public: Returns the number of queued messages
#
# returns Fixnum of messages in the queue
def queued_messages
def queued_nb
@queue.length
end

private

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The rest of the file did not change, I only indented to highlight the fact that following methods are private

# private: Enqueues the action.
#
# returns Boolean of whether the item was added to the queue.
def enqueue(action)
# add our request id for tracing purposes
action[:messageId] = uid
unless queue_full = @queue.length >= @max_queue_size
ensure_worker_running
@queue << action
# private: Enqueues the action.
#
# returns Boolean of whether the item was added to the queue.
def enqueue(action)
# add our request id for tracing purposes
action[:messageId] = create_uid()
unless queue_full = @queue.length >= @max_queue_size
ensure_worker_running
@queue << action
end
queue_full ? !queue_full : action
end
!queue_full
end

# private: Ensures that a string is non-empty
#
# obj - String|Number that must be non-blank
# name - Name of the validated value
#
def check_presence!(obj, name)
if obj.nil? || (obj.is_a?(String) && obj.empty?)
fail ArgumentError, "#{name} must be given"
# private: Ensures that a string is non-empty
#
# obj - String|Number that must be non-blank
# name - Name of the validated value
#
def check_presence!(obj, name)
if obj.nil? || (obj.is_a?(String) && obj.empty?)
fail ArgumentError, "#{name} must be given"
end
end
end

# private: Adds contextual information to the call
#
# context - Hash of call context
def add_context(context)
context[:library] = { :name => "salesmachine-ruby", :version => Salesmachine::Api::VERSION.to_s }
end
# private: Adds contextual information to the call
#
# context - Hash of call context
def add_context(context)
context[:library] = { :name => "salesmachine-ruby", :version => Salesmachine::Api::VERSION.to_s }
end

# private: Checks that the api_key is properly initialized
def check_api_key!
fail ArgumentError, 'Api key must be initialized' if @api_key.nil?
end
# private: Checks that the api_token is properly initialized
def check_api_token!
fail ArgumentError, 'Api key must be initialized' if @api_token.nil?
end

# private: Checks the timstamp option to make sure it is a Time.
def check_timestamp!(timestamp)
fail ArgumentError, 'Timestamp must be a Time' unless timestamp.is_a? Time
end
# private: Checks the timstamp option to make sure it is a Time.
def check_timestamp!(timestamp)
fail ArgumentError, 'Timestamp must be a Time' unless timestamp.is_a? Time
end

def check_contact_id! attrs
fail ArgumentError, 'Must supply a contact_uid' unless attrs[:contact_uid]
end
def check_contact_uid! attrs
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Except for the name of this function

fail ArgumentError, 'Must supply a contact_uid' unless attrs[:contact_uid]
end

def ensure_worker_running
return if worker_running?
@worker_mutex.synchronize do
def ensure_worker_running
return if worker_running?
@worker_thread = Thread.new do
@worker.run
@worker_mutex.synchronize do
return if worker_running?
@worker_thread = Thread.new do
@worker.run
end
end
end
end

def worker_running?
@worker_thread && @worker_thread.alive?
end
def worker_running?
@worker_thread && @worker_thread.alive?
end
end
end
end
2 changes: 1 addition & 1 deletion lib/salesmachine/api/config.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ module Config
module Request
HOST = 'play.salesmachine.net'
PORT = 443
PATH = '/v1/bulk'
PATH = '/v1/batch'
SSL = true
HEADERS = { :accept => 'application/json' }
RETRIES = 4
Expand Down
13 changes: 6 additions & 7 deletions lib/salesmachine/api/request.rb
Original file line number Diff line number Diff line change
Expand Up @@ -36,33 +36,32 @@ def initialize(options = {})
# public: Posts the write key and batch of messages to the API.
#
# returns - Response of the status and error if it exists
def post(api_key, batch)
def post(api_token, batch)
status, error = nil, nil
remaining_retries = @retries
backoff = @backoff
headers = { 'Content-Type' => 'application/json', 'accept' => 'application/json' }
begin
# payload = JSON.generate :api_token=>api_key, :encode=>"base64", :data=>batch
payload = batch.to_json

request = Net::HTTP::Post.new(@path, headers)
request.basic_auth api_key, api_key
request.basic_auth api_token, api_token

if self.class.stub
status = 200
error = nil
logger.debug "stubbed request to #{@path}: write key = #{api_key}, payload = #{payload}"
logger.debug "stubbed request to #{@path}: write key = #{api_token}, payload = #{payload}"
else
res = @http.request(request, payload)

status = res.code.to_i
unless status==200 or status==201
unless status == 200 or status == 201
body = JSON.parse(res.body)
error = body["error"]
error = body["error"]
end
end
rescue Exception => e
unless (remaining_retries -=1).zero?
unless (remaining_retries -= 1).zero?
sleep(backoff)
retry
end
Expand Down
2 changes: 1 addition & 1 deletion lib/salesmachine/api/utils.rb
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ def isoify_dates!(hash)

# public: Returns a uid string
#
def uid
def create_uid
arr = SecureRandom.random_bytes(16).unpack("NnnnnN")
arr[2] = (arr[2] & 0x0fff) | 0x4000
arr[3] = (arr[3] & 0x3fff) | 0x8000
Expand Down
8 changes: 4 additions & 4 deletions lib/salesmachine/api/worker.rb
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,15 @@ class Worker
# and makes requests to the salesmachine.io api
#
# queue - Queue synchronized between client and worker
# api_key - String of the application's Api key
# api_token - String of the application's Api key
# options - Hash of worker options
# batch_size - Fixnum of how many items to send in a batch
# on_error - Proc of what to do on an error
#
def initialize(queue, api_key, options = {})
def initialize(queue, api_token, options = {})
symbolize_keys! options
@queue = queue
@api_key = api_key
@api_token = api_token
@batch_size = options[:batch_size] || Queue::BATCH_SIZE
@on_error = options[:on_error] || Proc.new { |status, error| }
@batch = []
Expand All @@ -41,7 +41,7 @@ def run
end
end

res = Request.new.post @api_key, @batch
res = Request.new.post @api_token, @batch

@lock.synchronize { @batch.clear }

Expand Down
4 changes: 2 additions & 2 deletions salesmachine-ruby.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ require 'salesmachine/api/version'
Gem::Specification.new do |spec|
spec.name = "salesmachine-ruby"
spec.version = Salesmachine::Api::VERSION
spec.authors = ["citizen75"]
spec.email = ["gsamoun@gmail.com"]
spec.authors = ["salesmachine-team"]
spec.email = ["support@salesmachine.io"]

spec.summary = %q{TODO: Write a short summary, because Rubygems requires one.}
spec.description = %q{TODO: Write a longer description or delete this line.}
Expand Down
3 changes: 1 addition & 2 deletions spec/salesmachine/account_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,11 @@ class Api

describe '#account' do
before :all do
@client = Client.new :api_key => API_KEY
@client = Client.new :api_token => API_TOKEN
@queue = @client.instance_variable_get :@queue
end

after :each do
# @queue.clear
@client.flush
end

Expand Down
10 changes: 5 additions & 5 deletions spec/salesmachine/api_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,16 @@ class Api
describe Client do

describe '#initialize' do
it 'should error if no api_key is supplied' do
it 'should error if no api_token is supplied' do
expect { Client.new }.to raise_error(ArgumentError)
end

it 'should not error if a api_key is supplied' do
Client.new :api_key => API_KEY
it 'should not error if a api_token is supplied' do
Client.new :api_token => API_TOKEN
end

it 'should not error if a api_key is supplied as a string' do
Client.new 'api_key' => API_KEY
it 'should not error if a api_token is supplied as a string' do
Client.new 'api_token' => API_TOKEN
end
end
end
Expand Down
Loading