aper_websocket_client/
client.rs1use crate::typed::TypedWebsocketConnection;
2use anyhow::Result;
3use aper::{
4 connection::{ClientConnection, MessageToClient, MessageToServer},
5 AperClient, Store,
6};
7use aper_stateroom::{IntentEvent, StateProgram};
8use core::fmt::Debug;
9use std::{
10 rc::{Rc, Weak},
11 sync::Mutex,
12};
13
14pub struct AperWebSocketStateProgramClient<S>
15where
16 S: StateProgram,
17{
18 conn: Rc<Mutex<ClientConnection<S>>>,
19 store: Store,
20}
21
22impl<S> Debug for AperWebSocketStateProgramClient<S>
23where
24 S: StateProgram,
25{
26 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
27 f.debug_struct("AperWebSocketStateProgramClient").finish()
28 }
29}
30
31impl<S> AperWebSocketStateProgramClient<S>
32where
33 S: StateProgram,
34{
35 pub fn new<F>(url: &str, state_callback: F) -> Result<Self>
36 where
37 F: Fn(S, u32) + 'static,
38 {
39 let client = AperClient::<S>::new();
47 let store = client.store();
48
49 let conn = Rc::new_cyclic(|c: &Weak<Mutex<ClientConnection<S>>>| {
50 let d = c.clone();
51 let socket_message_callback = move |message: MessageToClient| {
52 let d = d.upgrade().unwrap();
53 let mut conn = d.lock().unwrap();
54 conn.receive(&message);
55 };
56
57 let wss_conn = TypedWebsocketConnection::new(url, socket_message_callback).unwrap();
58
59 let message_callback = Box::new(move |message: MessageToServer| {
60 wss_conn.send(&message);
61 });
62
63 Mutex::new(ClientConnection::new(
64 client,
65 message_callback,
66 state_callback,
67 ))
68 });
69
70 Ok(AperWebSocketStateProgramClient { conn, store })
71 }
72
73 pub fn state(&self) -> S {
74 S::attach(self.store.handle())
75 }
76
77 pub fn push_intent(&self, intent: S::T) -> Result<(), S::Error> {
78 let mut conn = self.conn.lock().unwrap();
79
80 let client = conn.client_id;
81 let intent = IntentEvent {
82 client,
83 timestamp: chrono::Utc::now(),
84 intent,
85 };
86
87 conn.apply(&intent)
88 }
89}