archivist_lib/events/
types.rs1use crate::events::error::EventError;
6use crate::identity::ComponentIdentity;
7use fidl::endpoints::ServerEnd;
8use fidl::prelude::*;
9use fidl_table_validation::ValidFidlTable;
10use moniker::ExtendedMoniker;
11use std::sync::Arc;
12use {
13 fidl_fuchsia_component as fcomponent, fidl_fuchsia_inspect as finspect,
14 fidl_fuchsia_logger as flogger,
15};
16
17#[derive(Clone, Debug, Eq, Ord, PartialEq, PartialOrd)]
20pub enum EventType {
21 LogSinkRequested,
22 InspectSinkRequested,
23}
24
25impl AsRef<str> for EventType {
26 fn as_ref(&self) -> &str {
27 match &self {
28 Self::LogSinkRequested => "log_sink_requested",
29 Self::InspectSinkRequested => "inspect_sink_requested",
30 }
31 }
32}
33
34#[derive(Debug)]
36pub struct Event {
37 pub payload: EventPayload,
39 pub timestamp: zx::BootInstant,
40}
41
42impl Event {
43 pub fn ty(&self) -> EventType {
44 match &self.payload {
45 EventPayload::LogSinkRequested(_) => EventType::LogSinkRequested,
46 EventPayload::InspectSinkRequested(_) => EventType::InspectSinkRequested,
47 }
48 }
49}
50
51#[derive(Debug)]
53pub enum EventPayload {
54 LogSinkRequested(LogSinkRequestedPayload),
55 InspectSinkRequested(InspectSinkRequestedPayload),
56}
57
58pub struct InspectSinkRequestedPayload {
59 pub component: Arc<ComponentIdentity>,
61 pub request_stream: finspect::InspectSinkRequestStream,
63}
64
65impl std::fmt::Debug for InspectSinkRequestedPayload {
66 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
67 f.debug_struct("InspectSinkRequestedPayload").field("component", &self.component).finish()
68 }
69}
70
71pub struct LogSinkRequestedPayload {
73 pub component: Arc<ComponentIdentity>,
75 pub request_stream: flogger::LogSinkRequestStream,
77}
78
79impl std::fmt::Debug for LogSinkRequestedPayload {
80 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
81 f.debug_struct("LogSinkRequestedPayload").field("component", &self.component).finish()
82 }
83}
84
85#[derive(Debug, ValidFidlTable)]
86#[fidl_table_src(fcomponent::EventHeader)]
87#[fidl_table_strict]
88pub struct ValidatedEventHeader {
89 event_type: fcomponent::EventType,
90 component_url: String,
91 moniker: String,
92 timestamp: zx::BootInstant,
93}
94
95#[derive(Debug, ValidFidlTable)]
96#[fidl_table_src(fcomponent::Event)]
97#[fidl_table_strict]
98pub struct ValidatedEvent {
99 pub header: ValidatedEventHeader,
101
102 pub payload: fcomponent::EventPayload,
103}
104
105impl TryFrom<fcomponent::Event> for Event {
106 type Error = EventError;
107
108 fn try_from(event: fcomponent::Event) -> Result<Event, Self::Error> {
109 if let Ok(event) = ValidatedEvent::try_from(event) {
110 let identity = ComponentIdentity::new(
111 ExtendedMoniker::parse_str(&event.header.moniker)?,
112 &event.header.component_url,
113 );
114
115 match event.header.event_type {
116 fcomponent::EventType::CapabilityRequested => match event.payload {
117 fcomponent::EventPayload::CapabilityRequested(capability_requested) => {
118 let name =
119 capability_requested.name.ok_or(EventError::MissingField("name"))?;
120
121 if name == flogger::LogSinkMarker::PROTOCOL_NAME {
122 let capability = capability_requested
123 .capability
124 .ok_or(EventError::MissingField("capability"))?;
125 let request_stream =
126 ServerEnd::<flogger::LogSinkMarker>::new(capability).into_stream();
127 Ok(Event {
128 timestamp: event.header.timestamp,
129 payload: EventPayload::LogSinkRequested(LogSinkRequestedPayload {
130 component: Arc::new(identity),
131 request_stream,
132 }),
133 })
134 } else if name == finspect::InspectSinkMarker::PROTOCOL_NAME {
135 let capability = capability_requested
136 .capability
137 .ok_or(EventError::MissingField("capability"))?;
138 let request_stream =
139 ServerEnd::<finspect::InspectSinkMarker>::new(capability)
140 .into_stream();
141 Ok(Event {
142 timestamp: event.header.timestamp,
143 payload: EventPayload::InspectSinkRequested(
144 InspectSinkRequestedPayload {
145 component: Arc::new(identity),
146 request_stream,
147 },
148 ),
149 })
150 } else {
151 Err(EventError::IncorrectName {
152 received: name,
153 expected: flogger::LogSinkMarker::PROTOCOL_NAME,
154 })
155 }
156 }
157 _ => Err(EventError::UnknownResult(event.payload)),
158 },
159 _ => Err(EventError::InvalidEventType(event.header.event_type)),
160 }
161 } else {
162 Err(EventError::MissingField("Payload or header is missing"))
163 }
164 }
165}
166
167#[cfg(test)]
168mod tests {
169 use super::*;
170 use crate::logs::testing::create_log_sink_requested_event;
171 use assert_matches::assert_matches;
172 use fidl_fuchsia_logger::LogSinkMarker;
173 use {fidl_fuchsia_component as fcomponent, fidl_fuchsia_inspect as finspect};
174
175 fn create_inspect_sink_requested_event(
176 target_moniker: String,
177 target_url: String,
178 capability: zx::Channel,
179 ) -> fcomponent::Event {
180 fcomponent::Event {
181 header: Some(fcomponent::EventHeader {
182 event_type: Some(fcomponent::EventType::CapabilityRequested),
183 moniker: Some(target_moniker),
184 component_url: Some(target_url),
185 timestamp: Some(zx::BootInstant::get()),
186 ..Default::default()
187 }),
188 payload: Some(fcomponent::EventPayload::CapabilityRequested(
189 fcomponent::CapabilityRequestedPayload {
190 name: Some(finspect::InspectSinkMarker::PROTOCOL_NAME.into()),
191 capability: Some(capability),
192 ..Default::default()
193 },
194 )),
195 ..Default::default()
196 }
197 }
198
199 #[fuchsia::test]
200 fn inspect_sink_capability_requested() {
201 let _exec = fuchsia_async::LocalExecutor::new();
202 let (_, inspect_sink_server_end) =
203 fidl::endpoints::create_endpoints::<finspect::InspectSinkMarker>();
204 let event = create_inspect_sink_requested_event(
205 "a/b".into(),
206 "".into(),
207 inspect_sink_server_end.into_channel(),
208 );
209 let actual = event.try_into().unwrap();
210
211 assert_matches!(actual, Event { payload, .. } => {
212 assert_matches!(payload,
213 EventPayload::InspectSinkRequested(InspectSinkRequestedPayload {
214 component, ..
215 }) => {
216 assert_eq!(component, ComponentIdentity::from(vec!["a", "b"]).into());
217 })
218 });
219 }
220
221 #[fuchsia::test]
222 fn log_sink_capability_requested() {
223 let _exec = fuchsia_async::LocalExecutor::new();
224 let (_, log_sink_server_end) = fidl::endpoints::create_endpoints::<LogSinkMarker>();
225 let event = create_log_sink_requested_event(
226 "a/b".into(),
227 "".into(),
228 log_sink_server_end.into_channel(),
229 );
230 let actual = event.try_into().unwrap();
231
232 assert_matches!(actual, Event { payload, .. } => {
233 assert_matches!(payload,
234 EventPayload::LogSinkRequested(LogSinkRequestedPayload {
235 component, ..
236 }) => {
237 assert_eq!(component, ComponentIdentity::from(vec!["a", "b"]).into());
238 })
239 });
240 }
241}