field_lib

Cross-platform Rust runtime for Radroots iOS and Android apps
git clone https://radroots.dev/git/field_lib.git
Log | Files | Refs | README | LICENSE

commit 19bd9b31889a511f251aca09bde59922db558540
parent 985b55bd4b77d2dcb7e422389a92ab5756ad314b
Author: triesap <tyson@radroots.org>
Date:   Thu, 11 Jun 2026 16:04:16 -0700

field: normalize imported field crate workspace

Diffstat:
MCargo.toml | 29++++++++++++++++++++++-------
Dcrates/app/Cargo.toml | 21---------------------
Dcrates/app/build.rs | 53-----------------------------------------------------
Dcrates/app/src/error.rs | 7-------
Dcrates/app/src/lib.rs | 10----------
Dcrates/app/src/logging.rs | 38--------------------------------------
Dcrates/app/src/runtime.rs | 176-------------------------------------------------------------------------------
Dcrates/ffi/Cargo.toml | 21---------------------
Dcrates/ffi/bin/uniffi-bindgen.rs | 3---
Dcrates/ffi/src/lib.rs | 1-
Dcrates/ffi/uniffi.toml | 3---
Mcrates/field_core/Cargo.toml | 2+-
Mcrates/field_core/README.md | 6+++---
Mcrates/field_core/src/logging.rs | 1+
Mcrates/field_wasm/Cargo.toml | 2+-
Mcrates/field_wasm/README.md | 4++--
Mcrates/field_wasm/src/lib.rs | 8++++----
Mrust-toolchain.toml | 3+--
18 files changed, 35 insertions(+), 353 deletions(-)

