use alloc::borrow::Cow;
use alloc::vec::Vec;
use derive_new::new;
use serde::{Deserialize, Serialize};
use serde_with::skip_serializing_none;
use strum_macros::Display;
use crate::models::{currency::Currency, default_false, requests::RequestMethod, Model};
use super::{CommonFields, Request};
#[derive(Debug, Serialize, Deserialize, PartialEq, Eq, Clone, new)]
#[serde(rename_all(serialize = "PascalCase", deserialize = "snake_case"))]
pub struct SubscribeBook<'a> {
pub taker: Cow<'a, str>,
pub taker_gets: Currency<'a>,
pub taker_pays: Currency<'a>,
#[serde(default = "default_false")]
pub both: Option<bool>,
#[serde(default = "default_false")]
pub snapshot: Option<bool>,
}
#[derive(Debug, Eq, PartialEq, Clone, Serialize, Deserialize, Display)]
#[serde(rename_all = "snake_case")]
pub enum StreamParameter {
Consensus,
Ledger,
Manifests,
PeerStatus,
Transactions,
TransactionsProposed,
Server,
Validations,
}
#[skip_serializing_none]
#[derive(Debug, Serialize, Deserialize, PartialEq, Eq, Clone)]
pub struct Subscribe<'a> {
#[serde(flatten)]
pub common_fields: CommonFields<'a>,
pub accounts: Option<Vec<Cow<'a, str>>>,
pub accounts_proposed: Option<Vec<Cow<'a, str>>>,
pub books: Option<Vec<SubscribeBook<'a>>>,
pub streams: Option<Vec<StreamParameter>>,
pub url: Option<Cow<'a, str>>,
pub url_password: Option<Cow<'a, str>>,
pub url_username: Option<Cow<'a, str>>,
}
impl<'a> Model for Subscribe<'a> {}
impl<'a> Request<'a> for Subscribe<'a> {
fn get_common_fields(&self) -> &CommonFields<'a> {
&self.common_fields
}
fn get_common_fields_mut(&mut self) -> &mut CommonFields<'a> {
&mut self.common_fields
}
}
impl<'a> Subscribe<'a> {
pub fn new(
id: Option<Cow<'a, str>>,
accounts: Option<Vec<Cow<'a, str>>>,
accounts_proposed: Option<Vec<Cow<'a, str>>>,
books: Option<Vec<SubscribeBook<'a>>>,
streams: Option<Vec<StreamParameter>>,
url: Option<Cow<'a, str>>,
url_password: Option<Cow<'a, str>>,
url_username: Option<Cow<'a, str>>,
) -> Self {
Self {
common_fields: CommonFields {
command: RequestMethod::Subscribe,
id,
},
books,
streams,
accounts,
accounts_proposed,
url,
url_username,
url_password,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::models::currency::{IssuedCurrency, XRP};
use alloc::vec;
#[test]
fn test_serde_round_trip_no_books() {
let req = Subscribe::new(
Some("sub-1".into()),
Some(vec!["rAcc1111111111111111111111111111".into()]),
None,
None,
Some(vec![StreamParameter::Ledger, StreamParameter::Transactions]),
Some("https://example.test/cb".into()),
None,
None,
);
let serialized = serde_json::to_string(&req).unwrap();
let deserialized: Subscribe = serde_json::from_str(&serialized).unwrap();
assert_eq!(req, deserialized);
assert!(serialized.contains("\"command\":\"subscribe\""));
assert!(serialized.contains("\"streams\""));
}
#[test]
fn test_subscribe_book_serializes() {
let book = SubscribeBook::new(
"rTaker1111111111111111111111111111".into(),
Currency::XRP(XRP::new()),
Currency::IssuedCurrency(IssuedCurrency::new(
"USD".into(),
"rIssuer11111111111111111111111111".into(),
)),
Some(true),
Some(false),
);
let serialized = serde_json::to_string(&book).unwrap();
assert!(serialized.contains("\"Taker\""));
assert!(serialized.contains("\"TakerGets\""));
assert!(serialized.contains("\"TakerPays\""));
}
}