- Add SaveMetaFn callback pattern: meta plugins receive a closure instead of
&Connection, enabling the same plugin code to work in local, client, and
server contexts (collect-to-Vec, collect-to-HashMap, or direct DB write)
- Client save now runs meta plugins locally during streaming (smart client
sets meta=false, server skips its own plugins)
- Add POST /api/item/{id}/update endpoint for re-running plugins on stored
content without downloading compressed data
- Add client update mode (--update with --meta-plugin flags)
- Extract shared utilities: stream_copy, print_serialized, build_path_table,
ensure_default_tag to reduce duplication across modes
- Add upsert_tag for idempotent tag addition (INSERT OR IGNORE)
- Add warn logging on save_meta lock failure in BaseMetaPlugin and MetaService
62 lines
2.0 KiB
Rust
62 lines
2.0 KiB
Rust
use crate::client::KeepClient;
|
|
use crate::modes::common::{
|
|
DisplayItemInfo, OutputFormat, format_size, render_item_info_table, settings_output_format,
|
|
};
|
|
use clap::Command;
|
|
use log::debug;
|
|
|
|
pub fn mode(
|
|
client: &KeepClient,
|
|
_cmd: &mut Command,
|
|
settings: &crate::config::Settings,
|
|
ids: &[i64],
|
|
tags: &[String],
|
|
) -> Result<(), anyhow::Error> {
|
|
debug!("CLIENT_INFO: Getting item info via remote server");
|
|
|
|
let output_format = settings_output_format(settings);
|
|
|
|
// If tags provided, find matching item first
|
|
let item_ids: Vec<i64> = if !tags.is_empty() {
|
|
let items = client.list_items(tags, "newest", 0, 1, &std::collections::HashMap::new())?;
|
|
if items.is_empty() {
|
|
return Err(anyhow::anyhow!("No items found matching tags: {:?}", tags));
|
|
}
|
|
items.into_iter().map(|i| i.id).collect()
|
|
} else {
|
|
ids.to_vec()
|
|
};
|
|
|
|
for &id in &item_ids {
|
|
let item = client.get_item_info(id)?;
|
|
|
|
match output_format {
|
|
OutputFormat::Json | OutputFormat::Yaml => {
|
|
crate::modes::common::print_serialized(&item, &output_format)?;
|
|
}
|
|
OutputFormat::Table => {
|
|
let display = DisplayItemInfo {
|
|
id: item.id,
|
|
timestamp: item.ts.clone(),
|
|
path: String::new(),
|
|
stream_size: item
|
|
.size
|
|
.map(|s| format_size(s as u64, settings.human_readable))
|
|
.unwrap_or_else(|| "N/A".to_string()),
|
|
compression: item.compression.clone(),
|
|
file_size: String::new(),
|
|
tags: item.tags.clone(),
|
|
metadata: item
|
|
.metadata
|
|
.iter()
|
|
.map(|(k, v)| (k.clone(), v.clone()))
|
|
.collect(),
|
|
};
|
|
render_item_info_table(&display, &settings.table_config);
|
|
}
|
|
}
|
|
}
|
|
|
|
Ok(())
|
|
}
|