use std::fs;
use std::time::Duration;
use std::time::SystemTime;
use bevy_brp_mcp_macros::ParamStruct;
use bevy_brp_mcp_macros::ResultStruct;
use bevy_brp_mcp_macros::ToolFn;
use schemars::JsonSchema;
use serde::Deserialize;
use serde::Serialize;
use super::support;
use super::support::LogFileEntry;
use crate::error::Error;
use crate::error::Result;
use crate::tool::HandlerContext;
use crate::tool::HandlerResult;
use crate::tool::ToolFn;
use crate::tool::ToolResult;
#[derive(Clone, Deserialize, Serialize, JsonSchema, ParamStruct)]
pub struct DeleteLogsParams {
#[to_metadata(skip_if_none)]
pub app_name: Option<String>,
#[to_metadata(skip_if_none)]
pub older_than_seconds: Option<u32>,
}
#[derive(Debug, Clone, Serialize, Deserialize, ResultStruct)]
pub struct DeleteLogsResult {
#[serde(rename = "deleted_files")]
#[to_metadata]
files: Vec<String>,
#[serde(rename = "deleted_count")]
#[to_metadata]
count: usize,
#[to_metadata(skip_if_none)]
app_name_filter: Option<String>,
#[to_metadata(skip_if_none)]
older_than_seconds: Option<u32>,
#[to_message(message_template = "Deleted {deleted_count} log files")]
message_template: String,
}
#[derive(ToolFn)]
#[tool_fn(params = "DeleteLogsParams", output = "DeleteLogsResult")]
pub struct DeleteLogs;
#[allow(
clippy::unused_async,
reason = "ToolFn trait requires async handler signature"
)]
async fn handle_impl(params: DeleteLogsParams) -> Result<DeleteLogsResult> {
let files = delete_log_files(params.app_name.as_deref(), params.older_than_seconds)?;
Ok(DeleteLogsResult::new(
files.clone(),
files.len(),
params.app_name.clone(),
params.older_than_seconds,
))
}
fn delete_log_files(
app_name_filter: Option<&str>,
older_than_seconds: Option<u32>,
) -> Result<Vec<String>> {
let mut files = Vec::new();
let cutoff_time = older_than_seconds
.map(|seconds| SystemTime::now() - Duration::from_secs(u64::from(seconds)));
let filter = |entry: &LogFileEntry| -> bool {
if let Some(app_filter) = app_name_filter
&& entry.app_name != app_filter
{
return false;
}
if let Some(cutoff) = cutoff_time
&& let Ok(modified) = entry.metadata.modified()
{
if modified > cutoff {
return false;
}
}
true
};
let log_entries = if app_name_filter.is_some() {
support::iterate_app_log_files(filter)
.map_err(|e| Error::tool_call_failed(e.to_string()))?
} else {
support::iterate_log_files(filter).map_err(|e| Error::tool_call_failed(e.to_string()))?
};
for entry in log_entries {
if fs::remove_file(&entry.path).is_ok() {
files.push(entry.filename);
}
}
Ok(files)
}