diff --git a/Cargo.toml b/Cargo.toml @@ -1,25 +1,40 @@ [workspace] members = [ - "crates/*", + "crates/field_core", + "crates/field_ffi_swift", + "crates/field_wasm", ] resolver = "2" [workspace.package] -version = "0.1.0" +version = "0.1.0-alpha.1" edition = "2024" -rust-version = "1.88.0" +rust-version = "1.92.0" license = "AGPL-3.0" +repository = "https://github.com/radrootslabs/field_lib" +homepage = "https://radroots.org" +readme = "README" [workspace.dependencies] -radroots-app = { path = "crates/app" } -radroots-app-ffi = { path = "crates/ffi" } -radroots-log = { path = "../../crates/crates/log" } -radroots-net-core = { path = "../../crates/crates/net-core"} +radroots_field_core = { path = "crates/field_core", version = "0.1.0-alpha.1", default-features = false } +radroots_field_ffi_swift = { path = "crates/field_ffi_swift", version = "0.1.0-alpha.1" } +radroots_field_wasm = { path = "crates/field_wasm", version = "0.1.0-alpha.1" } +radroots-core = { package = "radroots_core", path = "../lib/crates/core", version = "0.1.0-alpha.2", default-features = false } +radroots-events = { package = "radroots_events", path = "../lib/crates/events", version = "0.1.0-alpha.2", default-features = false } +radroots-events-codec = { package = "radroots_events_codec", path = "../lib/crates/events_codec", version = "0.1.0-alpha.2", default-features = false } +radroots-identity = { package = "radroots_identity", path = "../lib/crates/identity", version = "0.1.0-alpha.2", default-features = false } +radroots-log = { package = "radroots_log", path = "../lib/crates/log", version = "0.1.0-alpha.2", default-features = false } +radroots-net-core = { package = "radroots_net", path = "../lib/crates/net", version = "0.1.0-alpha.2", default-features = false } +radroots-nostr = { package = "radroots_nostr", path = "../lib/crates/nostr", version = "0.1.0-alpha.2", default-features = false } +radroots-trade = { package = "radroots_trade", path = "../lib/crates/trade", version = "0.1.0-alpha.2", default-features = false } chrono = { version = "0.4" } serde = { version = "1", features = ["derive"] } serde_json = { version = "1" } thiserror = { version = "1" } +tokio = { version = "1" } tracing = { version = "0.1" } +tracing-subscriber = { version = "0.3" } uniffi = { version = "0.29.4" } uniffi_build = { version = "0.29.4" } +wasm-bindgen = { version = "0.2" } diff --git a/crates/app/Cargo.toml b/crates/app/Cargo.toml @@ -1,20 +0,0 @@ -[package] -name = "radroots-app" -version.workspace = true -edition.workspace = true -authors = ["Radroots Authors"] -rust-version.workspace = true -license.workspace = true - -[lib] -crate-type = ["rlib"] - -[dependencies] -radroots-log = { workspace = true } -radroots-net-core = { workspace = true, features = ["rt"] } -chrono = { workspace = true } -serde = { workspace = true, features = ["derive"] } -serde_json = { workspace = true } -thiserror = { workspace = true } -tracing = { workspace = true } -uniffi = { workspace = true } -\ No newline at end of file diff --git a/crates/app/build.rs b/crates/app/build.rs @@ -1,53 +0,0 @@ -use std::{ - env, - process::Command, - time::{SystemTime, UNIX_EPOCH}, -}; - -fn main() { - println!("cargo:rerun-if-changed=build.rs"); - println!("cargo:rerun-if-env-changed=SOURCE_DATE_EPOCH"); - println!("cargo:rerun-if-env-changed=PROFILE"); - - let rustc = env::var("RUSTC").unwrap_or_else(|_| "rustc".into()); - if let Ok(out) = Command::new(rustc).arg("--version").output() { - if out.status.success() { - if let Ok(ver) = String::from_utf8(out.stdout) { - println!("cargo:rustc-env=RUSTC_VERSION={}", ver.trim()); - } - } - } - - if let Ok(out) = Command::new("git") - .args(["rev-parse", "--short=12", "HEAD"]) - .output() - { - if out.status.success() { - let mut sha = String::from_utf8_lossy(&out.stdout).trim().to_string(); - let dirty = Command::new("git") - .args(["status", "--porcelain"]) - .output() - .ok() - .map_or(false, |o| o.status.success() && !o.stdout.is_empty()); - if dirty { - sha.push_str("-dirty"); - } - println!("cargo:rustc-env=GIT_HASH={sha}"); - } - } - - if let Ok(profile) = env::var("PROFILE") { - println!("cargo:rustc-env=PROFILE={profile}"); - } - - let epoch = env::var("SOURCE_DATE_EPOCH") - .ok() - .and_then(|v| v.parse::<u64>().ok()) - .unwrap_or_else(|| { - SystemTime::now() - .duration_since(UNIX_EPOCH) - .map(|d| d.as_secs()) - .unwrap_or(0) - }); - println!("cargo:rustc-env=BUILD_TIME_UNIX={epoch}"); -} diff --git a/crates/app/src/error.rs b/crates/app/src/error.rs @@ -1,7 +0,0 @@ -use thiserror::Error; - -#[derive(Debug, Error, uniffi::Error)] -pub enum RadrootsAppError { - #[error("{0}")] - Msg(String), -} diff --git a/crates/app/src/lib.rs b/crates/app/src/lib.rs @@ -1,10 +0,0 @@ -uniffi::setup_scaffolding!("radroots"); - -pub mod error; -pub mod logging; -pub mod runtime; - -pub use error::RadrootsAppError; -pub use radroots_net_core::net::{BuildInfo, NetInfo}; -pub use radroots_net_core::{Net, NetHandle}; -pub use runtime::RadrootsRuntime; diff --git a/crates/app/src/logging.rs b/crates/app/src/logging.rs @@ -1,38 +0,0 @@ -use std::path::PathBuf; - -#[uniffi::export] -pub fn init_logging( - dir: Option<String>, - file_name: Option<String>, - is_stdout: Option<bool>, -) -> Result<(), crate::RadrootsAppError> { - let opts = radroots_log::LoggingOptions { - dir: dir.map(PathBuf::from), - file_name: file_name.unwrap_or_else(|| "radroots.log".to_string()), - stdout: is_stdout.unwrap_or(true), - }; - radroots_log::init_logging(opts).map_err(|e| crate::RadrootsAppError::Msg(format!("{e}"))) -} - -#[uniffi::export] -pub fn init_logging_stdout() -> Result<(), crate::RadrootsAppError> { - radroots_log::init_stdout().map_err(|e| crate::RadrootsAppError::Msg(format!("{e}"))) -} - -#[uniffi::export] -pub fn log_info(msg: String) -> Result<(), crate::RadrootsAppError> { - radroots_log::log_info(msg); - Ok(()) -} - -#[uniffi::export] -pub fn log_error(msg: String) -> Result<(), crate::RadrootsAppError> { - radroots_log::log_error(msg); - Ok(()) -} - -#[uniffi::export] -pub fn log_debug(msg: String) -> Result<(), crate::RadrootsAppError> { - radroots_log::log_debug(msg); - Ok(()) -} diff --git a/crates/app/src/runtime.rs b/crates/app/src/runtime.rs @@ -1,176 +0,0 @@ -use chrono::Utc; -use radroots_net_core::{NetHandle, builder::NetBuilder, net}; -use serde::Serialize; -use std::sync::{ - RwLock, - atomic::{AtomicBool, Ordering}, -}; -use tracing::info; - -#[inline] -fn is_false(b: &bool) -> bool { - !*b -} - -#[derive(Debug, Clone, Serialize, Default, uniffi::Record)] -pub struct NetBuildInfo { - pub crate_name: String, - pub crate_version: String, - pub rustc: Option<String>, - pub profile: Option<String>, - pub git_sha: Option<String>, - pub build_time_unix: Option<u64>, -} - -impl From<&net::BuildInfo> for NetBuildInfo { - fn from(b: &net::BuildInfo) -> Self { - Self { - crate_name: b.crate_name.to_string(), - crate_version: b.crate_version.to_string(), - rustc: b.rustc.map(|s| s.to_string()), - profile: b.profile.map(|s| s.to_string()), - git_sha: b.git_sha.map(|s| s.to_string()), - build_time_unix: b.build_time_unix, - } - } -} - -#[derive(Debug, Clone, Serialize, Default, uniffi::Record)] -pub struct AppInfoPlatform { - pub platform: Option<String>, - pub bundle_id: Option<String>, - pub version: Option<String>, - pub build_number: Option<String>, - pub build_sha: Option<String>, -} - -pub type AppBuildInfo = NetBuildInfo; - -#[derive(Debug, Clone, Serialize, uniffi::Record)] -pub struct AppInfo { - pub build: AppBuildInfo, - pub platform: Option<AppInfoPlatform>, - pub started_unix_ms: i64, - pub uptime_millis: i64, - #[serde(skip_serializing_if = "is_false")] - pub shutting_down: bool, -} - -#[derive(Debug, Clone, Serialize, uniffi::Record)] -pub struct RuntimeInfo { - pub app: AppInfo, - pub net: NetBuildInfo, -} - -#[derive(uniffi::Object)] -pub struct RadrootsRuntime { - net: NetHandle, - started_unix_ms: i64, - shutting_down: AtomicBool, - platform_app: RwLock<Option<AppInfoPlatform>>, -} - -impl RadrootsRuntime { - fn app_build_info() -> NetBuildInfo { - NetBuildInfo { - crate_name: env!("CARGO_PKG_NAME").to_string(), - crate_version: env!("CARGO_PKG_VERSION").to_string(), - rustc: option_env!("RUSTC_VERSION").map(|s| s.to_string()), - profile: option_env!("PROFILE").map(|s| s.to_string()), - git_sha: option_env!("GIT_HASH").map(|s| s.to_string()), - build_time_unix: option_env!("BUILD_TIME_UNIX").and_then(|s| s.parse().ok()), - } - } - - fn uptime_millis_from(&self, now_ms: i64) -> i64 { - now_ms.saturating_sub(self.started_unix_ms) - } -} - -#[uniffi::export] -impl RadrootsRuntime { - #[uniffi::constructor] - pub fn new() -> Result<Self, crate::RadrootsAppError> { - let cfg = radroots_net_core::config::NetConfig::default(); - let handle = NetBuilder::new() - .config(cfg) - .manage_runtime(true) - .build() - .map_err(|e| crate::RadrootsAppError::Msg(format!("net build failed: {e}")))?; - - Ok(Self { - net: handle, - started_unix_ms: Utc::now().timestamp_millis(), - shutting_down: AtomicBool::new(false), - platform_app: RwLock::new(None), - }) - } - - pub fn set_app_info_platform( - &self, - platform: Option<String>, - bundle_id: Option<String>, - version: Option<String>, - build_number: Option<String>, - build_sha: Option<String>, - ) { - let info = AppInfoPlatform { - platform, - bundle_id, - version, - build_number, - build_sha, - }; - if let Ok(mut guard) = self.platform_app.write() { - *guard = Some(info); - } - } - - pub fn stop(&self) { - if self - .shutting_down - .compare_exchange(false, true, Ordering::SeqCst, Ordering::SeqCst) - .is_err() - { - info!("Runtime stop already in progress or completed."); - return; - } - - if let Ok(mut net) = self.net.lock() { - if let Some(_rt) = net.rt.take() { - info!("The runtime stopped gracefully."); - } else { - info!("No runtime was active at stop call."); - } - } else { - info!("Failed to acquire runtime lock during stop."); - } - } - - pub fn uptime_millis(&self) -> i64 { - self.uptime_millis_from(Utc::now().timestamp_millis()) - } - - pub fn info(&self) -> RuntimeInfo { - let now_ms = Utc::now().timestamp_millis(); - let app = AppInfo { - build: Self::app_build_info(), - platform: self.platform_app.read().ok().and_then(|g| (*g).clone()), - started_unix_ms: self.started_unix_ms, - uptime_millis: self.uptime_millis_from(now_ms), - shutting_down: self.shutting_down.load(Ordering::SeqCst), - }; - let net = match self.net.lock() { - Ok(guard) => NetBuildInfo::from(&guard.info.build), - Err(_) => NetBuildInfo::default(), - }; - RuntimeInfo { app, net } - } - - pub fn info_json(&self) -> String { - match serde_json::to_string_pretty(&self.info()) { - Ok(s) => s, - Err(e) => format!(r#"{{"error":"failed to serialize RuntimeInfo: {e}"}}"#), - } - } -} diff --git a/crates/ffi/Cargo.toml b/crates/ffi/Cargo.toml @@ -1,21 +0,0 @@ -[package] -name = "radroots-app-ffi" -version.workspace = true -edition.workspace = true -authors = ["Radroots Authors"] -rust-version.workspace = true -license.workspace = true - -[lib] -crate-type = ["staticlib", "cdylib"] - -[[bin]] -name = "uniffi-bindgen" -path = "bin/uniffi-bindgen.rs" - -[build-dependencies] -uniffi_build = { workspace = true } - -[dependencies] -radroots-app = { workspace = true } -uniffi = { workspace = true, features = ["cli"] } diff --git a/crates/ffi/bin/uniffi-bindgen.rs b/crates/ffi/bin/uniffi-bindgen.rs @@ -1,3 +0,0 @@ -fn main() { - uniffi::uniffi_bindgen_main() -} diff --git a/crates/ffi/src/lib.rs b/crates/ffi/src/lib.rs @@ -1 +0,0 @@ -radroots_app::uniffi_reexport_scaffolding!(); diff --git a/crates/ffi/uniffi.toml b/crates/ffi/uniffi.toml @@ -1,3 +0,0 @@ -[bindings.swift] -module_name = "RadrootsKitBindings" -ffi_module_name = "RadrootsFFI" diff --git a/crates/field_core/Cargo.toml b/crates/field_core/Cargo.toml @@ -5,7 +5,7 @@ edition.workspace = true authors = ["Radroots Authors"] rust-version.workspace = true license.workspace = true -description = "core application runtime primitives for radroots app surfaces" +description = "core field runtime primitives for Radroots field surfaces" repository.workspace = true homepage.workspace = true documentation = "https://docs.rs/radroots_field_core" diff --git a/crates/field_core/README.md b/crates/field_core/README.md @@ -1,13 +1,13 @@ # radroots_field_core -Core application runtime primitives for Rad Roots app surfaces. +Core field runtime primitives for Rad Roots field surfaces. ## Goals -- define stable application runtime, error, and lifecycle interfaces +- define stable field runtime, error, and lifecycle interfaces - keep runtime and network wiring deterministic across supported targets - support reusable integration points with `radroots-net-core` -- provide reusable application primitives for higher-level Rad Roots crates +- provide reusable field primitives for higher-level Rad Roots crates ## License diff --git a/crates/field_core/src/logging.rs b/crates/field_core/src/logging.rs @@ -9,6 +9,7 @@ pub fn init_logging( let opts = radroots_log::LoggingOptions { dir: dir.map(PathBuf::from), file_name: file_name.unwrap_or_else(|| "radroots.log".to_string()), + file_layout: radroots_log::LogFileLayout::PrefixedDate, stdout: is_stdout.unwrap_or(true), default_level: None, }; diff --git a/crates/field_wasm/Cargo.toml b/crates/field_wasm/Cargo.toml @@ -5,7 +5,7 @@ edition.workspace = true authors = ["Radroots Authors"] rust-version.workspace = true license.workspace = true -description = "wasm application runtime bindings for radroots app surfaces" +description = "wasm runtime bindings for Radroots field surfaces" repository.workspace = true homepage.workspace = true documentation = "https://docs.rs/radroots_field_wasm" diff --git a/crates/field_wasm/README.md b/crates/field_wasm/README.md @@ -1,13 +1,13 @@ # radroots_field_wasm -Wasm application runtime bindings for Rad Roots app surfaces. +Wasm runtime bindings for Rad Roots field surfaces. ## Goals - define stable wasm runtime interfaces for app metadata and startup - keep wasm runtime behavior deterministic across supported browser targets - support feature-gated bindings backed by `radroots_field_core` -- provide reusable wasm entry points for higher-level Rad Roots app crates +- provide reusable wasm entry points for higher-level Rad Roots field crates ## License diff --git a/crates/field_wasm/src/lib.rs b/crates/field_wasm/src/lib.rs @@ -3,7 +3,7 @@ use wasm_bindgen::prelude::wasm_bindgen; #[wasm_bindgen] -pub fn app_wasm_build_info_json() -> String { +pub fn field_wasm_build_info_json() -> String { let runtime = radroots_field_core::RadrootsRuntime::new() .expect("runtime init must succeed with radroots_field_core no-default-features"); runtime.info_json() @@ -15,11 +15,11 @@ pub fn coverage_branch_probe(input: bool) -> &'static str { #[cfg(test)] mod tests { - use super::{app_wasm_build_info_json, coverage_branch_probe}; + use super::{coverage_branch_probe, field_wasm_build_info_json}; #[test] - fn app_wasm_build_info_json_contains_runtime_keys() { - let json = app_wasm_build_info_json(); + fn field_wasm_build_info_json_contains_runtime_keys() { + let json = field_wasm_build_info_json(); assert!(json.contains("\"app\"")); } diff --git a/rust-toolchain.toml b/rust-toolchain.toml @@ -1,2 +1,2 @@ [toolchain] -channel = "1.88.0" -\ No newline at end of file +channel = "1.92.0"