defmodule Ibex.Inbound.Handler do
use GenServer
require Logger
@initial_state %{}
def start do
Logger.debug("Starting Inbound...")
GenServer.start(__MODULE__, @initial_state)
end
def start_link(_opt) do
Logger.info("Starting Inbound as a supervised process...")
GenServer.start_link(__MODULE__, @initial_state, name: __MODULE__)
end
def init(state) do
{:ok, state}
end
def handle_info({:dispatch, fields}, state) do
msg_code = String.to_integer(Enum.at(fields, 0))
msg_code = Ibex.Messages.Types.Inbound.parse(msg_code)
req_id = Enum.at(fields, 1)
msg_body = Enum.slice(fields, 2..-1)
case msg_code do
:contract_data ->
Logger.info("Received contact data: #{inspect(msg_body)}")
:symbol_samples ->
process_symbol_samples(Enum.slice(fields, 1..-1))
_ ->
Logger.info("Received unhandled message type #{msg_code}. Body was: #{inspect(msg_body)}")
end
{:noreply, state}
end
defp process_symbol_samples(fields) do
{req_id, fields} = chomp(fields)
{num_descriptions, fields} = chomp(fields)
nd = Enum.at(num_descriptions, 0)
nd = String.to_integer(nd)
contracts = Ibex.Contracts.Inbound.SymbolSamples.extract_contracts(fields, [])
Enum.each(contracts, fn contract ->
Logger.info("Sending #{inspect(contract.contract.con_id)} to storage")
if contract.contract.con_id == "" do
nil
else
send(Ibex.Contracts.Storage, {:add_contract, contract})
end
end)
end
defp chomp(fields) do
Enum.split(fields, 1)
end
end
defmodule Ibex.Contracts.Inbound.SymbolSamples do
require Logger
alias Ibex.Contracts.ContractDescription, as: CD
def extract_contracts(fields, con_descs) do
{fields, con_descs} = extract_contract(fields, con_descs)
case length(fields) > 0 do
true ->
extract_contracts(fields, con_descs)
false ->
con_descs
end
end
def extract_contract(fields, con_descs) do
ncdesc = Ibex.Contracts.ContractDescription.t()
{con_id, fields} = chomp(fields)
{symbol, fields} = chomp(fields)
{sec_type, fields} = chomp(fields)
{primary_exchange, fields} = chomp(fields)
{currency, fields} = chomp(fields)
{nDerivativeSecTypes, fields} = chomp(fields)
nt = Enum.at(nDerivativeSecTypes, 0)
{fields, ncdesc} =
if nt == nil do
{fields, CD.insert_derivative_types(ncdesc, [])}
else
nt = String.to_integer(nt)
{derivs, fields} = Enum.split(fields, nt)
{fields, CD.insert_derivative_types(ncdesc, derivs)}
end
{description, fields} = chomp(fields)
{issuer_id, fields} = chomp(fields)
ncdesc =
CD.insert_into_contract(ncdesc, :con_id, to_string(con_id))
|> CD.insert_into_contract(:symbol, to_string(symbol))
|> CD.insert_into_contract(:sec_type, sec_type)
|> CD.insert_into_contract(:primary_exchange, primary_exchange)
|> CD.insert_into_contract(:currency, currency)
|> CD.insert_into_contract(:description, description)
|> CD.insert_into_contract(:issuer_id, issuer_id)
{fields, con_descs ++ [ncdesc]}
end
defp chomp(fields) do
result = Enum.split(fields, 1)
result
end
end