1use crate::policy::PolicyError;
6use crate::rights::Rights;
7use async_trait::async_trait;
8use clonable_error::ClonableError;
9use cm_rust::offer::OfferDeclCommon;
10use cm_rust::{CapabilityTypeName, ExposeDeclCommon, SourceName, UseDeclCommon};
11use cm_types::{Availability, LongName, Name, RelativePath};
12use fidl_fuchsia_component as fcomponent;
13use fidl_fuchsia_component_decl as fdecl;
14use itertools::Itertools;
15use moniker::{ChildName, ExtendedMoniker, Moniker};
16use router_error::{Explain, RouterError};
17use std::sync::Arc;
18use thiserror::Error;
19use zx_status as zx;
20
21#[cfg(feature = "serde")]
22use serde::{Deserialize, Serialize};
23
24#[cfg_attr(feature = "serde", derive(Deserialize, Serialize), serde(rename_all = "snake_case"))]
26#[derive(Debug, Error, Clone)]
27pub enum ComponentInstanceError {
28 #[error("could not find `{moniker}`")]
29 InstanceNotFound { moniker: Moniker },
30 #[error("component is not executable `{moniker}`")]
31 InstanceNotExecutable { moniker: Moniker },
32 #[error("component manager instance unavailable")]
33 ComponentManagerInstanceUnavailable {},
34 #[error("expected a component instance, but got component manager's instance")]
35 ComponentManagerInstanceUnexpected {},
36 #[error("malformed url `{url}` for `{moniker}`")]
37 MalformedUrl { url: String, moniker: Moniker },
38 #[error("url `{url}` for `{moniker}` does not resolve to an absolute url")]
39 NoAbsoluteUrl { url: String, moniker: Moniker },
40 #[cfg_attr(feature = "serde", serde(skip))]
43 #[error("failed to resolve `{moniker}`:\n\t{err}")]
44 ResolveFailed {
45 moniker: Moniker,
46 #[source]
47 err: ClonableError,
48 },
49 #[cfg_attr(feature = "serde", serde(skip))]
52 #[error("failed to start `{moniker}`:\n\t{err_msg}")]
53 StartFailed {
54 moniker: Moniker,
55 err_msg: String,
59 err_as_zx: zx::Status,
60 },
61 #[error("failed to create storage for `{moniker}`:\n\t{err_msg}")]
62 FailedToCreateStorage { moniker: Moniker, err_msg: String },
63}
64
65impl ComponentInstanceError {
66 pub fn as_zx_status(&self) -> zx::Status {
67 match self {
68 ComponentInstanceError::ResolveFailed { .. }
69 | ComponentInstanceError::InstanceNotFound { .. }
70 | ComponentInstanceError::ComponentManagerInstanceUnavailable {}
71 | ComponentInstanceError::InstanceNotExecutable { .. }
72 | ComponentInstanceError::NoAbsoluteUrl { .. }
73 | ComponentInstanceError::FailedToCreateStorage { .. } => zx::Status::NOT_FOUND,
74 ComponentInstanceError::StartFailed { err_as_zx, .. } => *err_as_zx,
75 ComponentInstanceError::MalformedUrl { .. }
76 | ComponentInstanceError::ComponentManagerInstanceUnexpected { .. } => {
77 zx::Status::INTERNAL
78 }
79 }
80 }
81
82 pub fn instance_not_found(moniker: Moniker) -> ComponentInstanceError {
83 ComponentInstanceError::InstanceNotFound { moniker }
84 }
85
86 pub fn cm_instance_unavailable() -> ComponentInstanceError {
87 ComponentInstanceError::ComponentManagerInstanceUnavailable {}
88 }
89
90 pub fn resolve_failed(moniker: Moniker, err: impl Into<anyhow::Error>) -> Self {
91 Self::ResolveFailed { moniker, err: err.into().into() }
92 }
93}
94
95impl Explain for ComponentInstanceError {
96 fn as_zx_status(&self) -> zx::Status {
97 self.as_zx_status()
98 }
99}
100
101impl From<ComponentInstanceError> for ExtendedMoniker {
102 fn from(err: ComponentInstanceError) -> ExtendedMoniker {
103 match err {
104 ComponentInstanceError::InstanceNotFound { moniker }
105 | ComponentInstanceError::MalformedUrl { moniker, .. }
106 | ComponentInstanceError::NoAbsoluteUrl { moniker, .. }
107 | ComponentInstanceError::InstanceNotExecutable { moniker }
108 | ComponentInstanceError::ResolveFailed { moniker, .. }
109 | ComponentInstanceError::StartFailed { moniker, .. }
110 | ComponentInstanceError::FailedToCreateStorage { moniker, .. } => {
111 ExtendedMoniker::ComponentInstance(moniker)
112 }
113 ComponentInstanceError::ComponentManagerInstanceUnavailable {}
114 | ComponentInstanceError::ComponentManagerInstanceUnexpected {} => {
115 ExtendedMoniker::ComponentManager
116 }
117 }
118 }
119}
120
121impl PartialEq for ComponentInstanceError {
124 fn eq(&self, other: &Self) -> bool {
125 match (self, other) {
126 (
127 Self::InstanceNotFound { moniker: self_moniker },
128 Self::InstanceNotFound { moniker: other_moniker },
129 ) => self_moniker.eq(other_moniker),
130 (
131 Self::ComponentManagerInstanceUnavailable {},
132 Self::ComponentManagerInstanceUnavailable {},
133 ) => true,
134 (Self::ResolveFailed { .. }, Self::ResolveFailed { .. }) => false,
135 _ => false,
136 }
137 }
138}
139
140#[derive(Clone, Copy, Debug, PartialEq)]
141#[cfg_attr(feature = "serde", derive(Deserialize, Serialize), serde(rename_all = "snake_case"))]
142pub enum RouteVerb {
143 Use,
144 Offer,
145 Expose,
146 Declare,
147 Contain,
148 Register,
149 IncludeInAggregate,
150}
151
152impl std::fmt::Display for RouteVerb {
153 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
154 match self {
155 RouteVerb::Use => write!(f, "use"),
156 RouteVerb::Offer => write!(f, "offer"),
157 RouteVerb::Expose => write!(f, "expose"),
158 RouteVerb::Declare => write!(f, "declare"),
159 RouteVerb::Contain => write!(f, "contain"),
160 RouteVerb::Register => write!(f, "register in environment"),
161 RouteVerb::IncludeInAggregate => write!(f, "include in aggregate"),
162 }
163 }
164}
165
166impl From<&cm_rust::ExposeDecl> for RouteVerb {
167 fn from(_decl: &cm_rust::ExposeDecl) -> Self {
168 Self::Expose
169 }
170}
171
172impl From<&cm_rust::OfferDecl> for RouteVerb {
173 fn from(_decl: &cm_rust::OfferDecl) -> Self {
174 Self::Offer
175 }
176}
177
178impl From<&cm_rust::UseDecl> for RouteVerb {
179 fn from(_decl: &cm_rust::UseDecl) -> Self {
180 Self::Use
181 }
182}
183
184impl From<&cm_rust::DebugRegistration> for RouteVerb {
185 fn from(_decl: &cm_rust::DebugRegistration) -> Self {
186 Self::Register
187 }
188}
189
190impl From<&cm_rust::RunnerRegistration> for RouteVerb {
191 fn from(_decl: &cm_rust::RunnerRegistration) -> Self {
192 Self::Register
193 }
194}
195
196impl From<&cm_rust::ResolverRegistration> for RouteVerb {
197 fn from(_decl: &cm_rust::ResolverRegistration) -> Self {
198 Self::Register
199 }
200}
201
202#[derive(Clone, PartialEq, Debug, Error)]
203#[cfg_attr(feature = "serde", derive(Deserialize, Serialize), serde(rename_all = "snake_case"))]
204pub enum PrettyPrintRef {
205 Parent,
206 Self_,
207 Child(Name),
208 ChildInCollection(LongName, Name),
209 Collection(Name),
210 Framework,
211 Capability(Name),
212 Debug,
213 Void,
214 Environment,
215}
216
217impl std::fmt::Display for PrettyPrintRef {
218 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
219 match self {
220 PrettyPrintRef::Parent => write!(f, "parent"),
221 PrettyPrintRef::Self_ => write!(f, "self"),
222 PrettyPrintRef::Child(name) => write!(f, "child {name}"),
223 PrettyPrintRef::ChildInCollection(name, collection) => {
224 write!(f, "child {name} in collection {collection}")
225 }
226 PrettyPrintRef::Collection(name) => write!(f, "collection {name}"),
227 PrettyPrintRef::Framework => write!(f, "framework"),
228 PrettyPrintRef::Capability(name) => write!(f, "capability {name}"),
229 PrettyPrintRef::Debug => write!(f, "debug"),
230 PrettyPrintRef::Void => write!(f, "void"),
231 PrettyPrintRef::Environment => write!(f, "environment"),
232 }
233 }
234}
235
236impl From<fdecl::Ref> for PrettyPrintRef {
237 fn from(ref_: fdecl::Ref) -> Self {
238 match ref_ {
239 fdecl::Ref::Parent(_) => PrettyPrintRef::Parent,
240 fdecl::Ref::Self_(_) => PrettyPrintRef::Self_,
241 fdecl::Ref::Child(child_ref) if child_ref.collection.is_none() => {
242 PrettyPrintRef::Child(Name::new(child_ref.name).unwrap())
243 }
244 fdecl::Ref::Child(child_ref) => PrettyPrintRef::ChildInCollection(
245 LongName::new(child_ref.name).unwrap(),
246 Name::new(child_ref.collection.unwrap()).unwrap(),
247 ),
248 fdecl::Ref::Collection(collection) => {
249 PrettyPrintRef::Collection(Name::new(collection.name).unwrap())
250 }
251 fdecl::Ref::Framework(_) => PrettyPrintRef::Framework,
252 fdecl::Ref::Capability(capability) => {
253 PrettyPrintRef::Capability(Name::new(capability.name).unwrap())
254 }
255 fdecl::Ref::Debug(_) => PrettyPrintRef::Debug,
256 fdecl::Ref::VoidType(_) => PrettyPrintRef::Void,
257 fdecl::Ref::Environment(_) => PrettyPrintRef::Environment,
258 _ => panic!("unexpected fdecl::Ref variant found"),
259 }
260 }
261}
262
263impl From<ChildName> for PrettyPrintRef {
264 fn from(child_name: ChildName) -> Self {
265 if let Some(collection_name) = child_name.collection() {
266 Self::ChildInCollection(child_name.name().to_owned(), collection_name.to_owned())
267 } else {
268 Self::Child(Name::new(child_name.name()).unwrap())
269 }
270 }
271}
272
273#[cfg_attr(feature = "serde", derive(Deserialize, Serialize), serde(rename_all = "snake_case"))]
275#[derive(Debug, Error, Clone, PartialEq)]
276pub enum RoutingError {
277 #[error(
278 "cannot {verb} {capability_type} {capability_name} from {source} at {moniker} because {source} does not {counter_verb} the capability"
279 )]
280 RouteSourceNotFound {
281 moniker: Moniker,
282 verb: RouteVerb,
283 counter_verb: RouteVerb,
284 source: PrettyPrintRef,
285 capability_type: CapabilityTypeName,
286 capability_name: RelativePath,
287 },
288
289 #[error("route request received by `{moniker}` is unexpectedly unset")]
290 RouteRequestUnset { moniker: ExtendedMoniker },
291
292 #[error(
293 "route request received by `{moniker}` has been rejected because the following field is unset: `{missing_field}`"
294 )]
295 RouteRequestMissingField { moniker: ExtendedMoniker, missing_field: String },
296
297 #[error(
298 "failed to parse field `{field}` in route request received by `{moniker}`: {parse_error}"
299 )]
300 RouteRequestFailedToParseField { moniker: ExtendedMoniker, field: String, parse_error: String },
301
302 #[error(
303 "`{target_name:?}` tried to use a storage capability from `{source_moniker}` but it is \
304 not in the component id index. https://fuchsia.dev/go/components/instance-id"
305 )]
306 ComponentNotInIdIndex { source_moniker: Moniker, target_name: Option<ChildName> },
307
308 #[error(
309 "`{moniker}` tried to use {capability_type} `{capability_name}` from the root environment"
310 )]
311 UseFromRootEnvironmentNotAllowed {
312 moniker: Moniker,
313 capability_type: String,
314 capability_name: Name,
315 },
316
317 #[error(
318 "`{moniker}` tried to expose `{capability_id}` from the framework, but no such framework capability was found"
319 )]
320 ExposeFromFrameworkNotFound { moniker: Moniker, capability_id: String },
321
322 #[error("`{capability_id}` was not exposed from `/`")]
323 UseFromRootExposeNotFound { capability_id: String },
324
325 #[error("routing a capability from an unsupported source type `{source_type}` at `{moniker}`")]
326 UnsupportedRouteSource { source_type: String, moniker: ExtendedMoniker },
327
328 #[error("routing a capability of an unsupported type `{type_name}` at `{moniker}`")]
329 UnsupportedCapabilityType { type_name: CapabilityTypeName, moniker: ExtendedMoniker },
330
331 #[error("dynamic dictionaries are not allowed at component `{moniker}`")]
332 DynamicDictionariesNotAllowed { moniker: Moniker },
333
334 #[error("item `{name}` is not present in dictionary at component `{moniker}`")]
335 BedrockNotPresentInDictionary { name: String, moniker: ExtendedMoniker },
336
337 #[error(
338 "routed capability was the wrong type at component `{moniker}`. Was: {actual}, expected: {expected}"
339 )]
340 BedrockWrongCapabilityType { actual: String, expected: String, moniker: ExtendedMoniker },
341
342 #[error("failed to send message for capability `{capability_id}` from component `{moniker}`")]
343 BedrockFailedToSend { moniker: ExtendedMoniker, capability_id: String },
344
345 #[error(
346 "the source of capability `{capability_id}` at component `{moniker}` is unknown because we did not perform any routing tasks to find it"
347 )]
348 SourceUnknown { moniker: ExtendedMoniker, capability_id: String },
349
350 #[error(
351 "failed to route capability because the route source has been shutdown and possibly destroyed"
352 )]
353 RouteSourceShutdown { moniker: Moniker },
354
355 #[error(transparent)]
356 ComponentInstanceError(#[from] ComponentInstanceError),
357
358 #[error(transparent)]
359 EventsRoutingError(#[from] EventsRoutingError),
360
361 #[error(transparent)]
362 RightsRoutingError(#[from] RightsRoutingError),
363
364 #[error(transparent)]
365 AvailabilityRoutingError(#[from] AvailabilityRoutingError),
366
367 #[error(transparent)]
368 PolicyError(#[from] PolicyError),
369
370 #[error(
371 "source capability at component {moniker} is void. \
372 If the offer/expose declaration has `source_availability` set to `unknown`, \
373 the source component instance likely isn't defined in the component declaration"
374 )]
375 SourceCapabilityIsVoid { moniker: ExtendedMoniker },
376
377 #[error(
378 "routes that do not set the `debug` flag are unsupported in the current configuration (at `{moniker}`)."
379 )]
380 NonDebugRoutesUnsupported { moniker: ExtendedMoniker },
381
382 #[error("debug routes are unsupported for external routers (at `{moniker}`).")]
383 DebugRoutesUnsupported { moniker: ExtendedMoniker },
384
385 #[error("{type_name} router unexpectedly returned unavailable for target {moniker}")]
386 RouteUnexpectedUnavailable { type_name: CapabilityTypeName, moniker: ExtendedMoniker },
387
388 #[error("path at `{moniker}` was too long for `{keyword}`: {path}")]
389 PathTooLong { moniker: ExtendedMoniker, path: String, keyword: String },
390
391 #[error(
392 "conflicting dictionary entries detected component `{moniker}`: {}",
393 conflicting_names.iter().map(|n| format!("{}", n)).join(", ")
394 )]
395 ConflictingDictionaryEntries { moniker: ExtendedMoniker, conflicting_names: Vec<Name> },
396
397 #[error("FIDL error encountered while talking to a router implemented by component {moniker}")]
398 RemoteFIDLError { moniker: Moniker },
399
400 #[error("error returned by a router implemented by component {moniker}")]
402 RemoteRouterError { moniker: Moniker, error_code: i32 },
403}
404
405impl Explain for RoutingError {
406 fn as_zx_status(&self) -> zx::Status {
408 match self {
409 RoutingError::UseFromRootEnvironmentNotAllowed { .. }
410 | RoutingError::DynamicDictionariesNotAllowed { .. } => zx::Status::ACCESS_DENIED,
411 RoutingError::RouteRequestMissingField { .. }
412 | RoutingError::RouteRequestFailedToParseField { .. }
413 | RoutingError::RouteRequestUnset { .. }
414 | RoutingError::ComponentNotInIdIndex { .. }
415 | RoutingError::ConflictingDictionaryEntries { .. }
416 | RoutingError::ExposeFromFrameworkNotFound { .. }
417 | RoutingError::UseFromRootExposeNotFound { .. }
418 | RoutingError::UnsupportedRouteSource { .. }
419 | RoutingError::UnsupportedCapabilityType { .. }
420 | RoutingError::EventsRoutingError(_)
421 | RoutingError::BedrockNotPresentInDictionary { .. }
422 | RoutingError::BedrockFailedToSend { .. }
423 | RoutingError::SourceUnknown { .. }
424 | RoutingError::RouteSourceShutdown { .. }
425 | RoutingError::BedrockWrongCapabilityType { .. }
426 | RoutingError::SourceCapabilityIsVoid { .. }
427 | RoutingError::AvailabilityRoutingError(_)
428 | RoutingError::RouteSourceNotFound { .. }
429 | RoutingError::PathTooLong { .. } => zx::Status::NOT_FOUND,
430 RoutingError::NonDebugRoutesUnsupported { .. }
431 | RoutingError::DebugRoutesUnsupported { .. } => zx::Status::NOT_SUPPORTED,
432 RoutingError::ComponentInstanceError(err) => err.as_zx_status(),
433 RoutingError::RightsRoutingError(err) => err.as_zx_status(),
434 RoutingError::PolicyError(err) => err.as_zx_status(),
435 RoutingError::RouteUnexpectedUnavailable { .. } => zx::Status::INTERNAL,
436 RoutingError::RemoteFIDLError { .. } => zx::Status::PEER_CLOSED,
437 RoutingError::RemoteRouterError { error_code, .. } => {
438 zx::Status::err_from_raw(*error_code)
439 }
440 }
441 }
442}
443
444impl From<RoutingError> for ExtendedMoniker {
445 fn from(err: RoutingError) -> ExtendedMoniker {
446 match err {
447 RoutingError::ComponentNotInIdIndex { source_moniker: moniker, .. }
448 | RoutingError::ExposeFromFrameworkNotFound { moniker, .. }
449 | RoutingError::UseFromRootEnvironmentNotAllowed { moniker, .. }
450 | RoutingError::DynamicDictionariesNotAllowed { moniker, .. }
451 | RoutingError::RouteSourceShutdown { moniker }
452 | RoutingError::RemoteFIDLError { moniker }
453 | RoutingError::RouteSourceNotFound { moniker, .. }
454 | RoutingError::RemoteRouterError { moniker, .. } => moniker.into(),
455 RoutingError::PathTooLong { moniker, .. } => moniker,
456
457 RoutingError::BedrockNotPresentInDictionary { moniker, .. }
458 | RoutingError::BedrockFailedToSend { moniker, .. }
459 | RoutingError::SourceUnknown { moniker, .. }
460 | RoutingError::BedrockWrongCapabilityType { moniker, .. }
461 | RoutingError::RouteRequestMissingField { moniker, .. }
462 | RoutingError::RouteRequestFailedToParseField { moniker, .. }
463 | RoutingError::RouteRequestUnset { moniker, .. }
464 | RoutingError::SourceCapabilityIsVoid { moniker, .. }
465 | RoutingError::ConflictingDictionaryEntries { moniker, .. }
466 | RoutingError::NonDebugRoutesUnsupported { moniker }
467 | RoutingError::DebugRoutesUnsupported { moniker }
468 | RoutingError::RouteUnexpectedUnavailable { moniker, .. }
469 | RoutingError::UnsupportedCapabilityType { moniker, .. }
470 | RoutingError::UnsupportedRouteSource { moniker, .. } => moniker,
471 RoutingError::AvailabilityRoutingError(err) => err.into(),
472 RoutingError::ComponentInstanceError(err) => err.into(),
473 RoutingError::EventsRoutingError(err) => err.into(),
474 RoutingError::PolicyError(err) => err.into(),
475 RoutingError::RightsRoutingError(err) => err.into(),
476
477 RoutingError::UseFromRootExposeNotFound { .. } => ExtendedMoniker::ComponentManager,
478 }
479 }
480}
481
482impl From<RoutingError> for RouterError {
483 fn from(value: RoutingError) -> Self {
484 Self::NotFound(Arc::new(value))
485 }
486}
487
488impl TryFrom<RouterError> for RoutingError {
489 type Error = RouterError;
490
491 fn try_from(value: RouterError) -> Result<Self, Self::Error> {
492 match value {
493 RouterError::NotFound(arc_dyn_explain) => {
494 match arc_dyn_explain.as_any().downcast_ref::<Self>() {
495 Some(routing_error) => Ok(routing_error.clone()),
496 None => Err(RouterError::NotFound(arc_dyn_explain)),
497 }
498 }
499 err => Err(err),
500 }
501 }
502}
503
504impl RoutingError {
505 pub fn as_fidl_error(&self) -> fcomponent::Error {
507 fcomponent::Error::ResourceUnavailable
508 }
509
510 pub fn expose_from_framework_not_found(
511 moniker: &Moniker,
512 capability_id: impl Into<String>,
513 ) -> Self {
514 Self::ExposeFromFrameworkNotFound {
515 moniker: moniker.clone(),
516 capability_id: capability_id.into(),
517 }
518 }
519
520 pub fn unsupported_route_source(
521 moniker: impl Into<ExtendedMoniker>,
522 source: impl Into<String>,
523 ) -> Self {
524 Self::UnsupportedRouteSource { source_type: source.into(), moniker: moniker.into() }
525 }
526
527 pub fn unsupported_capability_type(
528 moniker: impl Into<ExtendedMoniker>,
529 type_name: impl Into<CapabilityTypeName>,
530 ) -> Self {
531 Self::UnsupportedCapabilityType { type_name: type_name.into(), moniker: moniker.into() }
532 }
533}
534
535#[cfg_attr(feature = "serde", derive(Deserialize, Serialize), serde(rename_all = "snake_case"))]
537#[derive(Error, Debug, Clone, PartialEq)]
538pub enum EventsRoutingError {
539 #[error("filter is not a subset at `{moniker}`")]
540 InvalidFilter { moniker: ExtendedMoniker },
541
542 #[error("event routes must end at source with a filter declaration at `{moniker}`")]
543 MissingFilter { moniker: ExtendedMoniker },
544}
545
546impl From<EventsRoutingError> for ExtendedMoniker {
547 fn from(err: EventsRoutingError) -> ExtendedMoniker {
548 match err {
549 EventsRoutingError::InvalidFilter { moniker }
550 | EventsRoutingError::MissingFilter { moniker } => moniker,
551 }
552 }
553}
554
555#[cfg_attr(feature = "serde", derive(Deserialize, Serialize), serde(rename_all = "snake_case"))]
556#[derive(Debug, Error, Clone, PartialEq)]
557pub enum RightsRoutingError {
558 #[error(
559 "requested rights ({requested}) greater than provided rights ({provided}) at \"{moniker}\""
560 )]
561 Invalid { moniker: ExtendedMoniker, requested: Rights, provided: Rights },
562
563 #[error(
564 "directory routes must end at source with a rights declaration, it's missing at \"{moniker}\""
565 )]
566 MissingRightsSource { moniker: ExtendedMoniker },
567}
568
569impl RightsRoutingError {
570 pub fn as_zx_status(&self) -> zx::Status {
572 match self {
573 RightsRoutingError::Invalid { .. } => zx::Status::ACCESS_DENIED,
574 RightsRoutingError::MissingRightsSource { .. } => zx::Status::NOT_FOUND,
575 }
576 }
577}
578
579impl From<RightsRoutingError> for ExtendedMoniker {
580 fn from(err: RightsRoutingError) -> ExtendedMoniker {
581 match err {
582 RightsRoutingError::Invalid { moniker, .. }
583 | RightsRoutingError::MissingRightsSource { moniker } => moniker,
584 }
585 }
586}
587
588#[cfg_attr(feature = "serde", derive(Deserialize, Serialize), serde(rename_all = "snake_case"))]
589#[derive(Debug, Error, Clone, PartialEq)]
590pub enum AvailabilityRoutingError {
591 #[error(
592 "availability requested by the target has stronger guarantees than what \
593 is being provided at the source at `{moniker}`"
594 )]
595 TargetHasStrongerAvailability { moniker: ExtendedMoniker },
596
597 #[error("offer uses void source, but target requires the capability at `{moniker}`")]
598 OfferFromVoidToRequiredTarget { moniker: ExtendedMoniker },
599
600 #[error("expose uses void source, but target requires the capability at `{moniker}`")]
601 ExposeFromVoidToRequiredTarget { moniker: ExtendedMoniker },
602}
603
604impl From<availability::TargetHasStrongerAvailability> for AvailabilityRoutingError {
605 fn from(value: availability::TargetHasStrongerAvailability) -> Self {
606 let availability::TargetHasStrongerAvailability { moniker } = value;
607 AvailabilityRoutingError::TargetHasStrongerAvailability { moniker }
608 }
609}
610
611impl From<AvailabilityRoutingError> for ExtendedMoniker {
612 fn from(err: AvailabilityRoutingError) -> ExtendedMoniker {
613 match err {
614 AvailabilityRoutingError::ExposeFromVoidToRequiredTarget { moniker }
615 | AvailabilityRoutingError::OfferFromVoidToRequiredTarget { moniker }
616 | AvailabilityRoutingError::TargetHasStrongerAvailability { moniker } => moniker,
617 }
618 }
619}
620
621#[async_trait]
624pub trait ErrorReporter: Clone + Send + Sync + 'static {
625 async fn report(
626 &self,
627 request: &RouteRequestErrorInfo,
628 err: &RouterError,
629 route_target: Arc<runtime_capabilities::WeakInstanceToken>,
630 );
631}
632
633#[derive(Clone, Debug, PartialEq, Eq)]
635pub struct RouteRequestErrorInfo {
636 capability_type: cm_rust::CapabilityTypeName,
637 name: cm_types::Name,
638 availability: cm_rust::Availability,
639}
640
641impl RouteRequestErrorInfo {
642 pub fn availability(&self) -> cm_rust::Availability {
643 self.availability
644 }
645
646 pub fn name(&self) -> &Name {
647 &self.name
648 }
649
650 pub fn type_name(&self) -> &CapabilityTypeName {
651 &self.capability_type
652 }
653
654 pub fn for_builtin(capability_type: CapabilityTypeName, name: &Name) -> Self {
655 Self { capability_type, name: name.clone(), availability: Availability::Required }
656 }
657}
658
659impl From<&RouteRequestErrorInfo> for runtime_capabilities::RouterErrorInfo {
660 fn from(value: &RouteRequestErrorInfo) -> Self {
661 Self {
662 capability_type: value.capability_type,
663 name: value.name.clone(),
664 availability: value.availability,
665 }
666 }
667}
668
669impl From<runtime_capabilities::RouterErrorInfo> for RouteRequestErrorInfo {
670 fn from(value: runtime_capabilities::RouterErrorInfo) -> Self {
671 Self {
672 capability_type: value.capability_type,
673 name: value.name,
674 availability: value.availability,
675 }
676 }
677}
678
679impl From<&cm_rust::UseDecl> for RouteRequestErrorInfo {
680 fn from(value: &cm_rust::UseDecl) -> Self {
681 RouteRequestErrorInfo {
682 capability_type: value.into(),
683 name: value.source_name().clone(),
684 availability: value.availability().clone(),
685 }
686 }
687}
688
689impl From<&cm_rust::UseConfigurationDecl> for RouteRequestErrorInfo {
690 fn from(value: &cm_rust::UseConfigurationDecl) -> Self {
691 RouteRequestErrorInfo {
692 capability_type: CapabilityTypeName::Config,
693 name: value.source_name().clone(),
694 availability: value.availability().clone(),
695 }
696 }
697}
698
699impl From<&cm_rust::UseEventStreamDecl> for RouteRequestErrorInfo {
700 fn from(value: &cm_rust::UseEventStreamDecl) -> Self {
701 RouteRequestErrorInfo {
702 capability_type: CapabilityTypeName::EventStream,
703 name: value.source_name.clone(),
704 availability: value.availability,
705 }
706 }
707}
708
709impl From<&cm_rust::ExposeDecl> for RouteRequestErrorInfo {
710 fn from(value: &cm_rust::ExposeDecl) -> Self {
711 RouteRequestErrorInfo {
712 capability_type: value.into(),
713 name: value.target_name().clone(),
714 availability: value.availability().clone(),
715 }
716 }
717}
718
719impl From<&cm_rust::offer::OfferDecl> for RouteRequestErrorInfo {
720 fn from(value: &cm_rust::offer::OfferDecl) -> Self {
721 RouteRequestErrorInfo {
722 capability_type: value.into(),
723 name: value.target_name().clone(),
724 availability: value.availability().clone(),
725 }
726 }
727}
728
729impl From<&cm_rust::ResolverRegistration> for RouteRequestErrorInfo {
730 fn from(value: &cm_rust::ResolverRegistration) -> Self {
731 RouteRequestErrorInfo {
732 capability_type: CapabilityTypeName::Resolver,
733 name: value.source_name().clone(),
734 availability: Availability::Required,
735 }
736 }
737}
738
739impl From<&cm_rust::RunnerRegistration> for RouteRequestErrorInfo {
740 fn from(value: &cm_rust::RunnerRegistration) -> Self {
741 RouteRequestErrorInfo {
742 capability_type: CapabilityTypeName::Runner,
743 name: value.source_name().clone(),
744 availability: Availability::Required,
745 }
746 }
747}
748
749impl From<&cm_rust::DebugRegistration> for RouteRequestErrorInfo {
750 fn from(value: &cm_rust::DebugRegistration) -> Self {
751 RouteRequestErrorInfo {
752 capability_type: CapabilityTypeName::Protocol,
753 name: value.source_name().clone(),
754 availability: Availability::Required,
755 }
756 }
757}
758
759impl From<&cm_rust::CapabilityDecl> for RouteRequestErrorInfo {
760 fn from(value: &cm_rust::CapabilityDecl) -> Self {
761 RouteRequestErrorInfo {
762 capability_type: value.into(),
763 name: value.name().clone(),
764 availability: Availability::Required,
765 }
766 }
767}
768
769impl std::fmt::Display for RouteRequestErrorInfo {
770 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
771 write!(f, "{} `{}`", self.capability_type, self.name)
772 }
773}