| 859 | } |
| 860 | |
| 861 | async fn get_link_metrics( |
| 862 | &self, |
| 863 | request: Request<api::GetDeviceLinkMetricsRequest>, |
| 864 | ) -> Result<Response<api::GetDeviceLinkMetricsResponse>, Status> { |
| 865 | let req = request.get_ref(); |
| 866 | let dev_eui = EUI64::from_str(&req.dev_eui).map_err(|e| e.status())?; |
| 867 | |
| 868 | self.validator |
| 869 | .validate( |
| 870 | request.extensions(), |
| 871 | validator::ValidateDeviceAccess::new(validator::Flag::Read, dev_eui), |
| 872 | ) |
| 873 | .await?; |
| 874 | |
| 875 | let start = SystemTime::try_from( |
| 876 | *req.start |
| 877 | .as_ref() |
| 878 | .ok_or_else(|| anyhow!("start is None")) |
| 879 | .map_err(|e| e.status())?, |
| 880 | ) |
| 881 | .map_err(|e| e.status())?; |
| 882 | |
| 883 | let end = SystemTime::try_from( |
| 884 | *req.end |
| 885 | .as_ref() |
| 886 | .ok_or_else(|| anyhow!("end is None")) |
| 887 | .map_err(|e| e.status())?, |
| 888 | ) |
| 889 | .map_err(|e| e.status())?; |
| 890 | |
| 891 | let start: DateTime<Local> = start.into(); |
| 892 | let end: DateTime<Local> = end.into(); |
| 893 | let aggregation = req.aggregation().from_proto(); |
| 894 | |
| 895 | let device_metrics = metrics::get( |
| 896 | &format!("device:{}", dev_eui), |
| 897 | metrics::Kind::ABSOLUTE, |
| 898 | aggregation, |
| 899 | start, |
| 900 | end, |
| 901 | ) |
| 902 | .await |
| 903 | .map_err(|e| e.status())?; |
| 904 | |
| 905 | let out = api::GetDeviceLinkMetricsResponse { |
| 906 | rx_packets: Some(common::Metric { |
| 907 | name: "Received".to_string(), |
| 908 | timestamps: device_metrics |
| 909 | .iter() |
| 910 | .map(|row| { |
| 911 | let ts: DateTime<Utc> = row.time.into(); |
| 912 | let ts: pbjson_types::Timestamp = ts.into(); |
| 913 | ts |
| 914 | }) |
| 915 | .collect(), |
| 916 | datasets: vec![common::MetricDataset { |
| 917 | label: "rx_count".to_string(), |
| 918 | data: device_metrics |