df_hyperliquid_core/live/frame/
control.rs1use crate::live::{BadSubscription, Subscription};
5use crate::utils::Json;
6use serde::Deserialize;
7
8#[derive(Debug, Clone, Copy, PartialEq, Eq, Deserialize)]
10#[serde(rename_all = "lowercase")]
11pub enum Method {
12 Subscribe,
13 Unsubscribe,
14}
15
16#[derive(Debug, Clone, PartialEq, Eq)]
19pub struct Ack {
20 pub method: Method,
21 pub echo: Json,
22}
23
24impl Ack {
25 pub fn subscription(&self) -> Result<Subscription, BadSubscription> {
27 Subscription::parse(&self.echo)
28 }
29}
30
31#[derive(Debug, Clone, PartialEq, Eq)]
34pub struct Refusal {
35 pub message: String,
36}
37
38impl Refusal {
39 #[must_use]
42 pub fn post_id(&self) -> Option<u64> {
43 if let Some((_, digits)) = self.message.rsplit_once("id=")
44 && !digits.is_empty()
45 && digits.bytes().all(|byte| byte.is_ascii_digit())
46 {
47 return digits.parse().ok();
48 }
49 let quoted = self.quoted()?;
50 match quoted.get("method").and_then(Json::as_str) {
51 Some("post") => quoted.get("id").and_then(Json::as_u64),
52 _ => None,
53 }
54 }
55
56 #[must_use]
58 pub fn subscription(&self) -> Option<Subscription> {
59 let quoted = self.quoted()?;
60 let subscription = match quoted.get("subscription") {
61 Some(inside) => inside,
62 None if ["Already subscribed", "Already unsubscribed", "Invalid subscription"]
63 .iter()
64 .any(|start| self.message.starts_with(start)) =>
65 {
66 "ed
67 }
68 None => return None,
69 };
70 Subscription::parse(subscription).ok()
71 }
72
73 fn quoted(&self) -> Option<Json> {
75 let at = self.message.find('{')?;
76 Json::parse(self.message.get(at..)?).ok()
77 }
78}
79
80#[cfg(test)]
81#[path = "tests/control.rs"]
82mod tests;