Files
sovereign_browser_rust/src/settings_sync.rs
T

103 lines
3.4 KiB
Rust

//! NIP-78 (kind 30078) settings sync for sovereign_browser
//!
//! Port of `settings_sync.c` / `settings_sync.h` from the C project.
//! Uses `nostr_signer` and `nostr_relay` from `rust_core_lib`.
use nostr_signer::traits::NostrSigner;
use std::sync::Arc;
use std::sync::Mutex;
use once_cell::sync::Lazy;
use crate::db;
use crate::settings;
/// The d-tag identifier used for the shared kind 30078 user-settings event.
const SETTINGS_SYNC_D_TAG: &str = "user-settings";
/// The Nostr kind for arbitrary custom app data (NIP-78).
const _SETTINGS_SYNC_KIND: u64 = 30078;
/// Global signer state for settings sync.
static G_SYNC_STATE: Lazy<Mutex<SyncState>> = Lazy::new(|| Mutex::new(SyncState::default()));
struct SyncState {
signer: Option<Arc<dyn NostrSigner>>,
pubkey_hex: String,
have_signer: bool,
}
impl Default for SyncState {
fn default() -> Self {
SyncState {
signer: None,
pubkey_hex: String::new(),
have_signer: false,
}
}
}
/// Initialize the settings sync module.
pub fn settings_sync_init(signer: Option<Arc<dyn NostrSigner>>, pubkey_hex: &str) {
let mut state = G_SYNC_STATE.lock().unwrap();
state.signer = signer;
state.pubkey_hex = pubkey_hex.to_string();
state.have_signer = state.signer.is_some() && !state.pubkey_hex.is_empty();
}
/// Update the signer reference.
pub fn settings_sync_set_signer(signer: Option<Arc<dyn NostrSigner>>, pubkey_hex: &str) {
settings_sync_init(signer, pubkey_hex);
}
/// Serialize syncable settings, build and sign a kind 30078 event.
pub fn settings_sync_publish() {
let state = G_SYNC_STATE.lock().unwrap();
if !state.have_signer {
return;
}
let browser_settings = settings::settings_get();
let payload = serde_json::json!({
"v": 2,
"updatedAt": std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.unwrap_or_default()
.as_secs(),
"sovereign_browser": {
"new_tab_url": browser_settings.new_tab_url,
"tab_bar_position": browser_settings.tab_bar_position,
"show_tab_close_buttons": browser_settings.show_tab_close_buttons,
"middle_click_close": browser_settings.middle_click_close,
"ctrl_tab_switch": browser_settings.ctrl_tab_switch,
"tab_drag_reorder": browser_settings.tab_drag_reorder,
"max_tabs": browser_settings.max_tabs,
"bootstrap_relays": browser_settings.bootstrap_relays,
"search_engine": browser_settings.search_engine,
}
});
if let Ok(payload_str) = serde_json::to_string(&payload) {
let _ = db::db_kv_set("settings_sync.last_payload", &payload_str);
}
println!("[settings_sync] Publish requested (NIP-44 encryption not yet implemented)");
}
/// Merge settings from a fetched kind 30078 event.
pub fn settings_sync_merge_from_nostr(event_json: &serde_json::Value) -> Result<(), Box<dyn std::error::Error>> {
let content = event_json["content"]
.as_str()
.ok_or("Missing content")?;
if let Ok(payload) = serde_json::from_str::<serde_json::Value>(content) {
if let Some(browser) = payload.get("sovereign_browser") {
settings::settings_update(browser);
settings::settings_save();
println!("[settings_sync] Merged settings from Nostr event");
}
}
Ok(())
}