Skip to main content

routing/
error_logging_router.rs

1// Copyright 2026 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use crate::error::{ErrorReporter, RouteRequestErrorInfo};
6use async_trait::async_trait;
7use capability_source::CapabilitySource;
8use fidl_fuchsia_component_runtime::RouteRequest;
9use router_error::RouterError;
10use runtime_capabilities::{
11    Capability, CapabilityBound, Connector, Data, Dictionary, DirConnector, Routable, Router,
12    WeakInstanceToken,
13};
14use std::sync::Arc;
15
16pub struct ErrorLoggingRouter<R: ErrorReporter> {
17    inner_router: Capability,
18    route_request: RouteRequestErrorInfo,
19    error_reporter: R,
20    error_location: Arc<WeakInstanceToken>,
21}
22
23impl<R: ErrorReporter> ErrorLoggingRouter<R> {
24    pub fn new(
25        inner_router: Capability,
26        route_request: impl Into<RouteRequestErrorInfo>,
27        error_reporter: R,
28        error_location: Arc<WeakInstanceToken>,
29    ) -> Capability {
30        match &inner_router {
31            Capability::ConnectorRouter(_) => Router::<Connector>::new(Self {
32                inner_router,
33                route_request: route_request.into(),
34                error_reporter,
35                error_location,
36            })
37            .into(),
38            Capability::DirConnectorRouter(_) => Router::<DirConnector>::new(Self {
39                inner_router,
40                route_request: route_request.into(),
41                error_reporter,
42                error_location,
43            })
44            .into(),
45            Capability::DictionaryRouter(_) => Router::<Dictionary>::new(Self {
46                inner_router,
47                route_request: route_request.into(),
48                error_reporter,
49                error_location,
50            })
51            .into(),
52            Capability::DataRouter(_) => Router::<Data>::new(Self {
53                inner_router,
54                route_request: route_request.into(),
55                error_reporter,
56                error_location,
57            })
58            .into(),
59            _ => panic!("non-router type passed to ErrorLoggingRouter"),
60        }
61    }
62}
63
64#[async_trait]
65impl<T: CapabilityBound, R: ErrorReporter> Routable<T> for ErrorLoggingRouter<R>
66where
67    Arc<Router<T>>: TryFrom<Capability>,
68{
69    async fn route(
70        &self,
71        request: RouteRequest,
72        target: Arc<WeakInstanceToken>,
73    ) -> Result<Option<Arc<T>>, RouterError> {
74        let inner_router: Arc<Router<T>> =
75            self.inner_router.clone().try_into().ok().expect("type mismatch");
76        match inner_router.route(request, target).await {
77            Ok(res) => Ok(res),
78            Err(err) => {
79                self.error_reporter
80                    .report(&self.route_request, &err, self.error_location.clone())
81                    .await;
82                Err(err)
83            }
84        }
85    }
86
87    async fn route_debug(
88        &self,
89        request: RouteRequest,
90        target: Arc<WeakInstanceToken>,
91    ) -> Result<CapabilitySource, RouterError> {
92        let inner_router: Arc<Router<T>> =
93            self.inner_router.clone().try_into().ok().expect("type mismatch");
94        match inner_router.route_debug(request, target).await {
95            Ok(res) => Ok(res),
96            Err(err) => {
97                self.error_reporter
98                    .report(&self.route_request, &err, self.error_location.clone())
99                    .await;
100                Err(err)
101            }
102        }
103    }
104}