# Development Your new bare-bones project includes minimal organization with a single `main.rs` file and a few assets. ``` project/ ├─ assets/ # Any assets that are used by the app should be placed here ├─ src/ │ ├─ main.rs # main.rs is the entry point to your application and currently contains all components for the app ├─ Cargo.toml # The Cargo.toml file defines the dependencies and feature flags for your project ``` ### Serving Your App Run the following command in the root of your project to start developing with the default platform: ```bash dx serve ``` To run for a different platform, use the `--platform platform` flag. E.g. ```bash dx serve --platform desktop ``` ## Configuration (appsettings.json and WASM fast-path) This project supports an `appsettings.json`-style configuration that is loaded at runtime. - Native (desktop/server): the app tries to read `appsettings.json` from the working directory. - WASM (web): the loader will first try a small HTML-injection fast-path (see below). If that is not present it will fetch `appsettings.json` from the hosting origin. Example `appsettings.json`: ```json { "server": { "stun_server": "stun:stun.l.google.com:19302" } } ``` HTML injection fast-path (for embedding a small config directly in `index.html`): ```html ``` This is useful for static hosting scenarios where you want to provide a different runtime configuration without rebuilding the WASM artifact. ## Consuming the Config in the UI (Dioxus) The Dioxus app provides a `Signal` via the hooks context. Child components can consume it with: ```rust let cfg_signal = use_context::>(); let cfg = cfg_signal.get(); // or cfg_signal.read()/() depending on the signal API // use cfg.server.stun_server ``` The app uses an async loader (via `use_resource`) and overwrites the initial default config when the runtime-loaded config becomes available. This gives instant sensible defaults while still allowing runtime overrides. ### Example: Provider + Consumer (Dioxus) Below is a minimal example showing how the app creates a `Signal` provider and how a child component consumes it. This pattern gives children an immediately-available default config while an async fetch can replace it at runtime. ```rust use dioxus::prelude::*; use dioxus_hooks::use_resource; use niom_webrtc::config; #[allow(non_snake_case)] fn ConfigProvider(cx: Scope) -> Element { // synchronous immediate default let default_cfg = config::load_config_sync_or_default(); // a reactive signal holding the current config let cfg_signal = use_state(cx, || default_cfg.clone()); // async resource that loads runtime config (WASM fetch or native file) let resource = use_resource(cx, (), |_| async move { config::load_config_or_default().await }); // when resource completes, update the signal so children react if let Some(cfg) = resource.value() { cfg_signal.set(cfg.clone()); } // provide the signal to descendants use_context_provider(cx, || cfg_signal.clone()); cx.render(rsx! { children(&cx) }) } fn SomeChild(cx: Scope) -> Element { let cfg_signal = use_context::>(cx); let cfg = cfg_signal.get(); cx.render(rsx!(div { "STUN: {cfg.server.stun_server}" })) } ``` Notes: - `load_config_sync_or_default()` returns a sensible default immediately (plus HTML fast-path on WASM). - `load_config_or_default()` is async and will perform a network fetch on WASM if the HTML fast-path wasn't present.