1use crate::config::{ConnectionConfig, HyperStackConfig};
2use crate::connection::{ConnectionManager, ConnectionState};
3use crate::entity::Stack;
4use crate::error::HyperStackError;
5use crate::frame::Frame;
6use crate::store::{SharedStore, StoreConfig};
7use crate::view::Views;
8use std::marker::PhantomData;
9use std::time::Duration;
10use tokio::sync::mpsc;
11
12pub struct HyperStack<S: Stack> {
22 connection: ConnectionManager,
23 store: SharedStore,
24 #[allow(dead_code)]
25 config: HyperStackConfig,
26 pub views: S::Views,
27 _stack: PhantomData<S>,
28}
29
30impl<S: Stack> HyperStack<S> {
31 pub async fn connect() -> Result<Self, HyperStackError> {
33 Self::builder().connect().await
34 }
35
36 pub async fn connect_url(url: &str) -> Result<Self, HyperStackError> {
38 Self::builder().url(url).connect().await
39 }
40
41 pub fn builder() -> HyperStackBuilder<S> {
43 HyperStackBuilder::new()
44 }
45
46 pub async fn connection_state(&self) -> ConnectionState {
47 self.connection.state().await
48 }
49
50 pub async fn disconnect(&self) {
51 self.connection.disconnect().await;
52 }
53
54 pub fn store(&self) -> &SharedStore {
55 &self.store
56 }
57}
58
59pub struct HyperStackBuilder<S: Stack> {
61 url: String,
62 config: HyperStackConfig,
63 _stack: PhantomData<S>,
64}
65
66impl<S: Stack> HyperStackBuilder<S> {
67 fn new() -> Self {
68 Self {
69 url: S::url().to_string(),
70 config: HyperStackConfig::default(),
71 _stack: PhantomData,
72 }
73 }
74
75 pub fn url(mut self, url: &str) -> Self {
76 self.url = url.to_string();
77 self
78 }
79
80 pub fn auto_reconnect(mut self, enabled: bool) -> Self {
81 self.config.auto_reconnect = enabled;
82 self
83 }
84
85 pub fn reconnect_intervals(mut self, intervals: Vec<Duration>) -> Self {
86 self.config.reconnect_intervals = intervals;
87 self
88 }
89
90 pub fn max_reconnect_attempts(mut self, max: u32) -> Self {
91 self.config.max_reconnect_attempts = max;
92 self
93 }
94
95 pub fn ping_interval(mut self, interval: Duration) -> Self {
96 self.config.ping_interval = interval;
97 self
98 }
99
100 pub fn initial_data_timeout(mut self, timeout: Duration) -> Self {
101 self.config.initial_data_timeout = timeout;
102 self
103 }
104
105 pub fn max_entries_per_view(mut self, max: usize) -> Self {
106 self.config.max_entries_per_view = Some(max);
107 self
108 }
109
110 pub fn unlimited_entries(mut self) -> Self {
111 self.config.max_entries_per_view = None;
112 self
113 }
114
115 pub async fn connect(self) -> Result<HyperStack<S>, HyperStackError> {
116 let store_config = StoreConfig {
117 max_entries_per_view: self.config.max_entries_per_view,
118 };
119 let store = SharedStore::with_config(store_config);
120 let store_clone = store.clone();
121
122 let (frame_tx, mut frame_rx) = mpsc::channel::<Frame>(1000);
123
124 let connection_config: ConnectionConfig = self.config.clone().into();
125 let connection = ConnectionManager::new(self.url, connection_config, frame_tx).await;
126
127 tokio::spawn(async move {
128 while let Some(frame) = frame_rx.recv().await {
129 store_clone.apply_frame(frame).await;
130 }
131 });
132
133 let view_builder = crate::view::ViewBuilder::new(
134 connection.clone(),
135 store.clone(),
136 self.config.initial_data_timeout,
137 );
138 let views = S::Views::from_builder(view_builder);
139
140 Ok(HyperStack {
141 connection,
142 store,
143 config: self.config,
144 views,
145 _stack: PhantomData,
146 })
147 }
148}