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};
14
15pub struct ErrorLoggingRouter<R: ErrorReporter> {
16    inner_router: Capability,
17    route_request: RouteRequestErrorInfo,
18    error_reporter: R,
19    error_location: WeakInstanceToken,
20}
21
22impl<R: ErrorReporter> ErrorLoggingRouter<R> {
23    pub fn new(
24        inner_router: Capability,
25        route_request: impl Into<RouteRequestErrorInfo>,
26        error_reporter: R,
27        error_location: WeakInstanceToken,
28    ) -> Capability {
29        match &inner_router {
30            Capability::ConnectorRouter(_) => Router::<Connector>::new(Self {
31                inner_router,
32                route_request: route_request.into(),
33                error_reporter,
34                error_location,
35            })
36            .into(),
37            Capability::DirConnectorRouter(_) => Router::<DirConnector>::new(Self {
38                inner_router,
39                route_request: route_request.into(),
40                error_reporter,
41                error_location,
42            })
43            .into(),
44            Capability::DictionaryRouter(_) => Router::<Dictionary>::new(Self {
45                inner_router,
46                route_request: route_request.into(),
47                error_reporter,
48                error_location,
49            })
50            .into(),
51            Capability::DataRouter(_) => Router::<Data>::new(Self {
52                inner_router,
53                route_request: route_request.into(),
54                error_reporter,
55                error_location,
56            })
57            .into(),
58            _ => panic!("non-router type passed to ErrorLoggingRouter"),
59        }
60    }
61}
62
63#[async_trait]
64impl<T: CapabilityBound, R: ErrorReporter> Routable<T> for ErrorLoggingRouter<R>
65where
66    Router<T>: TryFrom<Capability>,
67{
68    async fn route(
69        &self,
70        request: RouteRequest,
71        target: WeakInstanceToken,
72    ) -> Result<Option<T>, RouterError> {
73        let inner_router: Router<T> =
74            self.inner_router.clone().try_into().ok().expect("type mismatch");
75        match inner_router.route(request, target).await {
76            Ok(res) => Ok(res),
77            Err(err) => {
78                self.error_reporter
79                    .report(&self.route_request, &err, self.error_location.clone())
80                    .await;
81                Err(err)
82            }
83        }
84    }
85
86    async fn route_debug(
87        &self,
88        request: RouteRequest,
89        target: WeakInstanceToken,
90    ) -> Result<CapabilitySource, RouterError> {
91        let inner_router: Router<T> =
92            self.inner_router.clone().try_into().ok().expect("type mismatch");
93        match inner_router.route_debug(request, target).await {
94            Ok(res) => Ok(res),
95            Err(err) => {
96                self.error_reporter
97                    .report(&self.route_request, &err, self.error_location.clone())
98                    .await;
99                Err(err)
100            }
101        }
102    }
103}