feat: figured out leptos networking
This commit is contained in:
@@ -7,22 +7,29 @@ edition = "2021"
|
||||
crate-type = ["cdylib", "rlib"]
|
||||
|
||||
[dependencies]
|
||||
leptos = { version = "0.7.0", features = ["nightly"] }
|
||||
leptos_router = { version = "0.7.0", features = ["nightly"] }
|
||||
axum = { version = "0.7", optional = true }
|
||||
leptos = { version = "^0.7", features = ["nightly"] }
|
||||
leptos_router = { version = "^0.7", features = ["nightly"] }
|
||||
axum = { version = "^0.7", optional = true }
|
||||
console_error_panic_hook = "0.1"
|
||||
leptos_axum = { version = "0.7.0", optional = true }
|
||||
leptos_meta = { version = "0.7.0" }
|
||||
leptos_axum = { version = "^0.7", optional = true }
|
||||
leptos_meta = { version = "^0.7" }
|
||||
tokio = { version = "1", features = ["rt-multi-thread"], optional = true }
|
||||
tower = { version = "0.4", optional = true }
|
||||
tower-http = { version = "0.5", features = ["fs"], optional = true }
|
||||
wasm-bindgen = "=0.2.95"
|
||||
wasm-bindgen = "0.2"
|
||||
thiserror = "1"
|
||||
http = "1"
|
||||
axum-server = { version = "0.7.1", features = ["tokio-rustls"], optional = true }
|
||||
tracing-subscriber = { version = "0.3.19", features = ["chrono", "env-filter", "serde", "tracing", "tracing-serde"], optional = true }
|
||||
axum-server = { version = "^0.7", features = ["tokio-rustls"], optional = true }
|
||||
tracing-subscriber = { version = "0.3", features = ["chrono", "env-filter", "serde", "tracing", "tracing-serde"], optional = true }
|
||||
structopt = { version = "0.3", optional = true }
|
||||
anyhow = "1.0.95"
|
||||
anyhow = "1.0"
|
||||
futures = "0.3"
|
||||
tokio-stream = { version = "0.1", optional = true }
|
||||
futures-util = { version = "0.3", optional = true }
|
||||
tracing = { version = "0.1", optional = true }
|
||||
web-sys = { version = "0.3", features = ["WebSocket"] }
|
||||
leptos-use = { version = "0.15", default_features = false, features = ["use_websocket"] }
|
||||
codee = "0.2"
|
||||
|
||||
[features]
|
||||
hydrate = ["leptos/hydrate"]
|
||||
@@ -35,9 +42,14 @@ ssr = [
|
||||
"dep:axum-server",
|
||||
"dep:tracing-subscriber",
|
||||
"dep:structopt",
|
||||
"dep:tokio-stream",
|
||||
"dep:futures-util",
|
||||
"dep:tracing",
|
||||
"leptos/ssr",
|
||||
"leptos_meta/ssr",
|
||||
"leptos_router/ssr",
|
||||
"leptos-use/ssr",
|
||||
"axum/ws"
|
||||
]
|
||||
|
||||
[package.metadata.leptos]
|
||||
@@ -58,7 +70,7 @@ env = "DEV"
|
||||
|
||||
bin-features = ["ssr"]
|
||||
bin-default-features = false
|
||||
bin-target-triple = "x86_64-unknown-linux-musl"
|
||||
bin-target-triple = "x86_64-unknown-linux-gnu"
|
||||
|
||||
lib-features = ["hydrate"]
|
||||
lib-default-features = false
|
||||
|
||||
@@ -5,6 +5,21 @@ use leptos_router::{
|
||||
StaticSegment,
|
||||
};
|
||||
|
||||
#[server]
|
||||
pub async fn test_retrieve() -> Result<u64, ServerFnError> {
|
||||
use leptos::server_fn::error::NoCustomError;
|
||||
|
||||
tokio::time::sleep(tokio::time::Duration::from_millis(1000)).await;
|
||||
|
||||
let start = std::time::SystemTime::now();
|
||||
let since_the_epoch = start
|
||||
.duration_since(std::time::UNIX_EPOCH)
|
||||
.map_err(|e| ServerFnError::<NoCustomError>::ServerError(e.to_string()))?
|
||||
.as_secs();
|
||||
|
||||
Ok(since_the_epoch)
|
||||
}
|
||||
|
||||
pub fn shell(options: LeptosOptions) -> impl IntoView {
|
||||
view! {
|
||||
<!DOCTYPE html>
|
||||
@@ -47,12 +62,84 @@ pub fn App() -> impl IntoView {
|
||||
/// Renders the home page of your application.
|
||||
#[component]
|
||||
fn HomePage() -> impl IntoView {
|
||||
use web_sys::WebSocket;
|
||||
use std::sync::Arc;
|
||||
use leptos_use::{UseWebSocketReturn, use_websocket};
|
||||
|
||||
// Creates a reactive value to update the button
|
||||
let count = RwSignal::new(0);
|
||||
let on_click = move |_| *count.write() += 1;
|
||||
|
||||
let loaded_time = Resource::new(|| (), |_| async move { test_retrieve().await });
|
||||
|
||||
let (requested_time, set_requested_time) = signal(None::<String>);
|
||||
let request_time = Action::new(move |_: &()| async move {
|
||||
let t = match test_retrieve().await {
|
||||
Ok(t) => format!("{}", t),
|
||||
Err(_) => "Error!".to_string()
|
||||
};
|
||||
set_requested_time(Some(t));
|
||||
});
|
||||
let request_time_callback = move |_| {
|
||||
request_time.dispatch(());
|
||||
};
|
||||
let pending = request_time.pending();
|
||||
|
||||
let text_input = RwSignal::new("".to_owned());
|
||||
let (messages, set_messages) = signal(Vec::<String>::new());
|
||||
|
||||
let UseWebSocketReturn { send, message, .. } = use_websocket::<String, String, codee::string::FromToStringCodec>("/ws");
|
||||
|
||||
Effect::new(move |_| {
|
||||
message.with(move |message| {
|
||||
if let Some(m) = message {
|
||||
leptos::logging::log!("got update: {}", m);
|
||||
set_messages.update(|messages: &mut Vec<_>| messages.push(format!("msg: {}", m)));
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
let send_message = move |_| {
|
||||
send(&text_input.get());
|
||||
text_input.set("".to_string());
|
||||
};
|
||||
|
||||
view! {
|
||||
<h1>"Welcome to Leptos!"</h1>
|
||||
<button on:click=on_click>"Click Me: " {count}</button>
|
||||
<Suspense
|
||||
fallback=move || view! { <p>"Loading..."</p> }
|
||||
>
|
||||
<h2>"Loaded time:"</h2>
|
||||
{move || {
|
||||
loaded_time.get()
|
||||
.map(|time| match time {
|
||||
Ok(t) => view! { <p>{format!("{}", t)}</p>},
|
||||
Err(_) => view! { <p>{"Error!".to_string()}</p> }
|
||||
})
|
||||
}}
|
||||
<h2>"Requested time:"</h2>
|
||||
<button on:click=request_time_callback>"Request new time"</button>
|
||||
{move || pending.get().then_some("Loading...")}
|
||||
{move || match requested_time.get() {
|
||||
Some(t) => {
|
||||
leptos::logging::log!("updating time display");
|
||||
view! { <p>{t}</p> }
|
||||
},
|
||||
None => view! { <p>{"N/A".to_string()}</p> }
|
||||
}}
|
||||
</Suspense>
|
||||
<h2>"Messages"</h2>
|
||||
<input bind:value=text_input />
|
||||
<input
|
||||
on:click=send_message
|
||||
type="button"
|
||||
value="Send message"
|
||||
/>
|
||||
{move || messages
|
||||
.get()
|
||||
.iter()
|
||||
.map(|message| view! { <p>{message.clone()}</p> })
|
||||
.collect::<Vec<_>>()}
|
||||
}
|
||||
}
|
||||
|
||||
2
sparse-server/src/db.rs
Normal file
2
sparse-server/src/db.rs
Normal file
@@ -0,0 +1,2 @@
|
||||
mod beacons;
|
||||
mod users;
|
||||
1
sparse-server/src/db/beacons.rs
Normal file
1
sparse-server/src/db/beacons.rs
Normal file
@@ -0,0 +1 @@
|
||||
|
||||
1
sparse-server/src/db/users.rs
Normal file
1
sparse-server/src/db/users.rs
Normal file
@@ -0,0 +1 @@
|
||||
|
||||
@@ -14,6 +14,9 @@ mod cli;
|
||||
#[cfg(feature = "ssr")]
|
||||
mod webserver;
|
||||
|
||||
#[cfg(feature = "ssr")]
|
||||
mod db;
|
||||
|
||||
#[cfg(feature = "ssr")]
|
||||
#[tokio::main]
|
||||
async fn main() -> anyhow::Result<()> {
|
||||
|
||||
@@ -1,3 +1,37 @@
|
||||
pub async fn websocket(ws: axum::extract::ws::WebSocketUpgrade) -> axum::response::Response {
|
||||
ws.on_upgrade(handle_websocket)
|
||||
}
|
||||
|
||||
async fn handle_websocket(mut socket: axum::extract::ws::WebSocket) {
|
||||
use futures_util::StreamExt;
|
||||
use tracing::info;
|
||||
|
||||
let mut count = 0;
|
||||
|
||||
loop {
|
||||
tokio::select! {
|
||||
msg = socket.recv() => {
|
||||
match msg {
|
||||
None => {
|
||||
break;
|
||||
}
|
||||
Some(msg) => {
|
||||
let Ok(axum::extract::ws::Message::Text(msg)) = msg else { continue; };
|
||||
|
||||
info!("Received message! {}", msg);
|
||||
|
||||
let Ok(_) = socket.send(axum::extract::ws::Message::Text(msg)).await else { break; };
|
||||
}
|
||||
}
|
||||
}
|
||||
_ = tokio::time::sleep(tokio::time::Duration::from_secs(1)) => {
|
||||
let Ok(_) = socket.send(axum::extract::ws::Message::Text(format!("{}", count))).await else { break; };
|
||||
count += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn serve_web(options: crate::cli::Options) -> anyhow::Result<()> {
|
||||
use axum::Router;
|
||||
use leptos::logging::log;
|
||||
@@ -21,6 +55,7 @@ pub async fn serve_web(options: crate::cli::Options) -> anyhow::Result<()> {
|
||||
let routes = generate_route_list(App);
|
||||
|
||||
let app = Router::new()
|
||||
.route("/ws", axum::routing::any(websocket))
|
||||
.leptos_routes(&leptos_options, routes, {
|
||||
let leptos_options = leptos_options.clone();
|
||||
move || shell(leptos_options.clone())
|
||||
@@ -30,7 +65,7 @@ pub async fn serve_web(options: crate::cli::Options) -> anyhow::Result<()> {
|
||||
|
||||
// run our app with hyper
|
||||
// `axum::Server` is a re-export of `hyper::Server`
|
||||
log!("listening on http://{}", &addr);
|
||||
tracing::info!("listening on http://{}", &addr);
|
||||
let listener = tokio::net::TcpListener::bind(&addr).await?;
|
||||
axum::serve(listener, app.into_make_service()).await?;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user