1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
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,
}
}
|