aboutsummaryrefslogtreecommitdiffstats
path: root/crates/daemon/src/control
diff options
context:
space:
mode:
authorBenedikt Peetz <benedikt.peetz@b-peetz.de>2026-07-09 21:43:23 +0200
committerBenedikt Peetz <benedikt.peetz@b-peetz.de>2026-07-09 21:43:23 +0200
commit3223d93cb3c77ab02aa0a35f2a8314e447cee9a4 (patch)
tree3971a1f37f5fe3cadb747c5229a0d54e868e45e3 /crates/daemon/src/control
parentfix(client/sync): Pass through precise error on `SyncError::WrongKey` (diff)
downloadatuin-3223d93cb3c77ab02aa0a35f2a8314e447cee9a4.zip
chore: Separate daemon, client, server, and lib into crates
Diffstat (limited to 'crates/daemon/src/control')
-rw-r--r--crates/daemon/src/control/mod.rs76
1 files changed, 76 insertions, 0 deletions
diff --git a/crates/daemon/src/control/mod.rs b/crates/daemon/src/control/mod.rs
new file mode 100644
index 00000000..79398d61
--- /dev/null
+++ b/crates/daemon/src/control/mod.rs
@@ -0,0 +1,76 @@
+//! Control service implementation.
+//!
+//! This gRPC service allows external processes (like CLI commands) to inject
+//! events into the daemon's event bus.
+
+use tonic::{Request, Response, Status};
+use tracing::{Level, info, instrument};
+
+use crate::{
+ atuin_client::history::HistoryId,
+ atuin_daemon::{
+ daemon::DaemonHandle,
+ events::DaemonEvent,
+ generated::control::{
+ SendEventRequest, SendEventResponse,
+ control_server::{Control, ControlServer},
+ send_event_request::Event,
+ },
+ },
+};
+
+/// The Control gRPC service.
+///
+/// This service is used by external processes to inject events into the daemon.
+/// It's not a component - it's part of the daemon's core infrastructure.
+pub(crate) struct ControlService {
+ handle: DaemonHandle,
+}
+
+impl ControlService {
+ /// Create a new control service with the given daemon handle.
+ pub(crate) fn new(handle: DaemonHandle) -> Self {
+ Self { handle }
+ }
+
+ /// Get a tonic server for this service.
+ pub(crate) fn into_server(self) -> ControlServer<Self> {
+ ControlServer::new(self)
+ }
+}
+
+#[tonic::async_trait]
+impl Control for ControlService {
+ #[instrument(skip_all, level = Level::INFO, name = "control_send_event")]
+ async fn send_event(
+ &self,
+ request: Request<SendEventRequest>,
+ ) -> Result<Response<SendEventResponse>, Status> {
+ let req = request.into_inner();
+
+ let event = req
+ .event
+ .ok_or_else(|| Status::invalid_argument("event is required"))?;
+
+ let daemon_event = proto_event_to_daemon_event(event);
+
+ info!(?daemon_event, "received control event");
+ self.handle.emit(daemon_event);
+
+ Ok(Response::new(SendEventResponse {}))
+ }
+}
+
+/// Convert a proto event to a daemon event.
+fn proto_event_to_daemon_event(event: Event) -> DaemonEvent {
+ match event {
+ Event::HistoryPruned(_) => DaemonEvent::HistoryPruned,
+ Event::HistoryRebuilt(_) => DaemonEvent::HistoryRebuilt,
+ Event::HistoryDeleted(e) => DaemonEvent::HistoryDeleted {
+ ids: e.ids.into_iter().map(HistoryId).collect(),
+ },
+ Event::ForceSync(_) => DaemonEvent::ForceSync,
+ Event::SettingsReloaded(_) => DaemonEvent::SettingsReloaded,
+ Event::Shutdown(_) => DaemonEvent::ShutdownRequested,
+ }
+}