use std::path::PathBuf;
use serde::Serialize;
use tauri::{AppHandle, Emitter, State};
use crate::models::log_entry::{LogEntry, LogFormat};
use crate::state::app_state::AppState;
use crate::watcher::tail;
#[derive(Clone, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct TailPayload {
pub entries: Vec<LogEntry>,
pub file_path: String,
pub reset: bool,
}
#[tauri::command]
pub fn start_tail(
path: String,
_format: LogFormat,
byte_offset: u64,
next_id: u64,
next_line: u32,
app: AppHandle,
state: State<'_, AppState>,
) -> Result<(), crate::error::AppError> {
let path_buf = PathBuf::from(&path);
{
let mut sessions = state
.tail_sessions
.lock()
.map_err(|e| crate::error::AppError::State(e.to_string()))?;
if let Some(old_session) = sessions.remove(&path_buf) {
old_session.stop();
}
}
let parser_selection = {
let open_files = state
.open_files
.lock()
.map_err(|e| crate::error::AppError::State(e.to_string()))?;
open_files
.get(&path_buf)
.map(|f| f.parser_selection.clone())
.ok_or_else(|| {
crate::error::AppError::InvalidInput(format!("file is not open: {}", path))
})?
};
let file_path_for_event = path.clone();
let session = tail::start_tail_session(
path_buf.clone(),
byte_offset,
parser_selection,
next_id,
next_line,
move |batch| {
let payload = TailPayload {
entries: batch.entries,
file_path: file_path_for_event.clone(),
reset: batch.reset,
};
if let Err(e) = app.emit("tail-new-entries", &payload) {
log::error!("Failed to emit tail entries: {}", e);
}
},
)?;
let mut sessions = state
.tail_sessions
.lock()
.map_err(|e| crate::error::AppError::State(e.to_string()))?;
sessions.insert(path_buf, session);
Ok(())
}
#[tauri::command]
pub fn stop_tail(path: String, state: State<'_, AppState>) -> Result<(), crate::error::AppError> {
let path_buf = PathBuf::from(&path);
let mut sessions = state
.tail_sessions
.lock()
.map_err(|e| crate::error::AppError::State(e.to_string()))?;
if let Some(session) = sessions.remove(&path_buf) {
session.stop();
}
Ok(())
}
#[tauri::command]
pub fn pause_tail(path: String, state: State<'_, AppState>) -> Result<(), crate::error::AppError> {
let path_buf = PathBuf::from(&path);
let sessions = state
.tail_sessions
.lock()
.map_err(|e| crate::error::AppError::State(e.to_string()))?;
if let Some(session) = sessions.get(&path_buf) {
session.set_paused(true);
}
Ok(())
}
#[tauri::command]
pub fn resume_tail(path: String, state: State<'_, AppState>) -> Result<(), crate::error::AppError> {
let path_buf = PathBuf::from(&path);
let sessions = state
.tail_sessions
.lock()
.map_err(|e| crate::error::AppError::State(e.to_string()))?;
if let Some(session) = sessions.get(&path_buf) {
session.set_paused(false);
}
Ok(())
}