From 9cdc575666faad4c162f4b4cf519bfdd1fd528dc Mon Sep 17 00:00:00 2001 From: Benedikt Peetz Date: Fri, 24 Jul 2026 17:56:36 +0200 Subject: feat: Finalize design for fish-shell integration --- crates/daemon/src/api/history.rs | 80 +++++++++++++++++++++++++++------------- 1 file changed, 55 insertions(+), 25 deletions(-) (limited to 'crates/daemon/src/api/history.rs') diff --git a/crates/daemon/src/api/history.rs b/crates/daemon/src/api/history.rs index 6165464d..0b373604 100644 --- a/crates/daemon/src/api/history.rs +++ b/crates/daemon/src/api/history.rs @@ -1,10 +1,10 @@ -use std::pin::Pin; +use std::{pin::Pin, time::Duration}; use dashmap::DashMap; use eyre::Result; use time::OffsetDateTime; use tokio_stream::Stream; -use tonic::{Request, Response, Status}; +use tonic::{IntoRequest, Request, Response, Status}; use tracing::{Level, instrument}; use crate::{ @@ -12,12 +12,16 @@ use crate::{ daemon::DaemonHandle, events::DaemonEvent, }; -use turtle::{ +use turtle_api::{ + client::{ + proto_duration_to_std, proto_timestamp_to_time, std_to_proto_duration, + time_to_proto_timestamp, + }, generated::{ DAEMON_PROTOCOL_VERSION, history::{ - EndHistoryReply, EndHistoryRequest, HistoryEntry, HistoryEventKind, HistoryReply, - HistoryRequest, StartHistoryReply, StartHistoryRequest, TailHistoryReply, + AddHistoryRequest, EndHistoryReply, EndHistoryRequest, HistoryEntry, HistoryEventKind, + HistoryReply, HistoryRequest, StartHistoryReply, StartHistoryRequest, TailHistoryReply, TailHistoryRequest, history_server::{History as HistorySvc, HistoryServer}, }, @@ -60,8 +64,8 @@ impl HistoryService { fn history_to_reply(history: History) -> HistoryEntry { HistoryEntry { - timestamp: history.timestamp.unix_timestamp_nanos() as u64, - id: history.id.0, + timestamp: time_to_proto_timestamp(history.timestamp), + id: history.id.to_string(), command: history.command, cwd: history.cwd, session: history.session, @@ -69,7 +73,7 @@ fn history_to_reply(history: History) -> HistoryEntry { author: history.author, intent: history.intent.unwrap_or_default(), exit: history.exit, - duration: history.duration, + duration: std_to_proto_duration(history.duration), } } @@ -85,8 +89,8 @@ impl HistorySvc for HistoryService { let req = request.into_inner(); let entries = if let Some(range) = req.range { - let from = OffsetDateTime::from_unix_timestamp(range.start as i64).unwrap(); - let to = OffsetDateTime::from_unix_timestamp(range.end as i64).unwrap(); + let from = proto_timestamp_to_time(range.start); + let to = proto_timestamp_to_time(range.end); self.handle.history_db().range(from, to).await } else { @@ -100,19 +104,42 @@ impl HistorySvc for HistoryService { Ok(Response::new(HistoryReply { entries })) } + #[instrument(skip_all, level = Level::INFO)] + async fn add_history( + &self, + request: Request, + ) -> Result, Status> { + let req = request.into_inner(); + let start_req = req.start.expect("is some"); + + let start_response = self + .start_history(start_req.into_request()) + .await? + .into_inner(); + let end_responnse = self + .end_history( + EndHistoryRequest { + id: start_response.id, + exit: req.exit, + duration: req.duration, + } + .into_request(), + ) + .await?; + + Ok(end_responnse) + } + #[instrument(skip_all, level = Level::INFO)] async fn start_history( &self, request: Request, ) -> Result, Status> { + tokio::time::sleep(Duration::from_secs(5)).await; + let req = request.into_inner(); - let timestamp = OffsetDateTime::from_unix_timestamp_nanos(i128::from(req.timestamp)) - .map_err(|_| { - Status::invalid_argument( - "failed to parse timestamp as unix time (expected nanos since epoch)", - ) - })?; + let timestamp = proto_timestamp_to_time(req.timestamp); let h: History = History::daemon() .timestamp(timestamp) @@ -121,7 +148,7 @@ impl HistorySvc for HistoryService { .session(req.session) .hostname(req.hostname) .author(req.author) - .intent(req.intent) + .intent(req.intent.unwrap_or_default()) .build() .into(); @@ -146,16 +173,15 @@ impl HistorySvc for HistoryService { request: Request, ) -> Result, Status> { let req = request.into_inner(); - let id = HistoryId(req.id); + let id = HistoryId::from(req.id); if let Some((_, mut history)) = self.running.remove(&id) { history.exit = req.exit; - history.duration = match req.duration { - 0 => i64::try_from( - (OffsetDateTime::now_utc() - history.timestamp).whole_nanoseconds(), - ) - .expect("failed to convert calculated duration to i64"), - value => i64::try_from(value).expect("failed to get i64 duration"), + history.duration = match proto_duration_to_std(req.duration) { + Duration::ZERO => Duration::from_nanos_u128( + (OffsetDateTime::now_utc() - history.timestamp).whole_nanoseconds() as u128, + ), + value => value, }; self.handle @@ -164,7 +190,11 @@ impl HistorySvc for HistoryService { .await .map_err(|e| Status::internal(format!("failed to write to db: {e:?}")))?; - tracing::info!(id = id.0, duration = history.duration, "end history"); + tracing::info!( + id = id.to_string(), + duration = history.duration.as_nanos(), + "end history" + ); let (record_id, idx) = self .history_store -- cgit v1.3.1