use crate::feed_api::{FeedApiError, FeedApiResult};
use crate::password_encryption::PasswordEncryption;
use feedbin_api::models::{Cache, CacheRequestResponse, CacheResult, Subscription, Tagging};
use serde::{Deserialize, Serialize};
use std::fs::{self, File};
use std::io::Read;
use std::path::{Path, PathBuf};
static CONFIG_NAME: &str = "feedbin.json";
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct AccountConfig {
#[serde(skip_serializing_if = "Option::is_none")]
#[serde(default)]
user_name: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
#[serde(default)]
password: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
#[serde(default)]
url: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
#[serde(default)]
subscription_cache: Option<Cache>,
#[serde(skip_serializing_if = "Option::is_none")]
#[serde(default)]
taggings_cache: Option<Cache>,
#[serde(skip_serializing)]
#[serde(skip_deserializing)]
path: PathBuf,
}
impl AccountConfig {
pub fn load(config_dir: &Path) -> FeedApiResult<Self> {
let path = config_dir.join(CONFIG_NAME);
if path.as_path().exists() {
let mut contents = String::new();
tracing::info!(?path, "Attempting to open config file");
let mut file = File::open(&path).map_err(|error| {
tracing::error!(%error, "Failed to load config file");
FeedApiError::IO(error)
})?;
file.read_to_string(&mut contents).map_err(|error| {
tracing::error!(%error, "Reading content of file failed");
FeedApiError::IO(error)
})?;
let mut config: AccountConfig = serde_json::from_str(&contents)?;
if let Some(password) = config.password {
let password = PasswordEncryption::decrypt(&password)?;
config.password = Some(password);
}
config.path = path;
return Ok(config);
}
tracing::info!(?path, "Config file does not exist. Returning empty config");
Ok(AccountConfig {
user_name: None,
password: None,
url: None,
subscription_cache: None,
taggings_cache: None,
path,
})
}
pub fn save(&self) -> FeedApiResult<()> {
let mut config = self.clone();
if let Some(password) = config.get_password() {
config.set_password(&PasswordEncryption::encrypt(&password));
}
let data = serde_json::to_string_pretty(&config)?;
fs::write(&self.path, data).inspect_err(|error| tracing::error!(?self.path, %error,"Failed to write config"))?;
Ok(())
}
pub fn delete(&self) -> FeedApiResult<()> {
fs::remove_file(&self.path)?;
Ok(())
}
pub fn get_user_name(&self) -> Option<String> {
self.user_name.clone()
}
pub fn set_user_name(&mut self, user_name: &str) {
self.user_name = Some(user_name.to_owned());
}
pub fn get_password(&self) -> Option<String> {
self.password.clone()
}
pub fn set_password(&mut self, password: &str) {
self.password = Some(password.to_owned());
}
pub fn get_url(&self) -> Option<String> {
self.url.clone()
}
pub fn set_url(&mut self, url: &str) {
self.url = Some(url.to_owned());
}
pub fn get_subscription_cache(&self) -> Option<Cache> {
self.subscription_cache.clone()
}
pub fn set_subscription_cache(&mut self, subscriptions: &CacheRequestResponse<Vec<Subscription>>) {
if let CacheRequestResponse::Modified(CacheResult {
value: _subscriptions,
cache,
}) = subscriptions
{
self.subscription_cache.clone_from(cache);
}
}
pub fn reset_subscription_cache(&mut self) {
self.subscription_cache = None;
}
pub fn get_taggins_cache(&self) -> Option<Cache> {
self.taggings_cache.clone()
}
pub fn set_taggins_cache(&mut self, taggings: &CacheRequestResponse<Vec<Tagging>>) {
if let CacheRequestResponse::Modified(CacheResult { value: _tagging, cache }) = taggings {
self.taggings_cache.clone_from(cache);
}
}
pub fn reset_taggings_cache(&mut self) {
self.taggings_cache = None;
}
}