comet/macros/
comet_macro.rs

1#[macro_export]
2macro_rules! run {
3    ($e:expr) => {
4        // pub use comet::prelude::log::*;
5        pub use comet::prelude::*;
6
7        #[cfg(target_arch = "wasm32")]
8        use std::panic;
9
10        #[cfg(not(target_arch = "wasm32"))]
11        mod schema;
12
13        #[derive(Clone)]
14        pub struct Wrapper<T>(pub T);
15
16        #[async_trait(?Send)]
17        impl ToVirtualNode for Wrapper<i32> {
18            async fn to_virtual_node(self) -> VirtualNode {
19                self.0.to_string().into()
20            }
21        }
22
23        #[async_trait(?Send)]
24        impl ToVirtualNode for Wrapper<i64> {
25            async fn to_virtual_node(self) -> VirtualNode {
26                self.0.to_string().into()
27            }
28        }
29
30        #[async_trait(?Send)]
31        impl ToVirtualNode for Wrapper<String> {
32            async fn to_virtual_node(self) -> VirtualNode {
33                self.0.clone().into()
34            }
35        }
36
37        #[async_trait(?Send)]
38        impl ToVirtualNode for Wrapper<&str> {
39            async fn to_virtual_node(self) -> VirtualNode {
40                self.0.to_string().into()
41            }
42        }
43
44        #[async_trait(?Send)]
45        impl ToVirtualNode for Wrapper<()> {
46            async fn to_virtual_node(self) -> VirtualNode {
47                "".into()
48            }
49        }
50
51        #[async_trait(?Send)]
52        impl ToVirtualNode for Wrapper<bool> {
53            async fn to_virtual_node(self) -> VirtualNode {
54                self.0.to_string().into()
55            }
56        }
57
58        #[async_trait(?Send)]
59        impl<T: ToVirtualNode> ToVirtualNode for Wrapper<Vec<T>> {
60            async fn to_virtual_node(self) -> VirtualNode {
61                let mut elem = VElement::new("div");
62
63                for child in self.0.into_iter() {
64                    let child = child.to_virtual_node().await;
65                    elem.children.push(child);
66                }
67
68                VirtualNode::from(elem)
69            }
70        }
71
72        #[async_trait(?Send)]
73        impl<T> ToVirtualNode for Wrapper<Option<T>>
74        where
75            Wrapper<T>: ToVirtualNode,
76        {
77            async fn to_virtual_node(self) -> VirtualNode {
78                match self.0 {
79                    Some(child) => Wrapper(child).to_virtual_node().await,
80                    None => "".to_string().into(),
81                }
82            }
83        }
84
85        #[async_trait(?Send)]
86        impl ToVirtualNode for Wrapper<VirtualNode> {
87            async fn to_virtual_node(self) -> VirtualNode {
88                self.0
89            }
90        }
91
92        generate_rpc_proto! {}
93        generate_proto! {}
94
95        #[cfg(not(target_arch = "wasm32"))]
96        generate_migrations! {}
97
98        #[cfg(target_arch = "wasm32")]
99        generate_cache! {}
100
101        #[cfg(target_arch = "wasm32")]
102        #[wasm_bindgen(start)]
103        pub fn main() {
104            panic::set_hook(Box::new(comet::prelude::console_error_panic_hook::hook));
105            comet::prelude::wasm_logger::init(wasm_logger::Config::new(Level::Trace));
106
107            info!("Starting app...");
108
109            spawn_local(async { main_async().await });
110        }
111
112        #[cfg(target_arch = "wasm32")]
113        pub async fn main_async() {
114            let (ready_tx, ready_rx) = comet::prelude::futures::channel::oneshot::channel();
115
116            spawn_local(start_socket(ready_tx));
117
118            ready_rx.await.unwrap();
119
120            let mut app = comet::_run($e).await;
121
122            debug!("First render");
123
124            let mut vdom = app.run().await;
125
126            trace!("App rendered");
127
128            let (tx, mut rx) = tokio::sync::mpsc::channel(1);
129
130            spawn_local(async move {
131                while let Some(_) = rx.recv().await {
132                    trace!("Rerender");
133                    app.update(&mut vdom).await;
134                }
135            });
136
137            REDRAW_CHANNEL.write().await.replace(tx);
138        }
139
140        #[cfg(target_arch = "wasm32")]
141        lazy_static! {
142            pub static ref SOCKET: Arc<RwLock<Option<Socket<Proto>>>> = Arc::new(RwLock::new(None));
143        }
144
145        #[cfg(target_arch = "wasm32")]
146        lazy_static! {
147            pub static ref CACHE: Arc<RwLock<Cache>> = Arc::new(RwLock::new(Cache::new()));
148        }
149
150        #[cfg(target_arch = "wasm32")]
151        lazy_static! {
152            pub static ref REDRAW_CHANNEL: Arc<RwLock<Option<tokio::sync::mpsc::Sender<()>>>> =
153                Arc::new(RwLock::new(None));
154        }
155
156        #[cfg(target_arch = "wasm32")]
157        pub async fn redraw_root() {
158            trace!("Redrawing root");
159            crate::REDRAW_CHANNEL
160                .write()
161                .await
162                .as_mut()
163                .unwrap()
164                .send(())
165                .await
166                .unwrap();
167        }
168
169        #[cfg(target_arch = "wasm32")]
170        pub async fn start_socket(ready: comet::prelude::futures::channel::oneshot::Sender<()>) {
171            use comet::prelude::futures::StreamExt;
172
173            let addr = "ws://localhost:8080/ws".to_string();
174
175            info!("Connecting to {}", addr);
176
177            let mut socket: Socket<Proto> = Socket::connect(addr).await;
178
179            let mut rx = socket.take_receiver().unwrap();
180
181            SOCKET.write().await.replace(socket);
182
183            ready.send(()).unwrap();
184
185            debug!("Socket ready");
186
187            while let Some(msg) = rx.next().await {
188                let proto = Proto::from_bytes(&msg.msg);
189
190                debug!("packet {:#?}", proto);
191
192                if let Proto::Event(request_id, events) = proto {
193                    CACHE
194                        .write()
195                        .await
196                        .update_for_request_id(request_id, events);
197
198                    redraw_root().await;
199                }
200            }
201        }
202
203        #[cfg(not(target_arch = "wasm32"))]
204        use crate::diesel::pg::PgConnection;
205
206        #[cfg(not(target_arch = "wasm32"))]
207        pub fn establish_connection() -> PgConnection {
208            use crate::diesel::prelude::*;
209            use std::env;
210
211            let database_url = env::var("DATABASE_URL").expect("DATABASE_URL must be set");
212
213            trace!("New db connection: {}", database_url);
214
215            PgConnection::establish(&database_url)
216                .unwrap_or_else(|_| panic!("Error connecting to {}", database_url))
217        }
218
219        #[cfg(not(target_arch = "wasm32"))]
220        #[tokio::main]
221        pub async fn main() {
222            pretty_env_logger::init();
223
224            debug!("Staring server");
225
226            comet::server::server::run::<Proto>().await;
227        }
228    };
229}