refactor: split pod metadata store
This commit is contained in:
@@ -20,6 +20,7 @@ uuid = { workspace = true }
|
||||
toml = { workspace = true }
|
||||
manifest = { workspace = true }
|
||||
session-store = { workspace = true }
|
||||
pod-store = { workspace = true }
|
||||
pod-registry = { workspace = true }
|
||||
serde = { workspace = true, features = ["derive"] }
|
||||
pulldown-cmark = { version = "0.13.3", default-features = false }
|
||||
|
||||
@@ -3,6 +3,7 @@ use std::path::{Path, PathBuf};
|
||||
use std::time::{Duration, Instant};
|
||||
|
||||
use crossterm::event::{Event as TermEvent, KeyCode, KeyEvent, KeyModifiers, poll, read};
|
||||
use pod_store::FsPodStore;
|
||||
use protocol::stream::{JsonLineReader, JsonLineWriter};
|
||||
use protocol::{ErrorCode, Event, InvokeKind, Method, PodStatus, Segment};
|
||||
use ratatui::Frame;
|
||||
@@ -199,12 +200,22 @@ fn default_store_dir() -> Result<PathBuf, MultiPodError> {
|
||||
manifest::paths::sessions_dir().ok_or_else(|| {
|
||||
MultiPodError::Io(io::Error::new(
|
||||
io::ErrorKind::NotFound,
|
||||
"could not resolve sessions directory \
|
||||
(set INSOMNIA_HOME, INSOMNIA_DATA_DIR, or HOME)",
|
||||
"could not resolve sessions directory",
|
||||
))
|
||||
})
|
||||
}
|
||||
|
||||
fn default_pod_store_dir() -> Result<PathBuf, MultiPodError> {
|
||||
manifest::paths::data_dir()
|
||||
.map(|dir| dir.join("pods"))
|
||||
.ok_or_else(|| {
|
||||
MultiPodError::Io(io::Error::new(
|
||||
io::ErrorKind::NotFound,
|
||||
"could not resolve pod state directory",
|
||||
))
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub(crate) enum SendEligibility {
|
||||
@@ -483,7 +494,8 @@ enum MultiPodAction {
|
||||
async fn load_pod_list(selected_name: Option<String>) -> Result<PodList, MultiPodError> {
|
||||
let store_dir = default_store_dir()?;
|
||||
let store = FsStore::new(&store_dir)?;
|
||||
let stored = read_stored_pod_infos(&store_dir, &store)?;
|
||||
let pod_store = FsPodStore::new(default_pod_store_dir()?).map_err(io::Error::other)?;
|
||||
let stored = read_stored_pod_infos(&store, &pod_store)?;
|
||||
let live = read_reachable_live_pod_infos(&store)
|
||||
.await
|
||||
.unwrap_or_default();
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
//! Inline-viewport "pick a Pod to attach or restore" UX.
|
||||
//!
|
||||
//! Reads live Pod allocations from the runtime registry and stopped Pod state
|
||||
//! from the session store's name-keyed metadata. Picking a live row attaches to
|
||||
//! from the pod-store name-keyed metadata. Picking a live row attaches to
|
||||
//! its socket; picking a stopped row restores via `insomnia-pod --pod <name>`.
|
||||
|
||||
use std::io;
|
||||
@@ -9,6 +9,7 @@ use std::path::PathBuf;
|
||||
use std::time::Duration;
|
||||
|
||||
use crossterm::event::{self, Event as TermEvent, KeyCode, KeyEventKind, KeyModifiers};
|
||||
use pod_store::FsPodStore;
|
||||
use ratatui::Terminal;
|
||||
use ratatui::backend::CrosstermBackend;
|
||||
use ratatui::layout::{Constraint, Layout};
|
||||
@@ -102,7 +103,8 @@ impl PodRowState {
|
||||
pub async fn run() -> Result<PickerOutcome, PickerError> {
|
||||
let store_dir = default_store_dir()?;
|
||||
let store = FsStore::new(&store_dir)?;
|
||||
let stored_pods = read_stored_pod_infos(&store_dir, &store)?;
|
||||
let pod_store = FsPodStore::new(default_pod_store_dir()?).map_err(io::Error::other)?;
|
||||
let stored_pods = read_stored_pod_infos(&store, &pod_store)?;
|
||||
let live_pods = read_reachable_live_pod_infos(&store)
|
||||
.await
|
||||
.unwrap_or_default();
|
||||
@@ -172,6 +174,18 @@ fn default_store_dir() -> Result<PathBuf, PickerError> {
|
||||
})
|
||||
}
|
||||
|
||||
fn default_pod_store_dir() -> Result<PathBuf, PickerError> {
|
||||
manifest::paths::data_dir()
|
||||
.map(|dir| dir.join("pods"))
|
||||
.ok_or_else(|| {
|
||||
PickerError::Io(io::Error::new(
|
||||
io::ErrorKind::NotFound,
|
||||
"could not resolve pod state directory \
|
||||
(set INSOMNIA_HOME, INSOMNIA_DATA_DIR, or HOME)",
|
||||
))
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn live_socket_for_pod(pod_name: &str) -> Option<PathBuf> {
|
||||
pod_list_live_socket_for_pod(pod_name)
|
||||
}
|
||||
|
||||
+21
-30
@@ -1,14 +1,14 @@
|
||||
use std::collections::BTreeMap;
|
||||
use std::fs;
|
||||
use std::io;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::time::Duration;
|
||||
|
||||
use client::PodClient;
|
||||
use pod_registry::{LockFileGuard, default_registry_path};
|
||||
use pod_store::{PodActiveSegmentRef, PodMetadata, PodMetadataStore};
|
||||
use protocol::{Event, PodStatus};
|
||||
use session_store::{
|
||||
FsStore, LogEntry, LoggedContentPart, LoggedItem, PodMetadata, SegmentId, SessionId, Store,
|
||||
FsStore, LogEntry, LoggedContentPart, LoggedItem, SegmentId, SessionId, Store,
|
||||
};
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
@@ -234,27 +234,17 @@ pub(crate) enum PodEntryDiagnosticKind {
|
||||
}
|
||||
|
||||
pub(crate) fn read_stored_pod_infos(
|
||||
store_dir: &Path,
|
||||
store: &FsStore,
|
||||
pod_store: &impl PodMetadataStore,
|
||||
) -> Result<Vec<StoredPodInfo>, io::Error> {
|
||||
let pods_dir = store_dir.join("pods");
|
||||
let mut records = Vec::new();
|
||||
if !pods_dir.exists() {
|
||||
return Ok(records);
|
||||
}
|
||||
|
||||
for entry in fs::read_dir(pods_dir)? {
|
||||
let entry = entry?;
|
||||
if !entry.file_type()?.is_dir() {
|
||||
continue;
|
||||
}
|
||||
let pod_name = entry.file_name().to_string_lossy().to_string();
|
||||
let path = entry.path().join("metadata.json");
|
||||
let info = match fs::read_to_string(&path) {
|
||||
Ok(content) => match serde_json::from_str::<PodMetadata>(&content) {
|
||||
Ok(metadata) => stored_info_from_metadata(store, pod_name, metadata),
|
||||
Err(e) => corrupt_stored_info(pod_name, e.to_string()),
|
||||
},
|
||||
for pod_name in pod_store.list_names().map_err(io::Error::other)? {
|
||||
let info = match pod_store.read_by_name(&pod_name) {
|
||||
Ok(Some(metadata)) => stored_info_from_metadata(store, pod_name, metadata),
|
||||
Ok(None) => corrupt_stored_info(
|
||||
pod_name,
|
||||
"metadata disappeared during discovery".to_string(),
|
||||
),
|
||||
Err(e) => corrupt_stored_info(pod_name, e.to_string()),
|
||||
};
|
||||
records.push(info);
|
||||
@@ -392,10 +382,7 @@ fn summarize_live_pod(store: &FsStore, live: &LivePodInfo) -> PodEntrySummary {
|
||||
}
|
||||
}
|
||||
|
||||
fn summarize_metadata(
|
||||
store: &FsStore,
|
||||
active: Option<&session_store::PodActiveSegmentRef>,
|
||||
) -> SegmentSummary {
|
||||
fn summarize_metadata(store: &FsStore, active: Option<&PodActiveSegmentRef>) -> SegmentSummary {
|
||||
let Some(active) = active else {
|
||||
return SegmentSummary {
|
||||
updated_at: 0,
|
||||
@@ -558,7 +545,9 @@ fn trim_one_line(s: &str, max_chars: usize) -> String {
|
||||
mod tests {
|
||||
use super::*;
|
||||
use llm_worker::llm_client::types::RequestConfig;
|
||||
use session_store::{PodActiveSegmentRef, PodMetadataStore, new_segment_id, new_session_id};
|
||||
use pod_store::FsPodStore;
|
||||
use pod_store::{PodActiveSegmentRef, PodMetadataStore};
|
||||
use session_store::{new_segment_id, new_session_id};
|
||||
use tempfile::tempdir;
|
||||
|
||||
const SOURCE: PodVisibilitySource = PodVisibilitySource::ResumePicker;
|
||||
@@ -776,11 +765,12 @@ mod tests {
|
||||
fn read_stored_pod_infos_reports_corrupt_metadata() {
|
||||
let dir = tempdir().unwrap();
|
||||
let store = FsStore::new(dir.path()).unwrap();
|
||||
let pod_store = FsPodStore::new(dir.path().join("pods")).unwrap();
|
||||
let pod_dir = dir.path().join("pods").join("broken");
|
||||
fs::create_dir_all(&pod_dir).unwrap();
|
||||
fs::write(pod_dir.join("metadata.json"), "{not-json").unwrap();
|
||||
std::fs::create_dir_all(&pod_dir).unwrap();
|
||||
std::fs::write(pod_dir.join("metadata.json"), "{not-json").unwrap();
|
||||
|
||||
let records = read_stored_pod_infos(dir.path(), &store).unwrap();
|
||||
let records = read_stored_pod_infos(&store, &pod_store).unwrap();
|
||||
assert_eq!(records.len(), 1);
|
||||
assert_eq!(records[0].pod_name, "broken");
|
||||
assert!(matches!(
|
||||
@@ -793,16 +783,17 @@ mod tests {
|
||||
fn read_stored_pod_infos_reads_metadata() {
|
||||
let dir = tempdir().unwrap();
|
||||
let store = FsStore::new(dir.path()).unwrap();
|
||||
let pod_store = FsPodStore::new(dir.path().join("pods")).unwrap();
|
||||
let session_id = new_session_id();
|
||||
let segment_id = new_segment_id();
|
||||
store
|
||||
pod_store
|
||||
.write(&PodMetadata::new(
|
||||
"agent",
|
||||
Some(PodActiveSegmentRef::active_segment(session_id, segment_id)),
|
||||
))
|
||||
.unwrap();
|
||||
|
||||
let records = read_stored_pod_infos(dir.path(), &store).unwrap();
|
||||
let records = read_stored_pod_infos(&store, &pod_store).unwrap();
|
||||
assert_eq!(records.len(), 1);
|
||||
assert_eq!(records[0].pod_name, "agent");
|
||||
assert_eq!(records[0].metadata_state, StoredMetadataState::Present);
|
||||
|
||||
Reference in New Issue
Block a user