bodged refactor
This commit is contained in:
+59
-11
@@ -3,8 +3,10 @@ mod queries;
|
||||
mod todo_list;
|
||||
mod about;
|
||||
|
||||
use livevue_rs::{AppState, ConnectionManager, SubscriptionRegistry};
|
||||
use livevue_rs::{AppState, CacheKey, RenderContext, Store, spawn_fanout};
|
||||
use crate::app::{app_wrapper, resolve_and_render};
|
||||
use std::sync::Arc;
|
||||
use std::time::Duration;
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() -> anyhow::Result<()> {
|
||||
@@ -12,10 +14,8 @@ async fn main() -> anyhow::Result<()> {
|
||||
// Database setup
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
// SQLite with create-if-missing. In-memory `:memory:` also works for dev.
|
||||
let db = sqlx::SqlitePool::connect("sqlite:todo.db?mode=rwc").await?;
|
||||
|
||||
// Run migrations inline (no migration files needed for v0).
|
||||
sqlx::query(
|
||||
"CREATE TABLE IF NOT EXISTS todos (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
@@ -26,7 +26,6 @@ async fn main() -> anyhow::Result<()> {
|
||||
.execute(&db)
|
||||
.await?;
|
||||
|
||||
// Seed a few todos if the table is empty (nice for first run)
|
||||
let count: (i64,) = sqlx::query_as("SELECT COUNT(*) FROM todos")
|
||||
.fetch_one(&db)
|
||||
.await?;
|
||||
@@ -39,14 +38,65 @@ async fn main() -> anyhow::Result<()> {
|
||||
}
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// Store
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
let store = Store::new(db);
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// Render function
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
// The render_fn is the app's half of the framework contract. It receives
|
||||
// a RenderContext (with signals, tree, store access) and returns the
|
||||
// rendered inner HTML plus the accumulated subscription keys.
|
||||
//
|
||||
// The fanout task calls this for every server-initiated rerender.
|
||||
let render_fn: livevue_rs::RenderFn = Arc::new(|mut cx: RenderContext| {
|
||||
Box::pin(async move {
|
||||
println!("Render Called");
|
||||
let signals_json = cx.signals.to_json_string();
|
||||
let conn_id = cx.connection_id;
|
||||
let html = resolve_and_render(&mut cx).await?;
|
||||
let keys = cx.take_subscription_keys();
|
||||
// Wrap in app_wrapper so DataStar morphs the full #app element.
|
||||
// Signals are re-emitted from the stored json so the client stays
|
||||
// in sync even on server-initiated rerenders.
|
||||
let wrapped = app_wrapper(conn_id, &signals_json, &html);
|
||||
Ok((wrapped, keys))
|
||||
})
|
||||
});
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// Application state
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
let state = Arc::new(AppState {
|
||||
db,
|
||||
connections: ConnectionManager::new(),
|
||||
subscriptions: SubscriptionRegistry::new(),
|
||||
let state = AppState::new(store.clone(), render_fn);
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// Fanout task
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
spawn_fanout(state.clone());
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// Clock ticker
|
||||
//
|
||||
// Publishes CacheKey::Channel { key: "clock" } every second. Any
|
||||
// connection whose last render called cx.kv_run("clock") will be
|
||||
// scheduled for a rerender by the fanout task.
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
let clock_store = store.clone();
|
||||
tokio::spawn(async move {
|
||||
let mut interval = tokio::time::interval(Duration::from_secs(1));
|
||||
loop {
|
||||
interval.tick().await;
|
||||
let now = chrono::Utc::now().format("%H:%M:%S UTC").to_string();
|
||||
// set() writes the value and publishes the invalidation event.
|
||||
clock_store.kv.set("clock", serde_json::json!(now));
|
||||
}
|
||||
});
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
@@ -54,11 +104,9 @@ async fn main() -> anyhow::Result<()> {
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
let app = app::router(state);
|
||||
|
||||
let listener = tokio::net::TcpListener::bind("0.0.0.0:3000").await?;
|
||||
println!("Todo example listening on http://localhost:3000");
|
||||
|
||||
axum::serve(listener, app).await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user