use crate::{
engine::state::EngineState,
snapshot::{
BinaryMarketSnapshot, MarketCloseSnapshot, MarketSnapshot, RunnerSnapshot,
SnapshotPriceSelections,
},
types::{MarketId, MarketModel},
};
use serde::{Deserialize, Serialize};
use std::ops::{Deref, DerefMut};
use tracing::trace;
use uuid::Uuid;
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct EngineRoot {
inner: lucidstream::types::AggregateRoot<EngineState>,
#[serde(default)]
next_tx_id: u64,
}
impl EngineRoot {
pub fn new(state: EngineState) -> Self {
Self::new_with_id_and_version(Uuid::new_v4(), state, 0)
}
pub fn new_with(state: EngineState, version: u64) -> Self {
Self::new_with_id_and_version(Uuid::new_v4(), state, version)
}
pub fn new_with_id(engine_id: Uuid, state: EngineState) -> Self {
Self::new_with_id_and_version(engine_id, state, 0)
}
pub fn new_with_id_and_version(engine_id: Uuid, state: EngineState, version: u64) -> Self {
Self {
inner: lucidstream::types::AggregateRoot::new_with(engine_id, state, version),
next_tx_id: 0,
}
}
pub fn next_tx_id(&self) -> u64 {
self.next_tx_id
}
pub fn observe_tx_id(&mut self, tx_id: u64) {
self.next_tx_id = self.next_tx_id.max(tx_id.saturating_add(1));
}
pub fn take_tx_id(&mut self) -> u64 {
let tx_id = self.next_tx_id;
self.next_tx_id = self.next_tx_id.saturating_add(1);
tx_id
}
pub fn assert_next_seq(&self, seq: u64) {
let expected = self.version().saturating_add(1);
assert_eq!(
seq, expected,
"sequence gap: expected {}, got {}",
expected, seq
);
}
pub fn market_snapshot(&self, market_id: MarketId, depth: usize) -> Option<MarketSnapshot> {
trace!(market_id = ?market_id, depth, "building market snapshot");
let state = self.state();
let market = state.markets.get(&market_id)?;
let market_model = market.book.market_model();
let (runners, binary) = match market_model {
MarketModel::ExchangeOdds => {
let runners: Vec<RunnerSnapshot> = market
.book
.runners()
.map(|runner_id| {
let prices = market.book.runner_prices(runner_id, depth);
let selected_to_back =
SnapshotPriceSelections::from_levels(&prices.available_to_back);
let selected_to_lay =
SnapshotPriceSelections::from_levels(&prices.available_to_lay);
RunnerSnapshot {
runner_id,
available_to_back: prices.available_to_back,
available_to_lay: prices.available_to_lay,
matched_volume: market.book.runner_matched_volume(runner_id),
selected_to_back,
selected_to_lay,
}
})
.collect();
(runners, None)
}
MarketModel::BinaryYes { .. } => {
let d = market.book.binary_depth(depth);
let binary = d.map(|d| BinaryMarketSnapshot {
max_price_ticks: d.max_price_ticks,
bids: d.bids,
asks: d.asks,
});
(Vec::new(), binary)
}
};
let close = market
.book
.close_process_state()
.map(|s| MarketCloseSnapshot {
batch_max_events: s.batch_max_events,
total_live_orders: s.total_live_orders,
cancelled_total: s.cancelled_total,
chunks_done: s.chunks_done,
cursor_after: s.cursor_after,
});
Some(MarketSnapshot {
market_id,
market_seq: market.last_market_seq,
market_model,
state: market.book.market_state(),
close,
runners,
binary,
})
}
}
impl Deref for EngineRoot {
type Target = lucidstream::types::AggregateRoot<EngineState>;
fn deref(&self) -> &Self::Target {
&self.inner
}
}
impl DerefMut for EngineRoot {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.inner
}
}