Save a session to disk atomically. Writes to a temporary file first, then renames to the final path. This prevents corruption if the process is killed mid-write. # Errors Returns `AgentError::SessionSaveFailed` if the write or rename fails.
(&self, session: &AgentSession)
| 527 | /// |
| 528 | /// Returns `AgentError::SessionSaveFailed` if the write or rename fails. |
| 529 | pub fn save(&self, session: &AgentSession) -> AgentResult<()> { |
| 530 | validate_session_id(&session.session_id)?; |
| 531 | |
| 532 | let path = self.session_path(&session.session_id); |
| 533 | let tmp_path = self.temp_session_path(&session.session_id); |
| 534 | |
| 535 | let data = |
| 536 | serde_json::to_string_pretty(session).map_err(|e| AgentError::SessionSaveFailed { |
| 537 | session_id: session.session_id.clone(), |
| 538 | reason: format!("JSON serialize error: {}", e), |
| 539 | })?; |
| 540 | |
| 541 | // Each writer needs its own same-directory temp file. Concurrent hook |
| 542 | // processes can save the same session, and threads within one process |
| 543 | // must not collide either. |
| 544 | if let Err(e) = std::fs::write(&tmp_path, data.as_bytes()) { |
| 545 | let _ = std::fs::remove_file(&tmp_path); |
| 546 | return Err(AgentError::SessionSaveFailed { |
| 547 | session_id: session.session_id.clone(), |
| 548 | reason: format!("write temp file: {}", e), |
| 549 | }); |
| 550 | } |
| 551 | |
| 552 | // Atomic rename |
| 553 | if let Err(e) = std::fs::rename(&tmp_path, &path) { |
| 554 | let _ = std::fs::remove_file(&tmp_path); |
| 555 | return Err(AgentError::SessionSaveFailed { |
| 556 | session_id: session.session_id.clone(), |
| 557 | reason: format!("rename temp file: {}", e), |
| 558 | }); |
| 559 | } |
| 560 | |
| 561 | Ok(()) |
| 562 | } |
| 563 | |
| 564 | /// Delete a session state file. |
| 565 | /// |