Persist last publish report across restarts
This commit is contained in:
parent
e936524f72
commit
bab82f5148
7 changed files with 63 additions and 3 deletions
|
|
@ -140,6 +140,12 @@ export interface AppState {
|
|||
settings: Settings;
|
||||
/** Recently deleted profiles, newest last, for undo. */
|
||||
undo_history?: ProfileSummary[];
|
||||
/** The most recent publish report, persisted across restarts. */
|
||||
last_publish?: {
|
||||
event_id: string;
|
||||
succeeded: string[];
|
||||
failed: RelayFailure[];
|
||||
} | null;
|
||||
}
|
||||
|
||||
/** A secret key revealed after the vault is unlocked. */
|
||||
|
|
|
|||
|
|
@ -98,6 +98,9 @@ export function AppProvider({ children }: { children: ReactNode }) {
|
|||
const initial = await api.init();
|
||||
if (!cancelled) {
|
||||
setState(initial);
|
||||
if (initial.last_publish) {
|
||||
setLastPublish({ report: initial.last_publish, error: null, details: null, at: Date.now() });
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
if (!cancelled) {
|
||||
|
|
|
|||
|
|
@ -43,6 +43,7 @@ export function makeState(overrides?: Partial<AppState>): AppState {
|
|||
active_profile: alice,
|
||||
profiles: [alice, bob],
|
||||
settings,
|
||||
last_publish: null,
|
||||
...overrides,
|
||||
};
|
||||
}
|
||||
|
|
|
|||
10
src/app.rs
10
src/app.rs
|
|
@ -7,7 +7,7 @@ use crate::crypto::{self, VaultKey};
|
|||
use crate::errors::AppError;
|
||||
use crate::profiles::{self, ProfileSummary};
|
||||
use crate::settings::Settings;
|
||||
use crate::vault::{self, KdfParams, StoredProfile, Vault, VaultCrypto};
|
||||
use crate::vault::{self, KdfParams, StoredProfile, StoredPublishReport, Vault, VaultCrypto};
|
||||
|
||||
/// Minimum password length accepted when encrypting the vault.
|
||||
pub const MIN_PASSWORD_LEN: usize = 8;
|
||||
|
|
@ -20,6 +20,8 @@ pub struct App {
|
|||
unlock_key: Option<VaultKey>,
|
||||
/// Stack of deleted profiles for undo functionality.
|
||||
pub undo_history: Vec<ProfileSummary>,
|
||||
/// The most recent publish report, persisted across restarts.
|
||||
pub last_publish: Option<StoredPublishReport>,
|
||||
}
|
||||
|
||||
/// Snapshot of everything the UI needs, containing no secret keys.
|
||||
|
|
@ -38,6 +40,9 @@ pub struct AppStateView {
|
|||
/// Recently deleted profiles, newest last, for undo.
|
||||
#[serde(skip_serializing_if = "Vec::is_empty")]
|
||||
pub undo_history: Vec<ProfileSummary>,
|
||||
/// The most recent publish report, persisted across restarts.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub last_publish: Option<StoredPublishReport>,
|
||||
}
|
||||
|
||||
impl App {
|
||||
|
|
@ -48,6 +53,7 @@ impl App {
|
|||
settings: vault::load_settings()?,
|
||||
unlock_key: None,
|
||||
undo_history: Vec::new(),
|
||||
last_publish: vault::load_last_publish(),
|
||||
})
|
||||
}
|
||||
|
||||
|
|
@ -240,6 +246,7 @@ impl App {
|
|||
profiles: profiles::summaries(&self.vault),
|
||||
settings: self.settings.clone(),
|
||||
undo_history: self.undo_history.clone(),
|
||||
last_publish: self.last_publish.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -302,6 +309,7 @@ mod tests {
|
|||
settings: offline_settings(),
|
||||
unlock_key: None,
|
||||
undo_history: Vec::new(),
|
||||
last_publish: None,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -464,6 +464,13 @@ async fn run_with_app(app: &mut App, request: Request) -> Result<serde_json::Val
|
|||
let report =
|
||||
publish::publish_active(&app.vault, &app.settings, &content, app.vault_key())
|
||||
.await?;
|
||||
let stored = crate::vault::StoredPublishReport {
|
||||
event_id: report.event_id.clone(),
|
||||
succeeded: report.succeeded.clone(),
|
||||
failed: report.failed.clone(),
|
||||
};
|
||||
let _ = crate::vault::save_last_publish(&stored);
|
||||
app.last_publish = Some(stored);
|
||||
Ok(json!(report))
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ use std::collections::HashSet;
|
|||
use std::time::Duration;
|
||||
|
||||
use nostr_sdk::prelude::*;
|
||||
use serde::Serialize;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::crypto::VaultKey;
|
||||
use crate::errors::{AppError, ErrorKind};
|
||||
|
|
@ -16,7 +16,7 @@ use crate::vault::Vault;
|
|||
const RELAY_SEND_TIMEOUT: Duration = Duration::from_secs(6);
|
||||
|
||||
/// A relay that rejected a published note.
|
||||
#[derive(Debug, Clone, Serialize)]
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct RelayFailure {
|
||||
pub url: String,
|
||||
/// Concise, user-facing reason.
|
||||
|
|
|
|||
35
src/vault.rs
35
src/vault.rs
|
|
@ -18,6 +18,8 @@ pub const VAULT_VERSION: u32 = 2;
|
|||
pub const VAULT_FILE_NAME: &str = "profiles_vault.json";
|
||||
/// Filename of the settings file.
|
||||
pub const SETTINGS_FILE_NAME: &str = "settings.json";
|
||||
/// Filename of the last publish report.
|
||||
pub const LAST_PUBLISH_FILE_NAME: &str = "last_publish.json";
|
||||
|
||||
/// A profile stored on disk.
|
||||
///
|
||||
|
|
@ -180,6 +182,39 @@ pub fn settings_path() -> PathBuf {
|
|||
data_dir().join(SETTINGS_FILE_NAME)
|
||||
}
|
||||
|
||||
pub fn last_publish_path() -> PathBuf {
|
||||
data_dir().join(LAST_PUBLISH_FILE_NAME)
|
||||
}
|
||||
|
||||
/// A minimal publish report persisted across restarts so the Home screen can
|
||||
/// show the most recent publication result.
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct StoredPublishReport {
|
||||
pub event_id: String,
|
||||
pub succeeded: Vec<String>,
|
||||
pub failed: Vec<crate::publish::RelayFailure>,
|
||||
}
|
||||
|
||||
/// Load the last publish report, returning `None` when absent or unreadable.
|
||||
pub fn load_last_publish() -> Option<StoredPublishReport> {
|
||||
let path = last_publish_path();
|
||||
if !path.exists() {
|
||||
return None;
|
||||
}
|
||||
let content = fs::read_to_string(&path).ok()?;
|
||||
if content.trim().is_empty() {
|
||||
return None;
|
||||
}
|
||||
serde_json::from_str(&content).ok()
|
||||
}
|
||||
|
||||
/// Persist the last publish report with restrictive permissions.
|
||||
pub fn save_last_publish(report: &StoredPublishReport) -> Result<(), AppError> {
|
||||
let content = serde_json::to_string_pretty(report)
|
||||
.map_err(|e| AppError::json("Could not prepare the last publish report for saving", e))?;
|
||||
write_restricted(&last_publish_path(), &content)
|
||||
}
|
||||
|
||||
/// Candidate locations for a legacy vault created by the old CLI version.
|
||||
///
|
||||
/// The old application wrote `profiles_vault.json` in its working directory.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue