diff options
| author | Benedikt Peetz <benedikt.peetz@b-peetz.de> | 2026-06-11 00:54:30 +0200 |
|---|---|---|
| committer | Benedikt Peetz <benedikt.peetz@b-peetz.de> | 2026-06-11 00:54:30 +0200 |
| commit | 5c39e7cf284a1f6e9a1657f2deb44e359fc47eb8 (patch) | |
| tree | c64baa8d5866c8e339eaf660dd3f94f30a3f7d8a /crates/atuin-daemon | |
| parent | chore: Somewhat simplify sync code (diff) | |
| download | atuin-5c39e7cf284a1f6e9a1657f2deb44e359fc47eb8.zip | |
chore: Move everything into one big crate
That helps remove duplicated code and rustc/cargo will now also show
dead code correctly.
Diffstat (limited to '')
| -rw-r--r-- | crates/atuin-daemon/Cargo.toml | 52 | ||||
| -rw-r--r-- | crates/atuin-daemon/build.rs | 25 | ||||
| -rw-r--r-- | crates/atuin-daemon/tests/lifecycle.rs | 222 | ||||
| -rw-r--r-- | crates/turtle/proto/control.proto (renamed from crates/atuin-daemon/proto/control.proto) | 0 | ||||
| -rw-r--r-- | crates/turtle/proto/history.proto (renamed from crates/atuin-daemon/proto/history.proto) | 0 | ||||
| -rw-r--r-- | crates/turtle/proto/search.proto (renamed from crates/atuin-daemon/proto/search.proto) | 0 | ||||
| -rw-r--r-- | crates/turtle/proto/semantic.proto (renamed from crates/atuin-daemon/proto/semantic.proto) | 0 | ||||
| -rw-r--r-- | crates/turtle/src/atuin_daemon/client.rs (renamed from crates/atuin-daemon/src/client.rs) | 126 | ||||
| -rw-r--r-- | crates/turtle/src/atuin_daemon/components/history.rs (renamed from crates/atuin-daemon/src/components/history.rs) | 4 | ||||
| -rw-r--r-- | crates/turtle/src/atuin_daemon/components/mod.rs (renamed from crates/atuin-daemon/src/components/mod.rs) | 0 | ||||
| -rw-r--r-- | crates/turtle/src/atuin_daemon/components/search.rs (renamed from crates/atuin-daemon/src/components/search.rs) | 6 | ||||
| -rw-r--r-- | crates/turtle/src/atuin_daemon/components/semantic.rs (renamed from crates/atuin-daemon/src/components/semantic.rs) | 29 | ||||
| -rw-r--r-- | crates/turtle/src/atuin_daemon/components/sync.rs (renamed from crates/atuin-daemon/src/components/sync.rs) | 4 | ||||
| -rw-r--r-- | crates/turtle/src/atuin_daemon/control/mod.rs (renamed from crates/atuin-daemon/src/control/mod.rs) | 0 | ||||
| -rw-r--r-- | crates/turtle/src/atuin_daemon/control/service.rs (renamed from crates/atuin-daemon/src/control/service.rs) | 4 | ||||
| -rw-r--r-- | crates/turtle/src/atuin_daemon/daemon.rs (renamed from crates/atuin-daemon/src/daemon.rs) | 4 | ||||
| -rw-r--r-- | crates/turtle/src/atuin_daemon/events.rs (renamed from crates/atuin-daemon/src/events.rs) | 4 | ||||
| -rw-r--r-- | crates/turtle/src/atuin_daemon/history/mod.rs (renamed from crates/atuin-daemon/src/history/mod.rs) | 0 | ||||
| -rw-r--r-- | crates/turtle/src/atuin_daemon/mod.rs (renamed from crates/atuin-daemon/src/lib.rs) | 14 | ||||
| -rw-r--r-- | crates/turtle/src/atuin_daemon/search/index.rs (renamed from crates/atuin-daemon/src/search/index.rs) | 13 | ||||
| -rw-r--r-- | crates/turtle/src/atuin_daemon/search/mod.rs (renamed from crates/atuin-daemon/src/search/mod.rs) | 0 | ||||
| -rw-r--r-- | crates/turtle/src/atuin_daemon/semantic/mod.rs (renamed from crates/atuin-daemon/src/semantic/mod.rs) | 0 | ||||
| -rw-r--r-- | crates/turtle/src/atuin_daemon/server.rs (renamed from crates/atuin-daemon/src/server.rs) | 75 |
23 files changed, 62 insertions, 520 deletions
diff --git a/crates/atuin-daemon/Cargo.toml b/crates/atuin-daemon/Cargo.toml deleted file mode 100644 index e767d3c9..00000000 --- a/crates/atuin-daemon/Cargo.toml +++ /dev/null @@ -1,52 +0,0 @@ -[package] -name = "atuin-daemon" -edition = "2024" -version = { workspace = true } -description = "The daemon crate for Atuin" - -authors.workspace = true -rust-version.workspace = true -license.workspace = true -homepage.workspace = true -repository.workspace = true -readme.workspace = true - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[dependencies] -atuin-client = { path = "../atuin-client", version = "18.16.1" } -atuin-common = { path = "../atuin-common", version = "18.16.1" } -atuin-history = { path = "../atuin-history", version = "18.16.1" } - -time = { workspace = true } -uuid = { workspace = true } -tokio = { workspace = true } -tower = { workspace = true } -eyre = { workspace = true } -tracing = { workspace = true } -tracing-subscriber = { workspace = true } - -dashmap = "6.1.0" -lasso = { version = "0.7", features = ["multi-threaded"] } -tonic-types = "0.14" -tonic = "0.14" -tonic-prost = "0.14" -prost = "0.14" -prost-types = "0.14" -tokio-stream = { version = "0.1.14", features = ["net"] } -hyper-util = "0.1" - -rand.workspace = true -atuin-nucleo = { workspace = true } - - -[target.'cfg(target_os = "linux")'.dependencies] -listenfd = "1.0.1" - -[dev-dependencies] -tempfile = { workspace = true } - -[build-dependencies] -protox = "0.9" -tonic-build = "0.14" -tonic-prost-build = "0.14" diff --git a/crates/atuin-daemon/build.rs b/crates/atuin-daemon/build.rs deleted file mode 100644 index 7808a07b..00000000 --- a/crates/atuin-daemon/build.rs +++ /dev/null @@ -1,25 +0,0 @@ -use std::{env, fs, path::PathBuf}; - -use protox::prost::Message; - -fn main() -> std::io::Result<()> { - let proto_paths = [ - "proto/history.proto", - "proto/search.proto", - "proto/control.proto", - "proto/semantic.proto", - ]; - let proto_include_dirs = ["proto"]; - - let file_descriptors = protox::compile(proto_paths, proto_include_dirs).unwrap(); - - let file_descriptor_path = PathBuf::from(env::var_os("OUT_DIR").expect("OUT_DIR not set")) - .join("file_descriptor_set.bin"); - fs::write(&file_descriptor_path, file_descriptors.encode_to_vec()).unwrap(); - - tonic_prost_build::configure() - .build_server(true) - .file_descriptor_set_path(&file_descriptor_path) - .skip_protoc_run() - .compile_protos(&proto_paths, &proto_include_dirs) -} diff --git a/crates/atuin-daemon/tests/lifecycle.rs b/crates/atuin-daemon/tests/lifecycle.rs deleted file mode 100644 index 4a91e5cb..00000000 --- a/crates/atuin-daemon/tests/lifecycle.rs +++ /dev/null @@ -1,222 +0,0 @@ -//! Integration tests for the daemon server lifecycle. -//! -//! Each test spins up a real gRPC server on a temporary unix socket, -//! connects a client, and exercises the daemon RPCs. - -#[cfg(unix)] -mod unix { - use std::time::Duration; - - use atuin_client::database::Sqlite; - use atuin_client::record::sqlite_store::SqliteStore; - use atuin_client::settings::{Settings, init_meta_config_for_testing}; - use atuin_daemon::client::HistoryClient; - use atuin_daemon::components::HistoryComponent; - use atuin_daemon::{Daemon, DaemonHandle}; - use tempfile::TempDir; - use tokio::net::UnixListener; - use tokio_stream::wrappers::UnixListenerStream; - use tonic::transport::Server; - - /// Spins up a daemon server on a temp socket and returns a connected client, - /// the daemon handle (for shutdown), and the temp dir (must be held to keep paths alive). - async fn start_test_daemon() -> (HistoryClient, DaemonHandle, TempDir) { - let tmp = tempfile::tempdir().unwrap(); - - let db_path = tmp.path().join("history.db"); - let record_path = tmp.path().join("records.db"); - let key_path = tmp.path().join("key"); - let socket_path = tmp.path().join("test.sock"); - let meta_path = tmp.path().join("meta.db"); - - // Initialize the meta store config for testing (required for Settings::host_id()) - init_meta_config_for_testing(meta_path.to_str().unwrap(), 5.0); - - // Build settings with test paths - let settings: Settings = Settings::builder() - .expect("could not build settings builder") - .set_override("db_path", db_path.to_str().unwrap()) - .expect("failed to set db_path") - .set_override("record_store_path", record_path.to_str().unwrap()) - .expect("failed to set record_store_path") - .set_override("key_path", key_path.to_str().unwrap()) - .expect("failed to set key_path") - .set_override("daemon.socket_path", socket_path.to_str().unwrap()) - .expect("failed to set socket_path") - .set_override("meta.db_path", meta_path.to_str().unwrap()) - .expect("failed to set meta.db_path") - .build() - .expect("could not build settings") - .try_deserialize() - .expect("could not deserialize settings"); - - // Create databases - let history_db = Sqlite::new(&db_path, 5.0).await.unwrap(); - let store = SqliteStore::new(&record_path, 5.0).await.unwrap(); - - // Create the history component and get its gRPC service - let history_component = HistoryComponent::new(); - let history_service = history_component.grpc_service(); - - // Build and start the daemon - let mut daemon = Daemon::builder(settings) - .store(store) - .history_db(history_db) - .component(history_component) - .build() - .await - .unwrap(); - - let handle = daemon.handle(); - - // Start components (this initializes the history component with the handle) - daemon.start_components().await.unwrap(); - - // Start the gRPC server - let uds = UnixListener::bind(&socket_path).unwrap(); - let stream = UnixListenerStream::new(uds); - - let server_handle = handle.clone(); - tokio::spawn(async move { - let mut rx = server_handle.subscribe(); - Server::builder() - .add_service(history_service) - .serve_with_incoming_shutdown(stream, async move { - loop { - match rx.recv().await { - Ok(atuin_daemon::DaemonEvent::ShutdownRequested) => break, - Ok(_) => continue, - Err(_) => break, - } - } - }) - .await - .unwrap(); - }); - - // Spawn the daemon event loop in the background - tokio::spawn(async move { - daemon.run_event_loop().await.unwrap(); - }); - - // Give the server a moment to bind. - tokio::time::sleep(Duration::from_millis(50)).await; - - let client = HistoryClient::new(socket_path.to_string_lossy().to_string()) - .await - .unwrap(); - - (client, handle, tmp) - } - - #[tokio::test] - async fn test_status() { - let (mut client, _handle, _tmp) = start_test_daemon().await; - - let status = client.status().await.unwrap(); - assert!(status.healthy); - assert_eq!(status.version, env!("CARGO_PKG_VERSION")); - assert_eq!(status.protocol, 1); - assert!(status.pid > 0); - } - - #[tokio::test] - async fn test_start_end_history() { - use atuin_client::history::History; - - let (mut client, _handle, _tmp) = start_test_daemon().await; - - let history = History::daemon() - .timestamp(time::OffsetDateTime::now_utc()) - .command("echo hello".to_string()) - .cwd("/tmp".to_string()) - .session("test-session".to_string()) - .hostname("test-host".to_string()) - .build() - .into(); - - let start_reply = client.start_history(history).await.unwrap(); - assert!(!start_reply.id.is_empty()); - - let end_reply = client - .end_history(start_reply.id, 1_000_000, 0) - .await - .unwrap(); - assert!(!end_reply.id.is_empty()); - } - - #[tokio::test] - async fn test_tail_history_streams_started_and_ended_events() { - use atuin_client::history::History; - use atuin_daemon::history::HistoryEventKind; - - let (mut client, _handle, _tmp) = start_test_daemon().await; - let mut stream = client.tail_history().await.unwrap(); - - let history = History::daemon() - .timestamp(time::OffsetDateTime::now_utc()) - .command("git status".to_string()) - .cwd("/tmp/repo".to_string()) - .session("tail-session".to_string()) - .hostname("test-host:ellie".to_string()) - .author("claude".to_string()) - .intent("inspect repository state".to_string()) - .build() - .into(); - - let start_reply = client.start_history(history).await.unwrap(); - - let started = stream.message().await.unwrap().unwrap(); - assert_eq!( - HistoryEventKind::try_from(started.kind).unwrap(), - HistoryEventKind::Started - ); - let started_history = started.history.unwrap(); - assert_eq!(started_history.id, start_reply.id); - assert_eq!(started_history.command, "git status"); - assert_eq!(started_history.cwd, "/tmp/repo"); - assert_eq!(started_history.hostname, "test-host:ellie"); - assert_eq!(started_history.author, "claude"); - assert_eq!(started_history.intent, "inspect repository state"); - - client - .end_history(start_reply.id.clone(), 1_000_000, 0) - .await - .unwrap(); - - let ended = stream.message().await.unwrap().unwrap(); - assert_eq!( - HistoryEventKind::try_from(ended.kind).unwrap(), - HistoryEventKind::Ended - ); - let ended_history = ended.history.unwrap(); - assert_eq!(ended_history.id, start_reply.id); - assert_eq!(ended_history.exit, 0); - assert_eq!(ended_history.duration, 1_000_000); - } - - #[tokio::test] - async fn test_end_unknown_history_fails() { - let (mut client, _handle, _tmp) = start_test_daemon().await; - - let result = client - .end_history("nonexistent-id".to_string(), 1000, 0) - .await; - assert!(result.is_err()); - } - - #[tokio::test] - async fn test_shutdown() { - let (mut client, _handle, _tmp) = start_test_daemon().await; - - let accepted = client.shutdown().await.unwrap(); - assert!(accepted); - - // Give server time to shut down. - tokio::time::sleep(Duration::from_millis(100)).await; - - // Subsequent calls should fail since the server is gone. - let result = client.status().await; - assert!(result.is_err()); - } -} diff --git a/crates/atuin-daemon/proto/control.proto b/crates/turtle/proto/control.proto index 06347902..06347902 100644 --- a/crates/atuin-daemon/proto/control.proto +++ b/crates/turtle/proto/control.proto diff --git a/crates/atuin-daemon/proto/history.proto b/crates/turtle/proto/history.proto index 59c12471..59c12471 100644 --- a/crates/atuin-daemon/proto/history.proto +++ b/crates/turtle/proto/history.proto diff --git a/crates/atuin-daemon/proto/search.proto b/crates/turtle/proto/search.proto index 6b84acbd..6b84acbd 100644 --- a/crates/atuin-daemon/proto/search.proto +++ b/crates/turtle/proto/search.proto diff --git a/crates/atuin-daemon/proto/semantic.proto b/crates/turtle/proto/semantic.proto index 07e550c8..07e550c8 100644 --- a/crates/atuin-daemon/proto/semantic.proto +++ b/crates/turtle/proto/semantic.proto diff --git a/crates/atuin-daemon/src/client.rs b/crates/turtle/src/atuin_daemon/client.rs index c18e0e46..45ef19e9 100644 --- a/crates/atuin-daemon/src/client.rs +++ b/crates/turtle/src/atuin_daemon/client.rs @@ -1,8 +1,6 @@ -use atuin_client::database::Context; -use atuin_client::settings::{FilterMode, Settings}; +use crate::atuin_client::database::Context; +use crate::atuin_client::settings::{FilterMode, Settings}; use eyre::{Context as EyreContext, Result}; -#[cfg(windows)] -use tokio::net::TcpStream; use tonic::Code; use tonic::transport::{Channel, Endpoint, Uri}; use tower::service_fn; @@ -12,25 +10,25 @@ use hyper_util::rt::TokioIo; #[cfg(unix)] use tokio::net::UnixStream; -use atuin_client::history::History; +use crate::atuin_client::history::History; use tracing::{Level, instrument, span}; -use crate::control::HistoryRebuiltEvent; -use crate::control::{ +use crate::atuin_daemon::control::HistoryRebuiltEvent; +use crate::atuin_daemon::control::{ ForceSyncEvent, HistoryDeletedEvent, HistoryPrunedEvent, SendEventRequest, SettingsReloadedEvent, ShutdownEvent, control_client::ControlClient as ControlServiceClient, }; -use crate::events::DaemonEvent; -use crate::history::{ +use crate::atuin_daemon::events::DaemonEvent; +use crate::atuin_daemon::history::{ EndHistoryReply, EndHistoryRequest, ShutdownRequest, StartHistoryReply, StartHistoryRequest, StatusReply, StatusRequest, TailHistoryReply, TailHistoryRequest, history_client::HistoryClient as HistoryServiceClient, }; -use crate::search::{ +use crate::atuin_daemon::search::{ FilterMode as RpcFilterMode, SearchContext as RpcSearchContext, SearchRequest, SearchResponse, search_client::SearchClient as SearchServiceClient, }; -use crate::semantic::{ +use crate::atuin_daemon::semantic::{ CommandCapture, CommandOutputReply, CommandOutputRequest, OutputRange, RecordCommandsReply, semantic_client::SemanticClient as SemanticServiceClient, }; @@ -94,28 +92,6 @@ impl HistoryClient { Ok(HistoryClient { client }) } - #[cfg(not(unix))] - pub async fn new(port: u64) -> Result<Self> { - let channel = Endpoint::try_from("http://atuin_local_daemon:0")? - .connect_with_connector(service_fn(move |_: Uri| { - let url = format!("127.0.0.1:{port}"); - - async move { - Ok::<_, std::io::Error>(TokioIo::new(TcpStream::connect(url.clone()).await?)) - } - })) - .await - .wrap_err_with(|| { - format!( - "failed to connect to local atuin daemon at 127.0.0.1:{port}. Is it running?" - ) - })?; - - let client = HistoryServiceClient::new(channel); - - Ok(HistoryClient { client }) - } - pub async fn start_history(&mut self, h: History) -> Result<StartHistoryReply> { let req = StartHistoryRequest { command: h.command, @@ -188,28 +164,6 @@ impl SearchClient { Ok(SearchClient { client }) } - #[cfg(not(unix))] - pub async fn new(port: u64) -> Result<Self> { - let channel = Endpoint::try_from("http://atuin_local_daemon:0")? - .connect_with_connector(service_fn(move |_: Uri| { - let url = format!("127.0.0.1:{port}"); - - async move { - Ok::<_, std::io::Error>(TokioIo::new(TcpStream::connect(url.clone()).await?)) - } - })) - .await - .wrap_err_with(|| { - format!( - "failed to connect to local atuin daemon at 127.0.0.1:{port}. Is it running?" - ) - })?; - - let client = SearchServiceClient::new(channel); - - Ok(SearchClient { client }) - } - #[instrument(skip_all, level = Level::TRACE, name = "daemon_client_search", fields(query = %query, query_id = query_id))] pub async fn search( &mut self, @@ -289,38 +243,11 @@ impl SemanticClient { Ok(SemanticClient { client }) } - #[cfg(not(unix))] - pub async fn new(port: u64) -> Result<Self> { - let channel = Endpoint::try_from("http://atuin_local_daemon:0")? - .connect_with_connector(service_fn(move |_: Uri| { - let url = format!("127.0.0.1:{port}"); - - async move { - Ok::<_, std::io::Error>(TokioIo::new(TcpStream::connect(url.clone()).await?)) - } - })) - .await - .wrap_err_with(|| { - format!( - "failed to connect to local atuin daemon at 127.0.0.1:{port}. Is it running?" - ) - })?; - - let client = SemanticServiceClient::new(channel); - - Ok(SemanticClient { client }) - } - #[cfg(unix)] pub async fn from_settings(settings: &Settings) -> Result<Self> { Self::new(settings.daemon.socket_path.clone()).await } - #[cfg(not(unix))] - pub async fn from_settings(settings: &Settings) -> Result<Self> { - Self::new(settings.daemon.tcp_port).await - } - pub async fn record_commands( &mut self, captures: Vec<CommandCapture>, @@ -383,41 +310,12 @@ impl ControlClient { Ok(ControlClient { client }) } - /// Connect to the daemon's control service. - #[cfg(not(unix))] - pub async fn new(port: u64) -> Result<Self> { - let channel = Endpoint::try_from("http://atuin_local_daemon:0")? - .connect_with_connector(service_fn(move |_: Uri| { - let url = format!("127.0.0.1:{port}"); - - async move { - Ok::<_, std::io::Error>(TokioIo::new(TcpStream::connect(url.clone()).await?)) - } - })) - .await - .wrap_err_with(|| { - format!( - "failed to connect to local atuin daemon at 127.0.0.1:{port}. Is it running?" - ) - })?; - - let client = ControlServiceClient::new(channel); - - Ok(ControlClient { client }) - } - /// Connect using settings. #[cfg(unix)] pub async fn from_settings(settings: &Settings) -> Result<Self> { Self::new(settings.daemon.socket_path.clone()).await } - /// Connect using settings. - #[cfg(not(unix))] - pub async fn from_settings(settings: &Settings) -> Result<Self> { - Self::new(settings.daemon.tcp_port).await - } - /// Send an event to the daemon. pub async fn send_event(&mut self, event: DaemonEvent) -> Result<()> { let proto_event = daemon_event_to_proto(event); @@ -430,8 +328,10 @@ impl ControlClient { } /// Convert a daemon event to its proto representation. -fn daemon_event_to_proto(event: DaemonEvent) -> crate::control::send_event_request::Event { - use crate::control::send_event_request::Event; +fn daemon_event_to_proto( + event: DaemonEvent, +) -> crate::atuin_daemon::control::send_event_request::Event { + use crate::atuin_daemon::control::send_event_request::Event; match event { DaemonEvent::HistoryPruned => Event::HistoryPruned(HistoryPrunedEvent {}), diff --git a/crates/atuin-daemon/src/components/history.rs b/crates/turtle/src/atuin_daemon/components/history.rs index c82c8f94..95d34b69 100644 --- a/crates/atuin-daemon/src/components/history.rs +++ b/crates/turtle/src/atuin_daemon/components/history.rs @@ -4,7 +4,7 @@ use std::{pin::Pin, sync::Arc}; -use atuin_client::{ +use crate::atuin_client::{ database::Database, history::{History, HistoryId, store::HistoryStore}, settings::Settings, @@ -16,7 +16,7 @@ use tokio_stream::Stream; use tonic::{Request, Response, Status}; use tracing::{Level, instrument}; -use crate::{ +use crate::atuin_daemon::{ daemon::{Component, DaemonHandle}, events::DaemonEvent, history::{ diff --git a/crates/atuin-daemon/src/components/mod.rs b/crates/turtle/src/atuin_daemon/components/mod.rs index 447e31df..447e31df 100644 --- a/crates/atuin-daemon/src/components/mod.rs +++ b/crates/turtle/src/atuin_daemon/components/mod.rs diff --git a/crates/atuin-daemon/src/components/search.rs b/crates/turtle/src/atuin_daemon/components/search.rs index 9fc87fae..85191cff 100644 --- a/crates/atuin-daemon/src/components/search.rs +++ b/crates/turtle/src/atuin_daemon/components/search.rs @@ -5,7 +5,7 @@ use std::{pin::Pin, sync::Arc}; -use atuin_client::database::Database; +use crate::atuin_client::database::Database; use eyre::Result; use tokio::sync::RwLock; use tokio_stream::Stream; @@ -13,7 +13,7 @@ use tonic::{Request, Response, Status, Streaming}; use tracing::{Level, debug, info, instrument, span, trace}; use uuid::Uuid; -use crate::{ +use crate::atuin_daemon::{ daemon::{Component, DaemonHandle}, events::DaemonEvent, search::{ @@ -368,7 +368,7 @@ impl SearchSvc for SearchGrpcService { /// Convert proto FilterMode and context to IndexFilterMode. fn convert_filter_mode( mode: FilterMode, - context: &Option<crate::search::SearchContext>, + context: &Option<crate::atuin_daemon::search::SearchContext>, ) -> IndexFilterMode { match (mode, context) { (FilterMode::Global, _) => IndexFilterMode::Global, diff --git a/crates/atuin-daemon/src/components/semantic.rs b/crates/turtle/src/atuin_daemon/components/semantic.rs index dff38fd3..a42fd5cb 100644 --- a/crates/atuin-daemon/src/components/semantic.rs +++ b/crates/turtle/src/atuin_daemon/components/semantic.rs @@ -8,13 +8,13 @@ use std::collections::{HashMap, VecDeque}; use std::fmt::{Display, Formatter}; use std::sync::Arc; -use atuin_client::history::{History, HistoryId}; +use crate::atuin_client::history::{History, HistoryId}; use eyre::Result; use tokio::sync::Mutex; use tonic::{Request, Response, Status, Streaming}; use tracing::{Level, instrument}; -use crate::{ +use crate::atuin_daemon::{ daemon::{Component, DaemonHandle}, events::DaemonEvent, semantic::{ @@ -244,7 +244,7 @@ impl SemanticState { fn command_output_for_ref( &self, capture_ref: &CaptureRef, - ranges: &[crate::semantic::OutputRange], + ranges: &[crate::atuin_daemon::semantic::OutputRange], ) -> Option<CommandOutputReply> { let stored = self .sessions @@ -534,14 +534,17 @@ fn command_output_not_found() -> CommandOutputReply { } } -fn select_output_ranges(output: &str, ranges: &[crate::semantic::OutputRange]) -> Vec<OutputLine> { +fn select_output_ranges( + output: &str, + ranges: &[crate::atuin_daemon::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::semantic::OutputRange { start: 0, end: 999 }] + vec![crate::atuin_daemon::semantic::OutputRange { start: 0, end: 999 }] } else { ranges.to_vec() }; @@ -816,8 +819,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::semantic::OutputRange { start: 1, end: 2 }, - crate::semantic::OutputRange { start: -2, end: -1 }, + crate::atuin_daemon::semantic::OutputRange { start: 1, end: 2 }, + crate::atuin_daemon::semantic::OutputRange { start: -2, end: -1 }, ]; assert_eq!( @@ -838,8 +841,8 @@ mod tests { .collect::<Vec<_>>() .join("\n"); let ranges = vec![ - crate::semantic::OutputRange { start: 0, end: 100 }, - crate::semantic::OutputRange { + crate::atuin_daemon::semantic::OutputRange { start: 0, end: 100 }, + crate::atuin_daemon::semantic::OutputRange { start: -100, end: -1, }, @@ -856,8 +859,8 @@ mod tests { fn output_ranges_can_leave_gaps_for_client_formatting() { let output = "zero\none\ntwo\nthree\nfour"; let ranges = vec![ - crate::semantic::OutputRange { start: 0, end: 1 }, - crate::semantic::OutputRange { start: 4, end: 4 }, + crate::atuin_daemon::semantic::OutputRange { start: 0, end: 1 }, + crate::atuin_daemon::semantic::OutputRange { start: 4, end: 4 }, ]; assert_eq!( @@ -888,8 +891,8 @@ mod tests { fn output_ranges_skip_ranges_fully_outside_output() { let output = "zero\none\ntwo"; let ranges = vec![ - crate::semantic::OutputRange { start: 10, end: 20 }, - crate::semantic::OutputRange { + crate::atuin_daemon::semantic::OutputRange { start: 10, end: 20 }, + crate::atuin_daemon::semantic::OutputRange { start: -20, end: -10, }, diff --git a/crates/atuin-daemon/src/components/sync.rs b/crates/turtle/src/atuin_daemon/components/sync.rs index 6e486250..c76fb71b 100644 --- a/crates/atuin-daemon/src/components/sync.rs +++ b/crates/turtle/src/atuin_daemon/components/sync.rs @@ -9,9 +9,9 @@ use rand::Rng; use tokio::sync::mpsc; use tokio::time::{self, MissedTickBehavior}; -use atuin_client::{history::store::HistoryStore, record::sync, settings::Settings}; +use crate::atuin_client::{history::store::HistoryStore, record::sync, settings::Settings}; -use crate::{ +use crate::atuin_daemon::{ daemon::{Component, DaemonHandle}, events::DaemonEvent, }; diff --git a/crates/atuin-daemon/src/control/mod.rs b/crates/turtle/src/atuin_daemon/control/mod.rs index afb29c57..afb29c57 100644 --- a/crates/atuin-daemon/src/control/mod.rs +++ b/crates/turtle/src/atuin_daemon/control/mod.rs diff --git a/crates/atuin-daemon/src/control/service.rs b/crates/turtle/src/atuin_daemon/control/service.rs index 2e7403ce..cb2ff74e 100644 --- a/crates/atuin-daemon/src/control/service.rs +++ b/crates/turtle/src/atuin_daemon/control/service.rs @@ -3,7 +3,7 @@ //! This gRPC service allows external processes (like CLI commands) to inject //! events into the daemon's event bus. -use atuin_client::history::HistoryId; +use crate::atuin_client::history::HistoryId; use tonic::{Request, Response, Status}; use tracing::{Level, info, instrument}; @@ -12,7 +12,7 @@ use super::{ control_server::{Control, ControlServer}, send_event_request::Event, }; -use crate::{daemon::DaemonHandle, events::DaemonEvent}; +use crate::atuin_daemon::{daemon::DaemonHandle, events::DaemonEvent}; /// The Control gRPC service. /// diff --git a/crates/atuin-daemon/src/daemon.rs b/crates/turtle/src/atuin_daemon/daemon.rs index 625ca205..77c0d8a5 100644 --- a/crates/atuin-daemon/src/daemon.rs +++ b/crates/turtle/src/atuin_daemon/daemon.rs @@ -10,14 +10,14 @@ use std::sync::Arc; -use atuin_client::{ +use crate::atuin_client::{ database::Sqlite as HistoryDatabase, encryption, record::sqlite_store::SqliteStore, settings::Settings, }; use eyre::{Context, Result}; use tokio::sync::{RwLock, broadcast}; -use crate::events::DaemonEvent; +use crate::atuin_daemon::events::DaemonEvent; // ============================================================================ // DaemonState diff --git a/crates/atuin-daemon/src/events.rs b/crates/turtle/src/atuin_daemon/events.rs index 4e6c6ff3..9a398925 100644 --- a/crates/atuin-daemon/src/events.rs +++ b/crates/turtle/src/atuin_daemon/events.rs @@ -7,8 +7,8 @@ //! External processes (like CLI commands) can also inject events via the //! Control gRPC service. -use atuin_client::history::{History, HistoryId}; -use atuin_common::record::RecordId; +use crate::atuin_client::history::{History, HistoryId}; +use crate::atuin_common::record::RecordId; /// Events that flow through the daemon's event bus. /// diff --git a/crates/atuin-daemon/src/history/mod.rs b/crates/turtle/src/atuin_daemon/history/mod.rs index b71853df..b71853df 100644 --- a/crates/atuin-daemon/src/history/mod.rs +++ b/crates/turtle/src/atuin_daemon/history/mod.rs diff --git a/crates/atuin-daemon/src/lib.rs b/crates/turtle/src/atuin_daemon/mod.rs index 27d3932b..b05eb95c 100644 --- a/crates/atuin-daemon/src/lib.rs +++ b/crates/turtle/src/atuin_daemon/mod.rs @@ -1,6 +1,6 @@ -use atuin_client::database::Sqlite as HistoryDatabase; -use atuin_client::record::sqlite_store::SqliteStore; -use atuin_client::settings::{Settings, watcher::global_settings_watcher}; +use crate::atuin_client::database::Sqlite as HistoryDatabase; +use crate::atuin_client::record::sqlite_store::SqliteStore; +use crate::atuin_client::settings::{Settings, watcher::global_settings_watcher}; use eyre::Result; pub mod client; @@ -126,11 +126,3 @@ async fn shutdown_signal() { _ = int.recv() => {}, } } - -/// Wait for a shutdown signal (Ctrl+C). -#[cfg(not(unix))] -async fn shutdown_signal() { - tokio::signal::ctrl_c() - .await - .expect("failed to listen for ctrl+c"); -} diff --git a/crates/atuin-daemon/src/search/index.rs b/crates/turtle/src/atuin_daemon/search/index.rs index bb155979..df627e1b 100644 --- a/crates/atuin-daemon/src/search/index.rs +++ b/crates/turtle/src/atuin_daemon/search/index.rs @@ -12,8 +12,11 @@ use std::{ sync::Arc, }; -use atuin_client::history::{History, is_known_agent}; -use atuin_client::settings::Search; +use crate::atuin_client::settings::Search; +use crate::{ + atuin_client::history::{History, is_known_agent}, + atuin_daemon::components::search::with_trailing_slash, +}; use atuin_nucleo::{Injector, Nucleo, pattern}; use dashmap::DashMap; use lasso::{Spur, ThreadedRodeo}; @@ -22,8 +25,6 @@ use tokio::sync::RwLock; use tracing::{Level, instrument}; use uuid::Uuid; -use crate::components::search::with_trailing_slash; - /// Parse a UUID string into a 16-byte array. /// Returns None if the string is not a valid UUID. fn parse_uuid_bytes(s: &str) -> Option<[u8; 16]> { @@ -491,7 +492,7 @@ mod tests { #[test] fn frecency_data_compute() { - let now = 1000000i64; + let now = 1_000_000i64; // Recent command (with default multipliers of 1.0) let recent = FrecencyData { @@ -518,7 +519,7 @@ mod tests { #[test] fn frecency_data_compute_with_multipliers() { - let now = 1000000i64; + let now = 1_000_000_i64; let data = FrecencyData { count: 5, diff --git a/crates/atuin-daemon/src/search/mod.rs b/crates/turtle/src/atuin_daemon/search/mod.rs index 4d261956..4d261956 100644 --- a/crates/atuin-daemon/src/search/mod.rs +++ b/crates/turtle/src/atuin_daemon/search/mod.rs diff --git a/crates/atuin-daemon/src/semantic/mod.rs b/crates/turtle/src/atuin_daemon/semantic/mod.rs index c3511676..c3511676 100644 --- a/crates/atuin-daemon/src/semantic/mod.rs +++ b/crates/turtle/src/atuin_daemon/semantic/mod.rs diff --git a/crates/atuin-daemon/src/server.rs b/crates/turtle/src/atuin_daemon/server.rs index b823cff2..23b04342 100644 --- a/crates/atuin-daemon/src/server.rs +++ b/crates/turtle/src/atuin_daemon/server.rs @@ -1,15 +1,15 @@ use eyre::Result; -use crate::components::history::HistoryGrpcService; -use crate::components::search::SearchGrpcService; -use crate::components::semantic::SemanticGrpcService; -use crate::control::{ControlService, control_server::ControlServer}; -use crate::daemon::DaemonHandle; -use crate::history::history_server::HistoryServer; -use crate::search::search_server::SearchServer; -use crate::semantic::semantic_server::SemanticServer; +use crate::atuin_daemon::components::history::HistoryGrpcService; +use crate::atuin_daemon::components::search::SearchGrpcService; +use crate::atuin_daemon::components::semantic::SemanticGrpcService; +use crate::atuin_daemon::control::{ControlService, control_server::ControlServer}; +use crate::atuin_daemon::daemon::DaemonHandle; +use crate::atuin_daemon::history::history_server::HistoryServer; +use crate::atuin_daemon::search::search_server::SearchServer; +use crate::atuin_daemon::semantic::semantic_server::SemanticServer; -use atuin_client::settings::Settings; +use crate::atuin_client::settings::Settings; /// Run the gRPC server with the given services. /// @@ -65,8 +65,6 @@ pub async fn run_grpc_server( } (UnixListener::from_std(listener)?, false) } - #[cfg(not(target_os = "linux"))] - unreachable!() } else { tracing::info!("listening on unix socket {socket_path:?}"); (UnixListener::bind(socket_path.clone())?, true) @@ -78,7 +76,7 @@ pub async fn run_grpc_server( let shutdown_signal = async move { let mut rx = handle.subscribe(); loop { - use crate::DaemonEvent; + use crate::atuin_daemon::DaemonEvent; match rx.recv().await { Ok(DaemonEvent::ShutdownRequested) => break, @@ -115,56 +113,3 @@ pub async fn run_grpc_server( Ok(()) } - -/// Run the gRPC server with the given services (Windows/TCP version). -#[cfg(not(unix))] -pub async fn run_grpc_server( - settings: Settings, - history_service: HistoryServer<HistoryGrpcService>, - search_service: SearchServer<SearchGrpcService>, - semantic_service: SemanticServer<SemanticGrpcService>, - control_service: ControlServer<ControlService>, - handle: DaemonHandle, -) -> Result<()> { - use tokio::net::TcpListener; - use tokio_stream::wrappers::TcpListenerStream; - use tonic::transport::Server; - - let port = settings.daemon.tcp_port; - let url = format!("127.0.0.1:{port}"); - let tcp = TcpListener::bind(&url).await?; - let tcp_stream = TcpListenerStream::new(tcp); - - tracing::info!("listening on tcp port {:?}", port); - - // Create shutdown signal from daemon handle - let shutdown_signal = async move { - use crate::DaemonEvent; - - let mut rx = handle.subscribe(); - loop { - match rx.recv().await { - Ok(DaemonEvent::ShutdownRequested) => break, - Ok(_) => continue, - Err(_) => break, // Channel closed - } - } - eprintln!("Shutting down gRPC server..."); - }; - - // Spawn the server in the background - tokio::spawn(async move { - if let Err(e) = Server::builder() - .add_service(history_service) - .add_service(search_service) - .add_service(semantic_service) - .add_service(control_service) - .serve_with_incoming_shutdown(tcp_stream, shutdown_signal) - .await - { - tracing::error!("gRPC server error: {e}"); - } - }); - - Ok(()) -} |
