Module: StraightServer::GatewayModule

Included in:
GatewayOnConfig, GatewayOnDB
Defined in:
lib/straight-server/gateway.rb

Overview

This module contains common features of Gateway, later to be included in one of the classes below.

Defined Under Namespace

Classes: CallbackUrlBadResponse, GatewayInactive, InvalidOrderId, InvalidSignature, NoBlockchainAdapters, NoWebsocketsForNewGateway, OrderCountersDisabled, WebsocketExists, WebsocketForCompletedOrder

Constant Summary collapse

CALLBACK_URL_ATTEMPT_TIMEFRAME =

seconds

3600
@@redis =

Temporary fix for straight server benchmarking

StraightServer::Config.redis[:connection]
@@websockets =
{}

Instance Method Summary collapse

Instance Method Details

#add_websocket_for_order(ws, order) ⇒ Object

Raises:



145
146
147
148
149
150
151
152
153
154
155
# File 'lib/straight-server/gateway.rb', line 145

def add_websocket_for_order(ws, order)
  raise WebsocketExists            unless websockets[order.id].nil?
  raise WebsocketForCompletedOrder unless order.status < 2
  StraightServer.logger.info "Opening ws connection for #{order.id}"
  ws.on(:close) do |event|
    websockets.delete(order.id)
    StraightServer.logger.info "Closing ws connection for #{order.id}"
  end
  websockets[order.id] = ws
  ws
end

#create_order(attrs = {}) ⇒ Object

Creates a new order and saves into the DB. Checks if the MD5 hash is correct first.

Raises:



108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
# File 'lib/straight-server/gateway.rb', line 108

def create_order(attrs={})

  raise GatewayInactive unless self.active

  StraightServer.logger.info "Creating new order with attrs: #{attrs}"
  signature = attrs.delete(:signature)
  if !check_signature || sign_with_secret(attrs[:id]) == signature
    raise InvalidOrderId if check_signature && (attrs[:id].nil? || attrs[:id].to_i <= 0)
    order = order_for_keychain_id(
      amount:           attrs[:amount],
      keychain_id:      increment_last_keychain_id!,
      currency:         attrs[:currency],
      btc_denomination: attrs[:btc_denomination]
    )
    order.id         = attrs[:id].to_i if attrs[:id]
    order.data       = attrs[:data]    if attrs[:data]
    order.gateway    = self
    order.save
    self.save
    StraightServer.logger.info "Order #{order.id} created: #{order.to_h}"
    order
  else
    StraightServer.logger.warn "Invalid signature, cannot create an order for gateway (#{id})"
    raise InvalidSignature
  end
end

#fetch_transactions_for(address) ⇒ Object



11
12
13
# File 'lib/straight-server/gateway.rb', line 11

def fetch_transactions_for(address)
  try_adapters(@blockchain_adapters, type: 'blockchain') { |b| b.fetch_transactions_for(address) }
end

#get_order_counter(counter_name) ⇒ Object



198
199
200
201
# File 'lib/straight-server/gateway.rb', line 198

def get_order_counter(counter_name)
  raise OrderCountersDisabled unless StraightServer::Config.count_orders
  @@redis.get("#{StraightServer::Config.redis[:prefix]}:gateway_#{id}:#{counter_name}_orders_counter").to_i || 0
end

#increment_last_keychain_id!Object

Used to track the current keychain_id number, which is used by Straight::Gateway to generate addresses from the pubkey. The number is supposed to be incremented by 1. In the case of a Config file type of Gateway, the value is stored in a file in the .straight directory.



139
140
141
142
143
# File 'lib/straight-server/gateway.rb', line 139

def increment_last_keychain_id!
  self.last_keychain_id += 1
  self.save
  self.last_keychain_id
end

#increment_order_counter!(counter_name, by = 1) ⇒ Object



203
204
205
206
# File 'lib/straight-server/gateway.rb', line 203

def increment_order_counter!(counter_name, by=1)
  raise OrderCountersDisabled unless StraightServer::Config.count_orders
  @@redis.incrby("#{StraightServer::Config.redis[:prefix]}:gateway_#{id}:#{counter_name}_orders_counter", by)
