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    crate::require_live_session::require_live_session(server, &req.session_id).await?;
21
22    let sid = req
23        .session_id
24        .parse::<uuid::Uuid>()
25        .map_err(|_| Status::invalid_argument("Invalid session ID"))?;
26    server.session_mgr().touch_session(&sid);
27
28    let engine = server.engine();
29
30    // Get workspace for this session
31    let ws = engine
32        .workspace_manager()
33        .get_workspace(&sid)
34        .ok_or_else(|| Status::not_found("Workspace not found for session"))?;
35
36    // Get git repo for base-tree fallback
37    let (_repo_id, git_repo) = engine
38        .get_repo(&session.codebase)
39        .await
40        .map_err(|e| Status::internal(format!("Repo error: {e}")))?;
41
42    let result = ws
43        .read_file(&req.path, &git_repo)
44        .map_err(|e| Status::not_found(format!("File not found: {e}")))?;
45
46    // Record the read so the STALE_OVERLAY pre-write check can detect when
47    // this session's local view of `path` predates a competing submitted
48    // changeset touching the same path.
49    ws.mark_read(&req.path);
50
51    info!(
52        session_id = %req.session_id,
53        path = %req.path,
54        modified = result.modified_in_session,
55        "FILE_READ: served"
56    );
57
58    Ok(Response::new(FileReadResponse {
59        content: result.content,
60        hash: result.hash,
61        modified_in_session: result.modified_in_session,
62    }))
63}