comet/macros/
comet_macro.rs1#[macro_export]
2macro_rules! run {
3 ($e:expr) => {
4 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}