use crate::messages::{IncomingMessages, ResponseMessage, WARNING_CODE_RANGE};
#[derive(Debug, Clone, PartialEq)]
pub enum RoutingDecision {
ByRequestId(i32),
ByOrderId(i32),
ByMessageType(IncomingMessages),
SharedMessage(IncomingMessages),
Error { request_id: i32, error_code: i32 },
Shutdown,
}
pub fn determine_routing(message: &ResponseMessage) -> RoutingDecision {
let message_type = message.message_type();
if message_type == IncomingMessages::Shutdown {
return RoutingDecision::Shutdown;
}
if message_type == IncomingMessages::Error {
let request_id = message.error_request_id();
let error_code = message.error_code();
return RoutingDecision::Error { request_id, error_code };
}
match message_type {
IncomingMessages::OrderStatus
| IncomingMessages::OpenOrder
| IncomingMessages::OpenOrderEnd
| IncomingMessages::CompletedOrder
| IncomingMessages::CompletedOrdersEnd
| IncomingMessages::ExecutionData
| IncomingMessages::ExecutionDataEnd
| IncomingMessages::CommissionsReport => {
if let Some(order_id) = message.order_id() {
return RoutingDecision::ByOrderId(order_id);
} else {
return RoutingDecision::ByOrderId(-1);
}
}
_ => {}
}
if let Some(request_id) = message.request_id() {
return RoutingDecision::ByRequestId(request_id);
}
match message_type {
IncomingMessages::ManagedAccounts | IncomingMessages::NextValidId | IncomingMessages::CurrentTime => {
RoutingDecision::SharedMessage(message_type)
}
_ => RoutingDecision::ByMessageType(message_type),
}
}
pub fn is_warning_error(error_code: i32) -> bool {
WARNING_CODE_RANGE.contains(&error_code)
}
pub const UNSPECIFIED_REQUEST_ID: i32 = -1;
#[cfg(test)]
mod tests {
use super::*;
use crate::messages::ResponseMessage;
#[test]
fn test_determine_routing_by_request_id() {
let message_str = "63\01\0123\0DU123456\0AccountType\0ADVISOR\0USD\0";
let message = ResponseMessage::from(message_str);
match determine_routing(&message) {
RoutingDecision::ByRequestId(id) => assert_eq!(id, 123),
routing => panic!("Expected ByRequestId routing, got {routing:?}"),
}
}
#[test]
fn test_determine_routing_error_old_format() {
let message_str = "4\02\0123\0200\0No security definition found\0";
let message = ResponseMessage::from(message_str);
match determine_routing(&message) {
RoutingDecision::Error { request_id, error_code } => {
assert_eq!(request_id, 123);
assert_eq!(error_code, 200);
}
routing => panic!("Expected Error routing, got {routing:?}"),
}
}
#[test]
fn test_determine_routing_error_new_format() {
let message_str = "4\0123\0200\0No security definition found\0\0";
let message = ResponseMessage::from(message_str).with_server_version(crate::server_versions::ERROR_TIME);
match determine_routing(&message) {
RoutingDecision::Error { request_id, error_code } => {
assert_eq!(request_id, 123);
assert_eq!(error_code, 200);
}
routing => panic!("Expected Error routing, got {routing:?}"),
}
}
#[test]
fn test_determine_routing_shared_message() {
let message_str = "15\01\0DU123456,DU234567\0";
let message = ResponseMessage::from(message_str);
match determine_routing(&message) {
RoutingDecision::SharedMessage(msg_type) => {
assert_eq!(msg_type, IncomingMessages::ManagedAccounts);
}
routing => panic!("Expected SharedMessage routing, got {routing:?}"),
}
}
#[test]
fn test_is_warning_error() {
assert!(is_warning_error(2100));
assert!(is_warning_error(2169));
assert!(is_warning_error(2119));
assert!(is_warning_error(2150));
assert!(!is_warning_error(2099));
assert!(!is_warning_error(2170));
assert!(!is_warning_error(200));
assert!(!is_warning_error(2200));
}
#[test]
fn test_order_message_routing() {
let message_str = "5\0123\0AAPL\0STK\0"; let message = ResponseMessage::from(message_str);
match determine_routing(&message) {
RoutingDecision::ByOrderId(id) => assert_eq!(id, 123),
routing => panic!("Expected ByOrderId routing, got {routing:?}"),
}
let message_str = "102\01\0"; let message = ResponseMessage::from(message_str);
match determine_routing(&message) {
RoutingDecision::ByOrderId(id) => assert_eq!(id, -1),
routing => panic!("Expected ByOrderId(-1) routing, got {routing:?}"),
}
let message_str = "11\01\0123\0456\0"; let message = ResponseMessage::from(message_str);
match determine_routing(&message) {
RoutingDecision::ByOrderId(id) => assert_eq!(id, 123),
routing => panic!("Expected ByOrderId routing, got {routing:?}"),
}
let message_str = "59\01\0exec123\0100.0\0USD\0"; let message = ResponseMessage::from(message_str);
match determine_routing(&message) {
RoutingDecision::ByOrderId(id) => assert_eq!(id, -1),
routing => panic!("Expected ByOrderId(-1) routing, got {routing:?}"),
}
}
}