commit dba70faf9316079ddd3eeaa6103286a47f344ec5
parent d1a693dbcc0ade38a33b0144c81a55e6ecb3e5ef
Author: triesap <tyson@radroots.org>
Date: Fri, 20 Feb 2026 17:43:41 +0000
app-core: migrate runtime key flows to accounts apis
Diffstat:
4 files changed, 122 insertions(+), 42 deletions(-)
diff --git a/crates/field_core/Cargo.toml b/crates/field_core/Cargo.toml
@@ -17,6 +17,7 @@ nostr-client = [
"dep:radroots-core",
"dep:radroots-events-codec",
"dep:radroots-trade",
+ "dep:radroots-identity",
"dep:radroots-nostr",
]
directories = ["radroots-net-core/directories"]
@@ -27,6 +28,7 @@ radroots-log = { workspace = true }
radroots-events = { workspace = true }
radroots-net-core = { workspace = true, features = ["std"] }
radroots-core = { workspace = true, optional = true }
+radroots-identity = { workspace = true, optional = true, default-features = false, features = ["std"] }
radroots-events-codec = { workspace = true, features = ["serde_json"], optional = true }
radroots-trade = { workspace = true, features = ["std", "serde", "serde_json"], optional = true }
radroots-nostr = { workspace = true, features = ["events"], optional = true }
diff --git a/crates/field_core/src/runtime/key_management.rs b/crates/field_core/src/runtime/key_management.rs
@@ -1,14 +1,20 @@
use super::RadrootsRuntime;
use crate::RadrootsAppError;
+use radroots_identity::{RadrootsIdentity, RadrootsIdentityId};
use std::path::PathBuf;
#[uniffi::export]
impl RadrootsRuntime {
- pub fn keys_is_loaded(&self) -> bool {
+ pub fn accounts_has_selected_signing_identity(&self) -> bool {
if let Ok(guard) = self.net.lock() {
#[cfg(feature = "nostr-client")]
{
- return guard.keys.state.loaded;
+ return guard
+ .accounts
+ .selected_signing_identity()
+ .ok()
+ .flatten()
+ .is_some();
}
#[cfg(not(feature = "nostr-client"))]
{
@@ -18,25 +24,60 @@ impl RadrootsRuntime {
false
}
- pub fn keys_npub(&self) -> Option<String> {
+ pub fn accounts_selected_npub(&self) -> Option<String> {
if let Ok(guard) = self.net.lock() {
#[cfg(feature = "nostr-client")]
{
- return guard.keys.npub();
+ return guard
+ .accounts
+ .selected_public_identity()
+ .ok()
+ .flatten()
+ .map(|identity| identity.public_key_npub);
}
}
None
}
- pub fn keys_generate_in_memory(&self) -> Result<String, RadrootsAppError> {
+ pub fn accounts_list_ids(&self) -> Result<Vec<String>, RadrootsAppError> {
+ let guard = self
+ .net
+ .lock()
+ .map_err(|e| RadrootsAppError::Msg(format!("{e}")))?;
+ #[cfg(feature = "nostr-client")]
+ {
+ let accounts = guard
+ .accounts
+ .list_accounts()
+ .map_err(|e| RadrootsAppError::Msg(format!("{e}")))?;
+ return Ok(accounts
+ .into_iter()
+ .map(|account| account.account_id.to_string())
+ .collect());
+ }
+ #[cfg(not(feature = "nostr-client"))]
+ {
+ Err(RadrootsAppError::Msg("nostr disabled".into()))
+ }
+ }
+
+ pub fn accounts_generate(
+ &self,
+ label: Option<String>,
+ make_selected: bool,
+ ) -> Result<String, RadrootsAppError> {
let mut guard = self
.net
.lock()
.map_err(|e| RadrootsAppError::Msg(format!("{e}")))?;
#[cfg(feature = "nostr-client")]
{
- let k = guard.keys.generate_in_memory();
- return Ok(k.public_key().to_string());
+ let account_id = guard
+ .accounts
+ .generate_identity(label, make_selected)
+ .map_err(|e| RadrootsAppError::Msg(format!("{e}")))?;
+ guard.nostr = None;
+ return Ok(account_id.to_string());
}
#[cfg(not(feature = "nostr-client"))]
{
@@ -44,17 +85,26 @@ impl RadrootsRuntime {
}
}
- pub fn keys_export_secret_hex(&self) -> Result<String, RadrootsAppError> {
- let guard = self
+ pub fn accounts_import_secret(
+ &self,
+ secret_key: String,
+ label: Option<String>,
+ make_selected: bool,
+ ) -> Result<String, RadrootsAppError> {
+ let mut guard = self
.net
.lock()
.map_err(|e| RadrootsAppError::Msg(format!("{e}")))?;
#[cfg(feature = "nostr-client")]
{
- return guard
- .keys
- .export_secret_hex()
- .map_err(|e| RadrootsAppError::Msg(format!("{e}")));
+ let identity = RadrootsIdentity::from_secret_key_str(secret_key.as_str())
+ .map_err(|e| RadrootsAppError::Msg(format!("{e}")))?;
+ let account_id = guard
+ .accounts
+ .upsert_identity(&identity, label, make_selected)
+ .map_err(|e| RadrootsAppError::Msg(format!("{e}")))?;
+ guard.nostr = None;
+ return Ok(account_id.to_string());
}
#[cfg(not(feature = "nostr-client"))]
{
@@ -62,18 +112,24 @@ impl RadrootsRuntime {
}
}
- pub fn keys_load_hex32(&self, hex: String) -> Result<(), RadrootsAppError> {
+ pub fn accounts_import_from_path(
+ &self,
+ path: String,
+ label: Option<String>,
+ make_selected: bool,
+ ) -> Result<String, RadrootsAppError> {
let mut guard = self
.net
.lock()
.map_err(|e| RadrootsAppError::Msg(format!("{e}")))?;
#[cfg(feature = "nostr-client")]
{
- guard
- .keys
- .load_from_hex32(&hex)
+ let account_id = guard
+ .accounts
+ .migrate_legacy_identity_file(PathBuf::from(path), label, make_selected)
.map_err(|e| RadrootsAppError::Msg(format!("{e}")))?;
- Ok(())
+ guard.nostr = None;
+ return Ok(account_id.to_string());
}
#[cfg(not(feature = "nostr-client"))]
{
@@ -81,17 +137,45 @@ impl RadrootsRuntime {
}
}
- pub fn keys_load_from_path_auto(&self, path: String) -> Result<(), RadrootsAppError> {
+ pub fn accounts_export_selected_secret_hex(&self) -> Result<Option<String>, RadrootsAppError> {
+ let guard = self
+ .net
+ .lock()
+ .map_err(|e| RadrootsAppError::Msg(format!("{e}")))?;
+ #[cfg(feature = "nostr-client")]
+ {
+ let Some(selected_id) = guard
+ .accounts
+ .selected_account_id()
+ .map_err(|e| RadrootsAppError::Msg(format!("{e}")))?
+ else {
+ return Ok(None);
+ };
+ return guard
+ .accounts
+ .export_secret_hex(&selected_id)
+ .map_err(|e| RadrootsAppError::Msg(format!("{e}")));
+ }
+ #[cfg(not(feature = "nostr-client"))]
+ {
+ Err(RadrootsAppError::Msg("nostr disabled".into()))
+ }
+ }
+
+ pub fn accounts_select(&self, account_id: String) -> Result<(), RadrootsAppError> {
let mut guard = self
.net
.lock()
.map_err(|e| RadrootsAppError::Msg(format!("{e}")))?;
#[cfg(feature = "nostr-client")]
{
+ let account_id = RadrootsIdentityId::parse(account_id.as_str())
+ .map_err(|e| RadrootsAppError::Msg(format!("{e}")))?;
guard
- .keys
- .load_from_path_auto(PathBuf::from(path))
+ .accounts
+ .select_account(&account_id)
.map_err(|e| RadrootsAppError::Msg(format!("{e}")))?;
+ guard.nostr = None;
Ok(())
}
#[cfg(not(feature = "nostr-client"))]
@@ -100,30 +184,25 @@ impl RadrootsRuntime {
}
}
- pub fn keys_persist_best_practice(&self) -> Result<String, RadrootsAppError> {
- let _guard = self
+ pub fn accounts_remove(&self, account_id: String) -> Result<(), RadrootsAppError> {
+ let mut guard = self
.net
.lock()
.map_err(|e| RadrootsAppError::Msg(format!("{e}")))?;
- #[cfg(all(
- feature = "nostr-client",
- feature = "directories",
- feature = "fs-persistence"
- ))]
+ #[cfg(feature = "nostr-client")]
{
- let p = _guard
- .keys
- .persist_best_practice()
+ let account_id = RadrootsIdentityId::parse(account_id.as_str())
.map_err(|e| RadrootsAppError::Msg(format!("{e}")))?;
- Ok(p.display().to_string())
+ guard
+ .accounts
+ .remove_account(&account_id)
+ .map_err(|e| RadrootsAppError::Msg(format!("{e}")))?;
+ guard.nostr = None;
+ Ok(())
}
- #[cfg(not(all(
- feature = "nostr-client",
- feature = "directories",
- feature = "fs-persistence"
- )))]
+ #[cfg(not(feature = "nostr-client"))]
{
- Err(RadrootsAppError::Msg("persistence unsupported".into()))
+ Err(RadrootsAppError::Msg("nostr disabled".into()))
}
}
}
diff --git a/crates/field_core/src/runtime/nostr.rs b/crates/field_core/src/runtime/nostr.rs
@@ -144,7 +144,7 @@ impl RadrootsRuntime {
let guard = self.net.lock().ok()?;
#[cfg(feature = "nostr-client")]
{
- let keys = guard.keys.require().ok()?;
+ let keys = guard.selected_nostr_keys()?;
let pk = keys.public_key();
let mgr = guard.nostr.as_ref()?;
let out = mgr.fetch_profile_event_blocking(pk).ok()?;
diff --git a/crates/field_core/src/runtime/trade_listing.rs b/crates/field_core/src/runtime/trade_listing.rs
@@ -608,9 +608,8 @@ fn current_pubkey_hex(runtime: &RadrootsRuntime) -> Result<String, RadrootsAppEr
.lock()
.map_err(|e| RadrootsAppError::Msg(format!("{e}")))?;
let keys = guard
- .keys
- .require()
- .map_err(|e| RadrootsAppError::Msg(e.to_string()))?;
+ .selected_nostr_keys()
+ .ok_or_else(|| RadrootsAppError::Msg("no selected signing identity".into()))?;
Ok(keys.public_key().to_hex())
}