routers_rpc 0.1.3

gRPC Endpoints for Routers
Documentation
use crate::sdk::r#match::coordinate;
use crate::services::RPCAdapter;
use buffa::MessageField;
use buffa::view::OwnedView;
use connectrpc::{ConnectError, RequestContext, ServiceResult};
use core::cmp::Ordering;
use geo::{Distance, Haversine, Point};
use log::{debug, info};
use routers_network::{Entry, Metadata, Network};
use schema::connect::routers::api::scan::v1::ScanService;
use schema::proto::routers::api::scan::v1::{
    __buffa::view::{EdgeRequestView, PointRequestView, PointSnappedRequestView},
    EdgeResponse, PointResponse, PointSnappedResponse,
};
#[cfg(feature = "telemetry")]
use tracing::Level;

#[allow(refining_impl_trait)]
impl<T, E, M> ScanService for RPCAdapter<T, E, M>
where
    T: Network<E, M> + Send + Sync + 'static,
    M: Metadata + Send + Sync + 'static,
    E: Entry + Send + Sync + 'static,
{
    #[cfg_attr(feature="telemetry", tracing::instrument(skip_all, level = Level::INFO))]
    async fn point(
        &self,
        _ctx: RequestContext,
        request: OwnedView<PointRequestView<'static>>,
    ) -> ServiceResult<PointResponse> {
        let owned = request.to_owned_message();

        let point = owned
            .coordinate
            .as_option()
            .map(|c| Point::new(c.longitude, c.latitude))
            .ok_or_else(|| ConnectError::invalid_argument("Missing Coordinate"))?;

        let nearest = self
            .inner
            .nearest_node(&point)
            .ok_or_else(|| ConnectError::internal("Could not find appropriate point"))?;

        Ok(PointResponse {
            coordinate: MessageField::some(coordinate(nearest.position.into())),
            ..Default::default()
        }
        .into())
    }

    #[cfg_attr(feature="telemetry", tracing::instrument(skip_all, level = Level::INFO))]
    async fn point_snapped(
        &self,
        _ctx: RequestContext,
        request: OwnedView<PointSnappedRequestView<'static>>,
    ) -> ServiceResult<PointSnappedResponse> {
        let owned = request.to_owned_message();

        let point = owned
            .coordinate
            .as_option()
            .map(|c| Point::new(c.longitude, c.latitude))
            .ok_or_else(|| ConnectError::invalid_argument("Missing Point"))?;

        info!(
            "Got request for ({}, {}) within {} square meters",
            point.x(),
            point.y(),
            owned.search_radius
        );

        let mut nearest_points = self
            .inner
            .nearest_nodes_projected(&point, owned.search_radius)
            .collect::<Vec<_>>();

        debug!("Found {} points", nearest_points.len());

        nearest_points.sort_by(|(a, _), (b, _)| {
            let dist_a = Haversine.distance(point, *a);
            let dist_b = Haversine.distance(point, *b);
            dist_a.partial_cmp(&dist_b).unwrap_or(Ordering::Equal)
        });

        let nearest = nearest_points
            .first()
            .ok_or_else(|| ConnectError::internal("Could not find appropriate point"))?;

        Ok(PointSnappedResponse {
            coordinate: MessageField::some(coordinate(nearest.0.0)),
            ..Default::default()
        }
        .into())
    }

    #[cfg_attr(feature="telemetry", tracing::instrument(skip_all, level = Level::INFO))]
    async fn edge(
        &self,
        _ctx: RequestContext,
        _request: OwnedView<EdgeRequestView<'static>>,
    ) -> ServiceResult<EdgeResponse> {
        Err(ConnectError::unimplemented("edge lookup not implemented"))
    }
}