Aspirational examples for app developer contract.
This commit is contained in:
105
aspirational_examples/05_async_runtime_io.rs
Normal file
105
aspirational_examples/05_async_runtime_io.rs
Normal file
@@ -0,0 +1,105 @@
|
||||
//! Aspirational RUIN app API for runtime-integrated filesystem and network I/O.
|
||||
//!
|
||||
//! Intentionally non-compiling; this is a design sketch.
|
||||
|
||||
use ruin::prelude::*;
|
||||
|
||||
#[ruin_runtime::async_main]
|
||||
async fn main() -> ruin::Result<()> {
|
||||
App::new()
|
||||
.window(Window::new().title("RUIN Runtime I/O").size(1280.0, 820.0))
|
||||
.mount::<RuntimeIoExample>()
|
||||
.run()
|
||||
.await
|
||||
}
|
||||
|
||||
#[component]
|
||||
fn RuntimeIoExample() -> impl View {
|
||||
let manifest_path = use_signal(|| "./Cargo.toml".to_string());
|
||||
let release_url =
|
||||
use_signal(|| "https://api.github.com/repos/wtemple/ruin/releases/latest".to_string());
|
||||
|
||||
let manifest = use_resource(move || {
|
||||
let path = manifest_path.get();
|
||||
async move { ruin_runtime::fs::read_to_string(path).await }
|
||||
});
|
||||
|
||||
let release = use_resource(move || {
|
||||
let url = release_url.get();
|
||||
async move { ruin_http::get_json::<ReleaseSummary>(&url).await }
|
||||
});
|
||||
|
||||
let save_snapshot = use_action(move |_| {
|
||||
let manifest = manifest.latest_cloned();
|
||||
async move {
|
||||
let manifest = manifest.ok_or_else(|| anyhow!("manifest is not loaded yet"))?;
|
||||
ruin_runtime::fs::write("./tmp/manifest-snapshot.toml", manifest).await?;
|
||||
Ok::<_, anyhow::Error>(())
|
||||
}
|
||||
});
|
||||
|
||||
use_async_effect(move || {
|
||||
let url = release_url.get();
|
||||
async move {
|
||||
tracing::info!(%url, "release endpoint changed");
|
||||
Ok::<_, anyhow::Error>(())
|
||||
}
|
||||
});
|
||||
|
||||
view! {
|
||||
row(fill = true, gap = 20, padding = 20) {
|
||||
block(fill = true, gap = 12) {
|
||||
text(role = TextRole::Heading(1), size = 26, weight = FontWeight::Semibold) {
|
||||
"Filesystem"
|
||||
}
|
||||
text_input(value = manifest_path, placeholder = "./Cargo.toml") {}
|
||||
|
||||
match manifest.read() {
|
||||
Pending => view! { ProgressSpinner(label = "Reading file...") {} },
|
||||
Ready(Ok(contents)) => view! {
|
||||
column(gap = 12) {
|
||||
button(
|
||||
on_press = save_snapshot.dispatcher(),
|
||||
disabled = save_snapshot.pending(),
|
||||
) {
|
||||
"Save snapshot"
|
||||
}
|
||||
|
||||
CodeBlock(language = "toml") { contents }
|
||||
}
|
||||
},
|
||||
Ready(Err(error)) => view! {
|
||||
ErrorPanel(title = "Failed to read file", detail = error.to_string()) {}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
block(fill = true, gap = 12) {
|
||||
text(role = TextRole::Heading(1), size = 26, weight = FontWeight::Semibold) {
|
||||
"Network"
|
||||
}
|
||||
text_input(value = release_url, placeholder = "https://...") {}
|
||||
|
||||
match release.read() {
|
||||
Pending => view! { ProgressSpinner(label = "Fetching release summary...") {} },
|
||||
Ready(Ok(release)) => view! {
|
||||
column(gap = 8) {
|
||||
text(size = 20, weight = FontWeight::Semibold) { release.name.clone() }
|
||||
text(color = colors::muted()) { release.published_at.clone() }
|
||||
text { release.notes.clone() }
|
||||
}
|
||||
},
|
||||
Ready(Err(error)) => view! {
|
||||
ErrorPanel(title = "Failed to fetch release", detail = error.to_string()) {}
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct ReleaseSummary {
|
||||
name: String,
|
||||
published_at: String,
|
||||
notes: String,
|
||||
}
|
||||
Reference in New Issue
Block a user