use std::time::Duration;
use crate::hold::Hold;
use crate::hooks::{
AttemptInfo, Charge, Cost, LayerCharge, LayerId, Refused, RequestMeta, ResponseMeta, Throttle,
};
use crate::rate_limit::RateLimiter;
use crate::signer_limit::{SignerLimiter, TradingBucket, TradingRequest};
use super::clob_limits;
pub const CLOUDFLARE: LayerId = LayerId("cloudflare");
pub const SIGNER_ORDER: LayerId = LayerId("signer-order");
pub const SIGNER_CANCEL: LayerId = LayerId("signer-cancel");
pub fn signer_cost(request: TradingRequest) -> Cost {
Cost {
layer: match request.bucket() {
TradingBucket::Order => SIGNER_ORDER,
TradingBucket::Cancel => SIGNER_CANCEL,
},
units: request.cost().max(1),
exact: request.cost_is_exact(),
}
}
#[derive(Debug, Clone)]
pub struct ClobThrottle {
table: RateLimiter,
signer: SignerLimiter,
hold: Hold,
}
impl ClobThrottle {
pub fn new(table: RateLimiter, signer: SignerLimiter) -> Self {
let hold = table.hold().clone();
Self {
signer: signer.with_hold(hold.clone()),
table,
hold,
}
}
pub fn table(&self) -> &RateLimiter {
&self.table
}
pub fn signer(&self) -> &SignerLimiter {
&self.signer
}
}
impl Throttle for ClobThrottle {
async fn acquire(&self, meta: &RequestMeta<'_>) -> Result<Charge, Refused> {
self.hold.wait().await;
self.table.acquire(meta.path, Some(meta.method)).await;
let mut charge = Charge::none().with(LayerCharge {
layer: CLOUDFLARE,
units: 1,
window: None,
});
for cost in meta.costs {
let bucket = match cost.layer {
SIGNER_ORDER => TradingBucket::Order,
SIGNER_CANCEL => TradingBucket::Cancel,
_ => continue,
};
self.signer.charge(bucket, cost.units, cost.exact).await?;
charge = charge.with(LayerCharge {
layer: cost.layer,
units: cost.units,
window: None,
});
}
self.hold.wait().await;
Ok(charge)
}
fn observe(&self, _charge: &Charge, response: &ResponseMeta<'_>, _attempt: &AttemptInfo) {
self.signer.observe(response.headers);
}
fn hold(&self, delay: Duration) {
self.hold.extend(delay);
}
}
pub fn clob_throttle() -> ClobThrottle {
ClobThrottle::new(clob_limits(), SignerLimiter::new())
}