aboutsummaryrefslogtreecommitdiffstats
path: root/crates/turtle/src/atuin_daemon/components
diff options
context:
space:
mode:
authorBenedikt Peetz <benedikt.peetz@b-peetz.de>2026-06-13 00:50:54 +0200
committerBenedikt Peetz <benedikt.peetz@b-peetz.de>2026-06-13 00:50:54 +0200
commit6723829a3398b3c9dd6dc6ae79124f46000606ee (patch)
treea1ec535eddd711a4557e4bcc5b94382c3623504c /crates/turtle/src/atuin_daemon/components
parentchore(treewide): Cleanup themes (diff)
downloadatuin-6723829a3398b3c9dd6dc6ae79124f46000606ee.zip
chore(treewide): Remove `cargo` warnings to 0
There are still the `clippy` warnings, but they are for a future date.
Diffstat (limited to 'crates/turtle/src/atuin_daemon/components')
-rw-r--r--crates/turtle/src/atuin_daemon/components/history.rs21
-rw-r--r--crates/turtle/src/atuin_daemon/components/search.rs13
-rw-r--r--crates/turtle/src/atuin_daemon/components/semantic.rs41
-rw-r--r--crates/turtle/src/atuin_daemon/components/sync.rs37
4 files changed, 63 insertions, 49 deletions
diff --git a/crates/turtle/src/atuin_daemon/components/history.rs b/crates/turtle/src/atuin_daemon/components/history.rs
index b71543c1..b4f91b06 100644
--- a/crates/turtle/src/atuin_daemon/components/history.rs
+++ b/crates/turtle/src/atuin_daemon/components/history.rs
@@ -18,7 +18,7 @@ use tracing::{Level, instrument};
use crate::atuin_daemon::{
daemon::{Component, DaemonHandle},
events::DaemonEvent,
- history::{
+ generated::history::{
EndHistoryReply, EndHistoryRequest, HistoryEntry, HistoryEventKind, ShutdownReply,
ShutdownRequest, StartHistoryReply, StartHistoryRequest, StatusReply, StatusRequest,
TailHistoryReply, TailHistoryRequest,
@@ -144,8 +144,8 @@ impl HistorySvc for HistoryGrpcService {
) -> Result<Response<StartHistoryReply>, Status> {
let req = request.into_inner();
- let timestamp =
- OffsetDateTime::from_unix_timestamp_nanos(req.timestamp as i128).map_err(|_| {
+ 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)",
)
@@ -181,6 +181,7 @@ impl HistorySvc for HistoryGrpcService {
}
#[instrument(skip_all, level = Level::INFO)]
+ #[expect(clippy::significant_drop_tightening, reason = "Would be a logic-bug")]
async fn end_history(
&self,
request: Request<EndHistoryRequest>,
@@ -216,11 +217,7 @@ impl HistorySvc for HistoryGrpcService {
.await
.map_err(|e| Status::internal(format!("failed to write to db: {e:?}")))?;
- tracing::info!(
- id = id.0.to_string(),
- duration = history.duration,
- "end history"
- );
+ tracing::info!(id = id.0, duration = history.duration, "end history");
// Push to record store
let (record_id, idx) = history_store
@@ -247,6 +244,7 @@ impl HistorySvc for HistoryGrpcService {
}
#[instrument(skip_all, level = Level::INFO)]
+ #[expect(clippy::significant_drop_tightening, reason = "Would be a logic-bug")]
async fn tail_history(
&self,
_request: Request<TailHistoryRequest>,
@@ -265,11 +263,12 @@ impl HistorySvc for HistoryGrpcService {
let event = match rx.recv().await {
Ok(event) => event,
Err(tokio::sync::broadcast::error::RecvError::Lagged(skipped)) => {
- let _ = tx
- .send(Err(Status::resource_exhausted(format!(
+ drop(
+ tx.send(Err(Status::resource_exhausted(format!(
"tail stream lagged behind and dropped {skipped} events"
))))
- .await;
+ .await,
+ );
break;
}
Err(tokio::sync::broadcast::error::RecvError::Closed) => break,
diff --git a/crates/turtle/src/atuin_daemon/components/search.rs b/crates/turtle/src/atuin_daemon/components/search.rs
index 832d05d8..39df758b 100644
--- a/crates/turtle/src/atuin_daemon/components/search.rs
+++ b/crates/turtle/src/atuin_daemon/components/search.rs
@@ -15,10 +15,11 @@ use uuid::Uuid;
use crate::atuin_daemon::{
daemon::{Component, DaemonHandle},
events::DaemonEvent,
- search::{
- FilterMode, IndexFilterMode, QueryContext, SearchIndex, SearchRequest, SearchResponse,
+ generated::search::{
+ self, FilterMode, SearchRequest, SearchResponse,
search_server::{Search as SearchSvc, SearchServer},
},
+ search::{IndexFilterMode, QueryContext, SearchIndex},
};
const PAGE_SIZE: usize = 5000;
@@ -35,7 +36,7 @@ const FRECENCY_REFRESH_INTERVAL_SECS: u64 = 60;
/// - Provides the Search gRPC service
pub(crate) struct SearchComponent {
index: Arc<RwLock<SearchIndex>>,
- handle: tokio::sync::RwLock<Option<DaemonHandle>>,
+ handle: RwLock<Option<DaemonHandle>>,
loader_handle: Option<tokio::task::JoinHandle<()>>,
frecency_handle: Option<tokio::task::JoinHandle<()>>,
}
@@ -45,7 +46,7 @@ impl SearchComponent {
pub(crate) fn new() -> Self {
Self {
index: Arc::new(RwLock::new(SearchIndex::new())),
- handle: tokio::sync::RwLock::new(None),
+ handle: RwLock::new(None),
loader_handle: None,
frecency_handle: None,
}
@@ -351,7 +352,7 @@ impl SearchSvc for SearchGrpcService {
}
}
Err(e) => {
- let _ = tx.send(Err(e)).await;
+ drop(tx.send(Err(e)).await);
break;
}
}
@@ -367,7 +368,7 @@ impl SearchSvc for SearchGrpcService {
/// Convert proto FilterMode and context to IndexFilterMode.
fn convert_filter_mode(
mode: FilterMode,
- context: &Option<crate::atuin_daemon::search::SearchContext>,
+ context: &Option<search::SearchContext>,
) -> IndexFilterMode {
match (mode, context) {
(FilterMode::Global, _) => IndexFilterMode::Global,
diff --git a/crates/turtle/src/atuin_daemon/components/semantic.rs b/crates/turtle/src/atuin_daemon/components/semantic.rs
index 052c2d73..69ffc134 100644
--- a/crates/turtle/src/atuin_daemon/components/semantic.rs
+++ b/crates/turtle/src/atuin_daemon/components/semantic.rs
@@ -9,6 +9,7 @@ use std::fmt::{Display, Formatter};
use std::sync::Arc;
use crate::atuin_client::history::{History, HistoryId};
+use crate::atuin_daemon::generated::semantic;
use eyre::Result;
use tokio::sync::Mutex;
use tonic::{Request, Response, Status, Streaming};
@@ -17,7 +18,7 @@ use tracing::{Level, instrument};
use crate::atuin_daemon::{
daemon::{Component, DaemonHandle},
events::DaemonEvent,
- semantic::{
+ generated::semantic::{
CommandCapture, CommandOutputReply, CommandOutputRequest, OutputLine, RecordCommandsReply,
semantic_server::{Semantic as SemanticSvc, SemanticServer},
},
@@ -244,7 +245,7 @@ impl SemanticState {
fn command_output_for_ref(
&self,
capture_ref: &CaptureRef,
- ranges: &[crate::atuin_daemon::semantic::OutputRange],
+ ranges: &[semantic::OutputRange],
) -> Option<CommandOutputReply> {
let stored = self
.sessions
@@ -534,17 +535,14 @@ fn command_output_not_found() -> CommandOutputReply {
}
}
-fn select_output_ranges(
- output: &str,
- ranges: &[crate::atuin_daemon::semantic::OutputRange],
-) -> Vec<OutputLine> {
+fn select_output_ranges(output: &str, ranges: &[semantic::OutputRange]) -> Vec<OutputLine> {
let lines: Vec<&str> = output.lines().collect();
if lines.is_empty() {
return Vec::new();
}
let ranges = if ranges.is_empty() {
- vec![crate::atuin_daemon::semantic::OutputRange { start: 0, end: 999 }]
+ vec![semantic::OutputRange { start: 0, end: 999 }]
} else {
ranges.to_vec()
};
@@ -627,9 +625,20 @@ fn log_record(record: &SemanticCommandRecord, message: &'static str) {
#[cfg(test)]
mod tests {
- use super::*;
use time::OffsetDateTime;
+ use crate::{
+ atuin_client::history::{History, HistoryId},
+ atuin_daemon::{
+ components::semantic::{
+ MAX_COMMANDS_PER_SESSION, MAX_SESSIONS, SemanticCommandRecord, SemanticState,
+ SessionCaptures, SessionId, select_output_ranges,
+ },
+ generated::semantic::{self, CommandOutputReply, CommandOutputRequest, OutputLine},
+ },
+ atuin_pty_proxy::CommandCapture,
+ };
+
fn history(id: &str, session: &str, command: &str) -> History {
History {
id: HistoryId(id.to_string()),
@@ -819,8 +828,8 @@ mod tests {
fn output_ranges_are_line_based_inclusive_and_support_negative_offsets() {
let output = "zero\none\ntwo\nthree\nfour";
let ranges = vec![
- crate::atuin_daemon::semantic::OutputRange { start: 1, end: 2 },
- crate::atuin_daemon::semantic::OutputRange { start: -2, end: -1 },
+ semantic::OutputRange { start: 1, end: 2 },
+ semantic::OutputRange { start: -2, end: -1 },
];
assert_eq!(
@@ -841,8 +850,8 @@ mod tests {
.collect::<Vec<_>>()
.join("\n");
let ranges = vec![
- crate::atuin_daemon::semantic::OutputRange { start: 0, end: 100 },
- crate::atuin_daemon::semantic::OutputRange {
+ semantic::OutputRange { start: 0, end: 100 },
+ semantic::OutputRange {
start: -100,
end: -1,
},
@@ -859,8 +868,8 @@ mod tests {
fn output_ranges_can_leave_gaps_for_client_formatting() {
let output = "zero\none\ntwo\nthree\nfour";
let ranges = vec![
- crate::atuin_daemon::semantic::OutputRange { start: 0, end: 1 },
- crate::atuin_daemon::semantic::OutputRange { start: 4, end: 4 },
+ semantic::OutputRange { start: 0, end: 1 },
+ semantic::OutputRange { start: 4, end: 4 },
];
assert_eq!(
@@ -891,8 +900,8 @@ mod tests {
fn output_ranges_skip_ranges_fully_outside_output() {
let output = "zero\none\ntwo";
let ranges = vec![
- crate::atuin_daemon::semantic::OutputRange { start: 10, end: 20 },
- crate::atuin_daemon::semantic::OutputRange {
+ semantic::OutputRange { start: 10, end: 20 },
+ semantic::OutputRange {
start: -20,
end: -10,
},
diff --git a/crates/turtle/src/atuin_daemon/components/sync.rs b/crates/turtle/src/atuin_daemon/components/sync.rs
index fbfbbd67..8b5b621d 100644
--- a/crates/turtle/src/atuin_daemon/components/sync.rs
+++ b/crates/turtle/src/atuin_daemon/components/sync.rs
@@ -27,9 +27,9 @@ enum SyncCommand {
/// Sync state - tracks whether we're in normal operation or retrying after failure.
#[derive(Clone, Copy, PartialEq, Eq)]
enum SyncState {
- /// Normal operation. Periodic syncs only run if auto_sync is enabled.
+ /// Normal operation. Periodic syncs only run if [`auto_sync`] is enabled.
Idle,
- /// Retrying after a sync failure. Retries continue regardless of auto_sync
+ /// Retrying after a sync failure. Retries continue regardless of [`auto_sync`]
/// until the sync succeeds.
Retrying,
}
@@ -39,7 +39,7 @@ enum SyncState {
/// This component:
/// - Runs a background sync loop on a configurable interval
/// - Implements exponential backoff on sync failures
-/// - Responds to ForceSync events for immediate sync
+/// - Responds to [`ForceSync`] events for immediate sync
/// - Emits SyncCompleted/SyncFailed events
pub(crate) struct SyncComponent {
task_handle: Option<tokio::task::JoinHandle<()>>,
@@ -80,22 +80,28 @@ impl Component for SyncComponent {
}
async fn handle_event(&mut self, event: &DaemonEvent) -> Result<()> {
- if let DaemonEvent::ForceSync = event {
- tracing::info!("force sync requested");
- if let Some(tx) = &self.command_tx {
- let _ = tx.send(SyncCommand::ForceSync).await;
+ match event {
+ DaemonEvent::ForceSync => {
+ tracing::info!("force sync requested");
+ if let Some(tx) = &self.command_tx {
+ drop(tx.send(SyncCommand::ForceSync).await);
+ }
+ }
+ DaemonEvent::SyncFailed { error } => {
+ tracing::error!(?error, "Sync failed.");
}
+ _ => (),
}
Ok(())
}
async fn stop(&mut self) -> Result<()> {
if let Some(tx) = &self.command_tx {
- let _ = tx.send(SyncCommand::Stop).await;
+ drop(tx.send(SyncCommand::Stop).await);
}
if let Some(handle) = self.task_handle.take() {
// Give the task a moment to shut down gracefully
- let _ = tokio::time::timeout(std::time::Duration::from_secs(5), handle).await;
+ drop(time::timeout(Duration::from_secs(5), handle).await);
}
tracing::info!("sync component stopped");
Ok(())
@@ -126,7 +132,7 @@ async fn sync_loop(handle: DaemonHandle, mut cmd_rx: mpsc::Receiver<SyncCommand>
// Don't backoff by more than 30 mins (with a random jitter of up to 1 min)
let max_interval: f64 = 60.0 * 30.0 + rand::thread_rng().gen_range(0.0..60.0);
- let mut ticker = time::interval(time::Duration::from_secs(settings.daemon.sync_frequency));
+ let mut ticker = time::interval(Duration::from_secs(settings.daemon.sync_frequency));
// IMPORTANT: without this, if we miss ticks because a sync takes ages or is otherwise delayed,
// we may end up running a lot of syncs in a hot loop.
@@ -224,10 +230,10 @@ async fn do_sync_tick(
}
*ticker = time::interval_at(
- tokio::time::Instant::now() + Duration::from_secs(new_interval as u64),
- time::Duration::from_secs(new_interval as u64),
+ time::Instant::now() + Duration::from_secs(new_interval as u64),
+ Duration::from_secs(new_interval as u64),
);
- ticker.reset_after(time::Duration::from_secs(new_interval as u64));
+ ticker.reset_after(Duration::from_secs(new_interval as u64));
ticker.set_missed_tick_behavior(MissedTickBehavior::Skip);
tracing::error!("backing off, next sync tick in {new_interval}");
@@ -261,9 +267,8 @@ async fn do_sync_tick(
// Reset backoff on success
if ticker.period().as_secs() != settings.daemon.sync_frequency {
*ticker = time::interval_at(
- tokio::time::Instant::now()
- + Duration::from_secs(settings.daemon.sync_frequency),
- time::Duration::from_secs(settings.daemon.sync_frequency),
+ time::Instant::now() + Duration::from_secs(settings.daemon.sync_frequency),
+ Duration::from_secs(settings.daemon.sync_frequency),
);
ticker.set_missed_tick_behavior(MissedTickBehavior::Skip);
}