use tonic::{Response, Status};
use tracing::info;
use crate::server::ProtocolServer;
use crate::validation::validate_file_path;
use crate::{FileEntry, FileListRequest, FileListResponse};
pub async fn handle_file_list(
server: &ProtocolServer,
req: FileListRequest,
) -> Result<Response<FileListResponse>, Status> {
if let Some(ref prefix) = req.prefix {
if !prefix.is_empty() {
validate_file_path(prefix)?;
}
}
let session = server.validate_session(&req.session_id)?;
crate::require_live_session::require_live_session(server, &req.session_id).await?;
let sid = req
.session_id
.parse::<uuid::Uuid>()
.map_err(|_| Status::invalid_argument("Invalid session ID"))?;
server.session_mgr().touch_session(&sid);
let engine = server.engine();
let ws = engine
.workspace_manager()
.get_workspace(&sid)
.ok_or_else(|| Status::not_found("Workspace not found for session"))?;
let (_repo_id, git_repo) = engine
.get_repo(&session.codebase)
.await
.map_err(|e| Status::internal(format!("Repo error: {e}")))?;
let prefix = req.prefix.as_deref().filter(|p| !p.is_empty());
let all_files = ws
.list_files(&git_repo, req.only_modified, prefix)
.map_err(|e| Status::internal(format!("List files failed: {e}")))?;
let modified_paths: std::collections::HashSet<String> =
ws.overlay.list_paths().into_iter().collect();
let repo_id = ws.repo_id;
let wm = engine.workspace_manager();
let files: Vec<FileEntry> = all_files
.into_iter()
.map(|path| {
let modified = modified_paths.contains(&path);
let modified_by_other = wm.describe_other_modifiers(&path, repo_id, sid);
FileEntry {
path,
modified_in_session: modified,
modified_by_other,
}
})
.collect();
info!(
session_id = %req.session_id,
file_count = files.len(),
only_modified = req.only_modified,
"FILE_LIST: served"
);
Ok(Response::new(FileListResponse { files }))
}