end

#initialize_blockchain_adaptersObject



66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
# File 'lib/straight-server/gateway.rb', line 66

def initialize_blockchain_adapters
  @blockchain_adapters = []
  StraightServer::Config.blockchain_adapters.each do |a|

    adapter = begin
      Straight::Blockchain.const_get("#{a}Adapter")
    rescue NameError
      begin
        Kernel.const_get(a)
      rescue NameError
        puts "WARNING: No blockchain adapter with the name #{a} was found!"
        nil
      end
    end

    @blockchain_adapters << adapter.mainnet_adapter if adapter
  end
  raise NoBlockchainAdapters if @blockchain_adapters.empty?
end

#initialize_callbacksObject



86
87
88
89
90
91
92
93
94
95
96
97
# File 'lib/straight-server/gateway.rb', line 86

def initialize_callbacks
  # When the status of an order changes, we send an http request to the callback_url
  # and also notify a websocket client (if present, of course).
  @order_callbacks = [
    lambda do |order|
      StraightServer::Thread.new do
        send_callback_http_request     order
        send_order_to_websocket_client order
      end
    end
  ]
end

#initialize_exchange_rate_adaptersObject

Initializers methods ######################################################## We have separate methods, because with GatewayOnDB they are called from #after_initialize but in GatewayOnConfig they are called from #initialize intself. #########################################################################################



53
54
55
56
57
58
59
60
61
62
63
64
# File 'lib/straight-server/gateway.rb', line 53

def initialize_exchange_rate_adapters
  @exchange_rate_adapters ||= []
  if self.exchange_rate_adapter_names.kind_of?(Array) && self.exchange_rate_adapter_names
    self.exchange_rate_adapter_names.each do |adapter|
      begin
        @exchange_rate_adapters << Straight::ExchangeRate.const_get("#{adapter}Adapter").instance
      rescue NameError => e 
        puts "WARNING: No exchange rate adapter with the name #{a} was found!"
      end
    end
  end
end

#initialize_status_check_scheduleObject



99
100
101
# File 'lib/straight-server/gateway.rb', line 99

def initialize_status_check_schedule
  @status_check_schedule = Straight::GatewayModule::DEFAULT_STATUS_CHECK_SCHEDULE
end

#order_counters(reload: false) ⇒ Object



186
187
188
189
190
191
192
193
194
195
196
# File 'lib/straight-server/gateway.rb', line 186

def order_counters(reload: false)
  return @order_counters if @order_counters && !reload
  @order_counters = {
    new:         get_order_counter(:new),
    unconfirmed: get_order_counter(:unconfirmed),
    paid:        get_order_counter(:paid),
    underpaid:   get_order_counter(:underpaid),
    overpaid:    get_order_counter(:overpaid),
    expired:     get_order_counter(:expired)
  }
end

#order_status_changed(order) ⇒ Object



177
178
179
180
181
182
183
184
# File 'lib/straight-server/gateway.rb', line 177

def order_status_changed(order)
  statuses = Order::STATUSES.invert
  if StraightServer::Config.count_orders
    increment_order_counter!(statuses[order.old_status], -1) if order.old_status
    increment_order_counter!(statuses[order.status])
  end
  super
end

#send_order_to_websocket_client(order) ⇒ Object



162
163
164
165
166
167
# File 'lib/straight-server/gateway.rb', line 162

def send_order_to_websocket_client(order)
  if ws = websockets[order.id]
    ws.send(order.to_json)
    ws.close
  end
end

#sign_with_secret(content, level: 1) ⇒ Object



169
170
171
172
173
174
175
# File 'lib/straight-server/gateway.rb', line 169

def sign_with_secret(content, level: 1)
  result = content.to_s
  level.times do
    result = OpenSSL::HMAC.digest('sha256', secret, result).unpack("H*").first
  end
  result
end

#websocketsObject



157
158
159
160
# File 'lib/straight-server/gateway.rb', line 157

def websockets
  raise NoWebsocketsForNewGateway unless self.id
  @@websockets[self.id]
end