use std::cell::RefCell;
use std::future::Future;
use std::path::PathBuf;
use df_hyperliquid_core::client::native::{Native, clock};
use df_hyperliquid_core::client::{Http, Request, Response, TransportError};
use df_hyperliquid_core::{Client, Network};
use serde_json::Value;
use crate::shape::added;
use crate::support::{entry, fixture};
pub struct Tap {
wire: Native,
kept: RefCell<Vec<(String, String)>>,
}
impl Http for Tap {
fn send(&self, request: Request) -> impl Future<Output = Result<Response, TransportError>> {
let body = String::from_utf8_lossy(&request.body).into_owned();
async move {
let answer = self.wire.send(request).await?;
self.kept.borrow_mut().push((body, answer.text()));
Ok(answer)
}
}
}
pub fn reader() -> Client<Tap> {
Client::reader(Tap { wire: Native::new(), kept: RefCell::default() }, Network::Mainnet, clock)
}
pub fn last(client: &Client<Tap>) -> Value {
let kept = client.http().kept.borrow();
let (body, answer) = kept.last().expect("nothing was sent");
serde_json::from_str(answer).unwrap_or_else(|error| panic!("{error}: the answer to {body} is not JSON: {answer}"))
}
pub fn same_shape(client: &Client<Tap>, recording: &str) {
same_shape_as_any(client, &[recording]);
}
pub fn same_shape_as_any(client: &Client<Tap>, recordings: &[&str]) {
let live = last(client);
keep(recordings[0], &live);
let mut unseen: Option<Vec<String>> = None;
for recording in recordings {
let recorded: Value = serde_json::from_str(&recorded(recording)).unwrap();
let missing = added(&recorded, &live);
unseen = Some(match unseen {
None => missing,
Some(before) => before.into_iter().filter(|path| missing.contains(path)).collect(),
});
}
let unseen = unseen.unwrap_or_default();
assert!(unseen.is_empty(), "the venue now answers {recordings:?} with fields it did not have: {unseen:#?}");
}
fn recorded(recording: &str) -> String {
match recording.split_once('#') {
Some((path, key)) => entry(path, key),
None => fixture(recording),
}
}
fn keep(recording: &str, live: &Value) {
let path = PathBuf::from(env!("CARGO_TARGET_TMPDIR")).join("live").join(recording.replace('#', "."));
std::fs::create_dir_all(path.parent().unwrap()).unwrap();
std::fs::write(&path, serde_json::to_string_pretty(live).unwrap()).unwrap();
}