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