A Rust CLI for publishing thought records. Designed to work with thought.stream.
at main 2.4 kB view raw
1use anyhow::{Context, Result}; 2use directories::ProjectDirs; 3use serde::{Deserialize, Serialize}; 4use std::fs; 5use std::path::PathBuf; 6 7#[derive(Debug, Clone, Serialize, Deserialize)] 8pub struct Credentials { 9 pub username: String, 10 pub password: String, 11 pub pds_uri: String, 12} 13 14impl Credentials { 15 pub fn new(username: String, password: String, pds_uri: String) -> Self { 16 Self { 17 username, 18 password, 19 pds_uri, 20 } 21 } 22} 23 24pub struct CredentialStore { 25 config_dir: PathBuf, 26} 27 28impl CredentialStore { 29 pub fn new() -> Result<Self> { 30 let project_dirs = ProjectDirs::from("com", "thoughtstream", "think") 31 .context("Failed to determine project directories")?; 32 33 let config_dir = project_dirs.config_dir().to_path_buf(); 34 35 // Create config directory if it doesn't exist 36 fs::create_dir_all(&config_dir) 37 .context("Failed to create config directory")?; 38 39 Ok(Self { config_dir }) 40 } 41 42 fn credentials_path(&self) -> PathBuf { 43 self.config_dir.join("credentials.json") 44 } 45 46 pub fn store(&self, credentials: &Credentials) -> Result<()> { 47 let json = serde_json::to_string_pretty(credentials) 48 .context("Failed to serialize credentials")?; 49 50 fs::write(self.credentials_path(), json) 51 .context("Failed to write credentials file")?; 52 53 println!("Credentials stored successfully"); 54 Ok(()) 55 } 56 57 pub fn load(&self) -> Result<Option<Credentials>> { 58 let path = self.credentials_path(); 59 60 if !path.exists() { 61 return Ok(None); 62 } 63 64 let json = fs::read_to_string(&path) 65 .context("Failed to read credentials file")?; 66 67 let credentials: Credentials = serde_json::from_str(&json) 68 .context("Failed to parse credentials file")?; 69 70 Ok(Some(credentials)) 71 } 72 73 pub fn clear(&self) -> Result<()> { 74 let path = self.credentials_path(); 75 76 if path.exists() { 77 fs::remove_file(&path) 78 .context("Failed to remove credentials file")?; 79 println!("Credentials cleared successfully"); 80 } else { 81 println!("No credentials found to clear"); 82 } 83 84 Ok(()) 85 } 86 87 pub fn exists(&self) -> bool { 88 self.credentials_path().exists() 89 } 90}