Skip to main content

dk_protocol/
file_read.rs

1use tonic::{Response, Status};
2use tracing::info;
3
4use crate::server::ProtocolServer;
5use crate::validation::validate_file_path;
6use crate::{FileReadRequest, FileReadResponse};
7
8/// Handle a FileRead RPC.
9///
10/// Reads a file through the session workspace overlay:
11/// 1. Check the overlay for session-local modifications.
12/// 2. Fall through to the Git tree at the workspace's base commit.
13pub async fn handle_file_read(
14    server: &ProtocolServer,
15    req: FileReadRequest,
16) -> Result<Response<FileReadResponse>, Status> {
17    validate_file_path(&req.path)?;
18
19    let session = server.validate_session(&req.session_id)?;
20
21    let sid = req
22        .session_id
23        .parse::<uuid::Uuid>()
24        .map_err(|_| Status::invalid_argument("Invalid session ID"))?;
25    server.session_mgr().touch_session(&sid);
26
27    let engine = server.engine();
28
29    // Get workspace for this session
30    let ws = engine
31        .workspace_manager()
32        .get_workspace(&sid)
33        .ok_or_else(|| Status::not_found("Workspace not found for session"))?;
34
35    // Get git repo for base-tree fallback
36    let (_repo_id, git_repo) = engine
37        .get_repo(&session.codebase)
38        .await
39        .map_err(|e| Status::internal(format!("Repo error: {e}")))?;
40
41    let result = ws
42        .read_file(&req.path, &git_repo)
43        .map_err(|e| Status::not_found(format!("File not found: {e}")))?;
44
45    info!(
46        session_id = %req.session_id,
47        path = %req.path,
48        modified = result.modified_in_session,
49        "FILE_READ: served"
50    );
51
52    Ok(Response::new(FileReadResponse {
53        content: result.content,
54        hash: result.hash,
55        modified_in_session: result.modified_in_session,
56    }))
57}