Commit 12d4053e authored by Sergey Gernyak's avatar Sergey Gernyak

Merge branch 'multiaccounting'

* multiaccounting: (29 commits)
  Passing api url to proxy tire 👍
  :running: specs
  Some additional logging 💩
  Fix hidden bug with keep_if :neckbeard:
  Fixes in logging
  Some logging
  Passing account name to account API methods
  FIX: run expiring said in connection
  Fix readme
  Some readme
  FIX: gemspec
  REF: provider requester is use account subsystem
  REF: session manager is use account subsystem
  Enhanced initialiser by setting up account manager
  Make am and asm method instead attributes
  FIX: specs
  Refactor SessionManager for multiaccounting
  Added to Account file paths for crt and key
  Passing application key to provider
  Fetching account in connection
  ...
parents 93ca4a74 ce6e658a
......@@ -6,7 +6,7 @@ API-NG is Betfair's next generation API for developers looking to create automat
Add this line to your application's Gemfile:
gem 'betfair_api_ng_rails', '1.5.0'
gem 'betfair_api_ng_rails', '2.0.0'
And then execute:
......@@ -37,6 +37,27 @@ In this files you must specify credentials to API-NG. Also you should notice tha
Please check [wiki pages](https://github.com/alterego-labs/betfair_api_ng_rails/wiki).
## CHANGES IN 2.0.0
One of the main features of this release was the multiaccounting.
Since version 1.5.0 is now available opportunity to place bets using placeOrders method. But at the same time there was another problem - to place bets in various Betfair accounts, and that the current implementation does not allow. Starting with version 2.0.0 is such an opportunity. But just be careful: if you want to use version 2.0.0 in an existing project, you have to do a small step:
```ruby
BetfairApiNgRails.config do |config|
# Rest of configuration same as for 1.5.0
# Setting up account
BetfairApiNgRails.account_manager.store BetfairApiNgRails::Account.new(config.username,
config.password,
config.application_key,
config.ssl_crt_filepath,
config.ssl_key_filepath)
BetfairApiNgRails.account_manager.default config.username
end
```
For additional info please visit [specific wiki page](https://github.com/alterego-labs/betfair_api_ng_rails/wiki/Multiaccounting).
## CHANGES IN 1.5.0
1. Add supporting **placeOrders** method
......
......@@ -18,14 +18,15 @@ Gem::Specification.new do |spec|
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
spec.require_paths = ["lib"]
spec.add_runtime_dependency 'activesupport', '>= 4.0.4'
spec.add_runtime_dependency 'rails', '>= 4.0.4'
spec.add_dependency "colorize", ">= 0.7.2"
spec.add_dependency "redis", '3.0.7'
spec.add_dependency "activesupport", '>= 3.0.0'
spec.add_development_dependency "bundler", "~> 1.3"
spec.add_development_dependency "rake", ">= 10.3.0"
# spec.add_development_dependency "activesupport", ">= 3.1.0"
spec.add_development_dependency "rspec", "~> 3.0.0.beta"
spec.add_development_dependency "rspec-its", "1.0.1"
spec.add_development_dependency "pry-nav", "0.2.3"
end
\ No newline at end of file
end
This diff is collapsed.
module BetfairApiNgRails
class Account < Struct.new(:username, :password, :app_key, :crt_filepath, :key_filepath)
end
end
require 'singleton'
module BetfairApiNgRails
class AccountManager
include Singleton
attr_reader :accounts
attr_reader :default_account
def initialize
clear
end
def store(account)
accounts[account.username] = account
end
def get(username)
accounts.fetch username, fetch_default_account
end
def default(username)
@default_account = username
end
def clear
@accounts = {}
end
private
def fetch_default_account
accounts.fetch default_account, nil
end
end
end
module BetfairApiNgRails
class AccountSession < Struct.new(:username, :ssoid)
end
end
require 'singleton'
module BetfairApiNgRails
class AccountSessionManager
include Singleton
attr_reader :sessions
def initialize
clear
end
def store(session)
sessions[session.username] = session
end
def get(username)
sessions.fetch(username, AccountSession.new).ssoid
end
def expire(username)
sessions.delete username
end
def clear
@sessions = {}
end
end
end
......@@ -2,7 +2,6 @@ module BetfairApiNgRails
module Api
module Caching
module Helper
def createsig(body)
Digest::MD5.hexdigest sigflat(body)
end
......@@ -29,8 +28,7 @@ module BetfairApiNgRails
end
res || body
end
end
end
end
end
\ No newline at end of file
end
......@@ -6,7 +6,6 @@ module BetfairApiNgRails
module Caching
class ResponseCache
include Api::Caching::Helper
attr_reader :method, :sig_params
def initialize(method, params)
......@@ -31,7 +30,7 @@ module BetfairApiNgRails
cache_adapter.expire cache_key, expire_time
end
private
private
def cache_result
@_cache_result ||= cache_adapter.get cache_key
......@@ -52,8 +51,7 @@ module BetfairApiNgRails
def cache_key
"betfair_api_ng_rails:#{method}:#{sig_params}"
end
end
end
end
end
\ No newline at end of file
end
......@@ -4,7 +4,6 @@ module BetfairApiNgRails
module Api
module Concerns
module Errorable
def has_errors?
!error_info.nil?
end
......@@ -12,8 +11,7 @@ module BetfairApiNgRails
def error_info
@http_responser.try(:error_info?)
end
end
end
end
end
\ No newline at end of file
end
require 'active_support/core_ext/module/delegation'
require "betfair_api_ng_rails/errors"
module BetfairApiNgRails
module Api
class Connection
attr_reader :account_name
delegate :app_key, :username, to: :account
def initialize(account_name)
BetfairApiNgRails.log.write("==> Initializing new connection #{self}")
@account_name = account_name
end
def request(method, params = {})
provider.fetch method: Api::RequestMethod.new(method), params: hashing(params)
end
......@@ -15,22 +25,29 @@ module BetfairApiNgRails
include Api::ConnectionExt::Formatting
def expire_provider
@_provider = nil
BetfairApiNgRails::Api::SessionManager.expire_ssoid account
end
protected
def provider
@_provider ||= BetfairApiNgRails::Api::Provider.new request_ssoid
BetfairApiNgRails::Api::Provider.new request_ssoid, app_key
end
def request_ssoid
BetfairApiNgRails::Api::SessionManager.new_ssoid
BetfairApiNgRails::Api::SessionManager.get_ssoid account
end
def hashing(params)
BetfairApiNgRails::Api::Hashalator.new(params).to_hash
end
def account
acc = BetfairApiNgRails.account_manager.get account_name
throw BetfairApiNgRails::NoAccountProvided unless acc
BetfairApiNgRails.log.write("==> Using account #{acc.username}")
acc
end
end
end
end
......@@ -4,18 +4,16 @@ module BetfairApiNgRails
module Api
class FormatterFactory
class << self
def initialize_formatter(name)
name.is_a?(Symbol) ? initialize_formatter_by(name: name) : name.try(:new)
end
private
private
def initialize_formatter_by(name: "")
"BetfairApiNgRails::Api::Formatters::#{name.to_s.camelize}Formatter".constantize.new
end
end
end
end
end
\ No newline at end of file
end
......@@ -5,14 +5,13 @@ module BetfairApiNgRails
module Api
module Formatters
class JsTreeFormatter
ALLOW_CHILDREN = [:event_types, :competitions]
def process(result, as: '')
result.map { |r| format_record(r, resource_from_method(as)) }
end
private
private
def resource_from_method(method)
method.underscore.gsub(/^list_/, '').to_sym
......@@ -31,8 +30,7 @@ module BetfairApiNgRails
}
}
end
end
end
end
end
\ No newline at end of file
end
......@@ -17,7 +17,7 @@ module BetfairApiNgRails
end
end
private
private
def hash_value(val)
need_to_hash?(val) ? hashing_val(val) : val
......@@ -34,7 +34,6 @@ module BetfairApiNgRails
def hash_key(key)
key.to_s.camelize(:lower)
end
end
end
end
\ No newline at end of file
end
......@@ -5,19 +5,19 @@ module BetfairApiNgRails
class << self
include Api::Constants
def provider_requester(api_url, ssoid = nil)
def provider_requester(api_url, ssoid = nil, app_key)
create_http_requester(api_url).tap do |req|
req.set_request_headers API_REQUEST_HEADERS
req.set_auth_headers Api::Config.application_key, ssoid
req.set_auth_headers app_key, ssoid
end
end
def session_requester
def session_requester(account)
create_http_requester(LOGIN_URL, false).tap do |req|
req.set_ssl_files Api::Config.ssl_crt_filepath, Api::Config.ssl_key_filepath
req.set_ssl_files account.crt_filepath, account.key_filepath
req.set_request_headers SESSION_REQUEST_HEADERS
req.set_auth_headers Api::Config.application_key
req.set_form_data "username" => Api::Config.username, "password" => Api::Config.password
req.set_auth_headers account.app_key
req.set_form_data "username" => account.username, "password" => account.password
end
end
......@@ -28,7 +28,7 @@ module BetfairApiNgRails
end
end
private
private
def create_http_requester(url = '', provider = true)
if !Api::Config.proxy_enable
......
......@@ -3,7 +3,6 @@ module BetfairApiNgRails
module Http
module Helpers
module InformationResponse
def self.included(base)
base.send :class_eval, <<-CODE
def has_error_with_info_response?
......@@ -18,7 +17,7 @@ module BetfairApiNgRails
result['result']
end
protected
protected
def info_response_error?
set_error_info(:API, result['error']) if check_info_response_status
......@@ -27,9 +26,8 @@ module BetfairApiNgRails
def check_info_response_status
result.has_key?('error')
end
end
end
end
end
end
\ No newline at end of file
end
......@@ -4,7 +4,7 @@ module BetfairApiNgRails
module Helpers
module KeepAliveResponse
include BetfairApiNgRails::Api::Constants
def self.included(base)
base.send :class_eval, <<-CODE
def has_error_with_keep_alive_response?
......@@ -15,7 +15,7 @@ module BetfairApiNgRails
CODE
end
protected
protected
def keep_alive_res_error?
set_error_info(:KEEP_ALIVE, result['status']) if check_keep_alive_status
......@@ -24,9 +24,8 @@ module BetfairApiNgRails
def check_keep_alive_status
result.fetch('status', SUCCESS_LOGIN) != SUCCESS_LOGIN
end
end
end
end
end
end
\ No newline at end of file
end
......@@ -4,7 +4,7 @@ module BetfairApiNgRails
module Helpers
module SessionResponse
include BetfairApiNgRails::Api::Constants
def self.included(base)
base.send :class_eval, <<-CODE
def has_error_with_session_response?
......@@ -19,7 +19,7 @@ module BetfairApiNgRails
result['sessionToken']
end
protected
protected
def session_res_error?
set_error_info(:SESSION, result['loginStatus']) if check_login_status
......@@ -28,9 +28,8 @@ module BetfairApiNgRails
def check_login_status
result.fetch('loginStatus', SUCCESS_LOGIN) != SUCCESS_LOGIN
end
end
end
end
end
end
\ No newline at end of file
end
......@@ -11,10 +11,11 @@ module BetfairApiNgRails
attr_reader :http, :request, :uri,
:app_key, :session_key, :username,
:password, :body, :is_provider
:password, :body, :is_provider, :api_url
def initialize(url, provider = true, use_ssl = true)
@is_provider = provider
@api_url = url
end
def do_request
......@@ -53,6 +54,7 @@ module BetfairApiNgRails
def create_http
@uri = URI.parse prepare_url
BetfairApiNgRails.log.write("==> Using url #{prepare_url}")
@http = Net::HTTP.new uri.host, uri.port
@request = Net::HTTP::Post.new uri.request_uri
end
......@@ -71,11 +73,13 @@ module BetfairApiNgRails
def prepare_form_data
return unless is_provider
BetfairApiNgRails.log.write("==> Setting request body #{body}")
request.set_form_data({
app_key: app_key,
api_url: api_url,
session_token: session_key,
body: body
})
})
end
end
end
......
......@@ -58,6 +58,7 @@ module BetfairApiNgRails
end
def set_request_body(body)
BetfairApiNgRails.log.write("==> Setting request body #{body}")
request.body = body
end
......
......@@ -27,7 +27,7 @@ module BetfairApiNgRails
include Api::Http::Helpers::KeepAliveResponse
include Api::Http::Helpers::SessionResponse
protected
protected
def http_error?
set_error_info(:HTTP, response.code) if check_response_code
......@@ -40,8 +40,7 @@ module BetfairApiNgRails
def set_error_info(type, info)
@error_info = { type: type, info: info }
end
end
end
end
end
\ No newline at end of file
end
......@@ -7,10 +7,11 @@ module BetfairApiNgRails
include Api::Concerns::Errorable
include Api::Constants
attr_reader :ssoid
attr_reader :ssoid, :application_key
def initialize(ssoid)
def initialize(ssoid, application_key)
@ssoid = ssoid
@application_key = application_key
end
def fetch(method: "", params: {})
......@@ -27,7 +28,7 @@ module BetfairApiNgRails
end
def http_requester(api_url)
Api::Http::Factory.provider_requester api_url, ssoid
Api::Http::Factory.provider_requester api_url, ssoid, application_key
end
end
end
......
......@@ -7,6 +7,7 @@ module BetfairApiNgRails
def initialize(name)
@name = name
BetfairApiNgRails.log.write("==> Creating request method for #{name}")
end
def allowed?
......@@ -15,23 +16,29 @@ module BetfairApiNgRails
def type
return :no_type unless allowed?
allow_data.keys.first
allow_data.keys.first.tap do |t|
BetfairApiNgRails.log.write("==> Type of #{name} is #{t}")
end
end
def api_url
return :no_api_url unless allowed?
API_URL[type]
API_URL[type].tap do |u|
BetfairApiNgRails.log.write("==> Api url of #{name} is #{u}")
end
end
def json_method
return :no_method unless allowed?
JSON_METHOD[type]
JSON_METHOD[type].tap do |j|
BetfairApiNgRails.log.write("==> Json method of #{name} is #{j}")
end
end
private
def allow_data
@_allow_data ||= ALLOWED_RESOURCES.keep_if do |k, v|
@_allow_data ||= ALLOWED_RESOURCES.select do |k, v|
v.include? name
end
end
......
......@@ -5,16 +5,16 @@ module BetfairApiNgRails
#
# Returns the details relating your account, including your discount rate and Betfair point balance.
#
def get_account_details
run_request __method__, {}
def get_account_details(account: '')
run_request __method__, {}, account
end
#
# Get available to bet amount. The getAccounts service will return the UK wallet balance by default
# from either the UK or AUS Accounts API endpoint if the wallet parameter is not specified.
#
def get_account_funds
run_request __method__, {}
def get_account_funds(account: '')
run_request __method__, {}, account
end
end
end
......
......@@ -13,8 +13,8 @@ module BetfairApiNgRails
private
def run_request(method, params, data = {})
BetfairApiNgRails.connection.request build_request_type(method), params.merge(data)
def run_request(method, params, account_name = '')
BetfairApiNgRails::Api::Connection.new(account_name).request build_request_type(method), params
end
def build_request_type(name)
......
......@@ -6,22 +6,22 @@ module BetfairApiNgRails
SIMPLE_LISTING_FILTERED.each do |method|
eval <<-CODE
def #{method.underscore}(filter: Api::Data::MarketFilter.new, locale: BetfairApiNgRails.config.locale)
run_request __method__, { filter: filter }, { locale: locale }
def #{method.underscore}(filter: BetfairApiNgRails::MarketFilter.new, locale: BetfairApiNgRails.config.locale)
run_request __method__, { filter: filter, locale: locale }
end
CODE
end
def list_market_catalogue(filter: BetfairApiNgRails::MarketFilter.new, market_projection: [], sort: "", max_results: '1', locale: BetfairApiNgRails.config.locale)
run_request __method__, { filter: filter, market_projection: market_projection, sort: sort, max_results: max_results }, { locale: locale }
run_request __method__, { filter: filter, market_projection: market_projection, sort: sort, max_results: max_results, locale: locale }
end
def list_market_book(market_ids: [], price_projection: BetfairApiNgRails::PriceProjection.new, order_projection: '', match_projection: '', currency_code: 'USD', locale: BetfairApiNgRails.config.locale)
run_request __method__, { market_ids: market_ids, price_projection: price_projection, order_projection: order_projection, match_projection: match_projection }, { currency_code: currency_code, locale: locale }
run_request __method__, { market_ids: market_ids, price_projection: price_projection, order_projection: order_projection, match_projection: match_projection, currency_code: currency_code, locale: locale }
end
def place_orders(market_id: "", instructions: [], customer_ref: "")
run_request __method__, { market_id: market_id, instructions: instructions, customer_ref: customer_ref }
def place_orders(market_id: "", instructions: [], customer_ref: "", account_name: '')