Skip to content
Merged
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
31 changes: 31 additions & 0 deletions bench/ex_fix_bench.exs
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,21 @@ defmodule ExFixBench do
Parser.parse(data, @dictionary, nil, false)
end

bench "Parse - Stage 1 (with SendingTime validation)", [data: get_parse_data_with_sending_time()] do
Parser.parse1(data, @dictionary, 12_345, true, true) # Assuming validate_sending_time is the 5th arg
end

bench "Parse - Full Msg (with SendingTime validation)", [data: get_parse_data_with_sending_time()] do
Parser.parse(data, @dictionary, 12_345, true, true) # Assuming validate_sending_time is the 5th arg
end

bench "Parse - Stage 1 (without SendingTime validation)", [data: get_parse_data_with_sending_time()] do
Parser.parse1(data, @dictionary, 12_345, true, false) # Assuming validate_sending_time is the 5th arg
end

bench "Parse - Full Msg (without SendingTime validation)", [data: get_parse_data_with_sending_time()] do
Parser.parse(data, @dictionary, 12_345, true, false) # Assuming validate_sending_time is the 5th arg
end
##
## Private functions
##
Expand All @@ -58,6 +73,22 @@ defmodule ExFixBench do
:binary.replace(str_data, "|", << 1 >>, [:global])
end

defp get_parse_data_with_sending_time() do
# Similar to get_parse_data but ensures SendingTime (tag 52) is present
# For the benchmark, we'll use a valid SendingTime relative to now.
# Benchfella executes functions in `setup` block before each run,
# so we can't directly use DateTime.utc_now() here as it would be fixed at compile time.
# Instead, we'll construct a string that's highly likely to be valid.
# A more robust way would be to pass the current time into this function if Benchfella allowed it,
# or modify the parser to accept a "current time" for validation purposes in tests.
# For now, this simplification should be acceptable for benchmarking the validation logic itself.
sending_time = DateTime.utc_now() |> DateTime.to_iso8601() |> String.slice(0, 17) # YYYYMMDD-HH:MM:SS
str_data = "8=FIXT.1.1|9=131|35=8|34=12345|49=SELL|52=#{sending_time}.000|" <>
"56=BUY|1=531|11=99|14=5|17=872|31=1.2|32=5|37=456|38=5|39=2|54=1|55=ABC|" <>
"150=F|151=0|10=240|"
:binary.replace(str_data, "|", << 1 >>, [:global])
end

def get_serialize_data() do
out_message = "D"
|> OutMessage.new()
Expand Down
12 changes: 6 additions & 6 deletions lib/ex_fix/parser.ex
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ defmodule ExFix.Parser do
@doc """
Parse full message
"""
def parse(data, dictionary, expected_seqnum \\ nil, validate \\ true) do
with %InMessage{valid: true} = msg1 <- parse1(data, dictionary, expected_seqnum, validate),
def parse(data, dictionary, expected_seqnum \\ nil, validate \\ true, validate_sending_time \\ true) do
with %InMessage{valid: true} = msg1 <- parse1(data, dictionary, expected_seqnum, validate, validate_sending_time),
msg2 <- parse2(msg1) do
msg2
end
Expand All @@ -23,9 +23,9 @@ defmodule ExFix.Parser do
@doc """
Parse - stage1
"""
def parse1(data, dictionary, expected_seqnum \\ nil, validate \\ true)
def parse1(data, dictionary, expected_seqnum \\ nil, validate \\ true, validate_sending_time \\ true)

def parse1(<<"8=FIXT.1.1", @soh, "9=", rest::binary>>, dictionary, expected_seqnum, validate) do
def parse1(<<"8=FIXT.1.1", @soh, "9=", rest::binary>>, dictionary, expected_seqnum, validate, _validate_sending_time) do
[str_len, rest1] = :binary.split(rest, <<@soh>>)
{len, _} = Integer.parse(str_len)

Expand Down Expand Up @@ -64,7 +64,7 @@ defmodule ExFix.Parser do
end
end

def parse1(<<"8=", _rest::binary>> = orig_msg, _dictionary, _expected_seqnum, _validate) do
def parse1(<<"8=", _rest::binary>> = orig_msg, _dictionary, _expected_seqnum, _validate, _validate_sending_time) do
%InMessage{
valid: false,
msg_type: nil,
Expand All @@ -75,7 +75,7 @@ defmodule ExFix.Parser do
}
end

def parse1(data, _dictionary, _expected_seqnum, _validate) do
def parse1(data, _dictionary, _expected_seqnum, _validate, _validate_sending_time) do
%InMessage{
valid: false,
msg_type: nil,
Expand Down
8 changes: 7 additions & 1 deletion lib/ex_fix/session.ex
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,7 @@ defmodule ExFix.Session do
config: %SessionConfig{
name: session_name,
validate_incoming_message: validate,
validate_sending_time: validate_sending_time,
log_incoming_msg: log_incoming_msg,
dictionary: dictionary
},
Expand All @@ -239,7 +240,8 @@ defmodule ExFix.Session do
<<extra_bytes::binary, data::binary>>,
dictionary,
expected_seqnum,
validate
validate,
validate_sending_time
)

case msg.valid do
Expand Down Expand Up @@ -719,6 +721,10 @@ defmodule ExFix.Session do
|> binary_part(0, len)
end

defp validate_sending_time(_session_name, %Session{config: %SessionConfig{validate_sending_time: false}}, _msg, _expected_seqnum) do
:ok
end

defp validate_sending_time(session_name, %Session{config: config, out_lastseq: out_lastseq} = session, %InMessage{fields: fields, other_msgs: other}, expected_seqnum) do
%SessionConfig{time_service: time_service, session_handler: handler, env: env} = config

Expand Down
1 change: 1 addition & 0 deletions lib/ex_fix/session_config.ex
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ defmodule ExFix.SessionConfig do
reconnect_interval: 15,
reset_on_logon: true,
validate_incoming_message: true,
validate_sending_time: true,
transport_mod: :gen_tcp,
transport_options: [],
time_service: nil,
Expand Down