refactor: splitted controller and reconciler
This commit is contained in:
77
src/state.rs
77
src/state.rs
@@ -1,80 +1,55 @@
|
||||
use miette::{Context, IntoDiagnostic, Result};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::cell::{Ref, RefCell};
|
||||
use std::collections::HashMap;
|
||||
use std::path::PathBuf;
|
||||
|
||||
use crate::config::PostgresVersion;
|
||||
|
||||
/// State information for a single PostgreSQL instance
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct InstanceState {
|
||||
/// Docker container ID
|
||||
pub container_id: String,
|
||||
|
||||
/// PostgreSQL version running in the container
|
||||
pub postgres_version: PostgresVersion,
|
||||
|
||||
/// Port the container is bound to
|
||||
pub port: u16,
|
||||
|
||||
/// Timestamp when the instance was created (Unix timestamp)
|
||||
pub created_at: u64,
|
||||
}
|
||||
|
||||
/// Manages the global state file at ~/.pgd/state.json
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct StateManager {
|
||||
/// Map of project name to instance state
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
|
||||
struct State {
|
||||
#[serde(default)]
|
||||
instances: HashMap<String, InstanceState>,
|
||||
}
|
||||
|
||||
/// Get the path to the state file (~/.pgd/state.json)
|
||||
|
||||
fn state_file_path() -> Result<PathBuf> {
|
||||
let home = std::env::var("HOME")
|
||||
.into_diagnostic()
|
||||
.wrap_err("Failed to get HOME environment variable")?;
|
||||
|
||||
Ok(PathBuf::from(home).join(".pgd").join("state.json"))
|
||||
}
|
||||
|
||||
|
||||
impl StateManager {
|
||||
/// Load the state manager from disk, or create a new one if it doesn't exist
|
||||
pub fn load() -> Result<Self> {
|
||||
impl State {
|
||||
fn new() -> Result<Self> {
|
||||
let state_path = state_file_path()?;
|
||||
|
||||
if !state_path.exists() {
|
||||
// Create the directory if it doesn't exist
|
||||
if let Some(parent) = state_path.parent() {
|
||||
std::fs::create_dir_all(parent)
|
||||
.into_diagnostic()
|
||||
.wrap_err("Failed to create .pgd directory")?;
|
||||
}
|
||||
|
||||
// Return empty state
|
||||
return Ok(StateManager {
|
||||
instances: HashMap::new(),
|
||||
});
|
||||
return Ok(Self::default());
|
||||
}
|
||||
|
||||
let content = std::fs::read_to_string(&state_path)
|
||||
.into_diagnostic()
|
||||
.wrap_err_with(|| format!("Failed to read state file: {}", state_path.display()))?;
|
||||
|
||||
let state: StateManager = serde_json::from_str(&content)
|
||||
let state: Self = serde_json::from_str(&content)
|
||||
.into_diagnostic()
|
||||
.wrap_err("Failed to parse state.json")?;
|
||||
|
||||
Ok(state)
|
||||
}
|
||||
|
||||
/// Save the state manager to disk
|
||||
pub fn save(&self) -> Result<()> {
|
||||
fn save(&self) -> Result<()> {
|
||||
let state_path = state_file_path()?;
|
||||
|
||||
// Ensure directory exists
|
||||
if let Some(parent) = state_path.parent() {
|
||||
std::fs::create_dir_all(parent)
|
||||
.into_diagnostic()
|
||||
@@ -91,20 +66,30 @@ impl StateManager {
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// Get mutable state for a specific project
|
||||
pub fn get_mut(&mut self, project_name: &str) -> Option<&mut InstanceState> {
|
||||
self.instances.get_mut(project_name)
|
||||
pub struct StateManager(RefCell<State>);
|
||||
|
||||
impl StateManager {
|
||||
pub fn new() -> Result<Self> {
|
||||
Ok(Self(RefCell::new(State::new()?)))
|
||||
}
|
||||
|
||||
/// Set the state for a specific project
|
||||
pub fn set(&mut self, project_name: String, state: InstanceState) {
|
||||
self.instances.insert(project_name, state);
|
||||
pub fn save(&self) -> Result<()> {
|
||||
self.0.borrow().save()?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Remove the state for a specific project
|
||||
pub fn remove(&mut self, project_name: &str) -> Option<InstanceState> {
|
||||
self.instances.remove(project_name)
|
||||
pub fn get(&self, project_name: &str) -> Option<InstanceState> {
|
||||
self.0.borrow().instances.get(project_name).cloned()
|
||||
}
|
||||
|
||||
pub fn set(&self, project_name: String, state: InstanceState) {
|
||||
self.0.borrow_mut().instances.insert(project_name, state);
|
||||
}
|
||||
|
||||
pub fn remove(&self, project_name: &str) -> Option<InstanceState> {
|
||||
self.0.borrow_mut().instances.remove(project_name)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -122,4 +107,10 @@ impl InstanceState {
|
||||
created_at: now,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn state_file_path() -> Result<PathBuf> {
|
||||
let home = std::env::home_dir().wrap_err("Failed to get HOME environment variable")?;
|
||||
|
||||
Ok(home.join(".pgd").join("state.json"))
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user