diff --git a/chirpstack/src/api/gateway.rs b/chirpstack/src/api/gateway.rs index eb377bdb..be38f181 100644 --- a/chirpstack/src/api/gateway.rs +++ b/chirpstack/src/api/gateway.rs @@ -303,9 +303,15 @@ impl GatewayService for Gateway { .await .map_err(|e| e.status())?; - gateway::update_tls_cert(&gw_id, cert.as_bytes()) - .await - .map_err(|e| e.status())?; + gateway::partial_update( + gw_id, + &gateway::GatewayChangeset { + tls_certificate: Some(Some(cert.as_bytes().to_vec())), + ..Default::default() + }, + ) + .await + .map_err(|e| e.status())?; let mut resp = Response::new(api::GenerateGatewayClientCertificateResponse { ca_cert, diff --git a/chirpstack/src/storage/gateway.rs b/chirpstack/src/storage/gateway.rs index 07c192c0..292c9be8 100644 --- a/chirpstack/src/storage/gateway.rs +++ b/chirpstack/src/storage/gateway.rs @@ -40,6 +40,17 @@ impl Gateway { } } +#[derive(AsChangeset, Debug, Clone, Default)] +#[diesel(table_name = gateway)] +pub struct GatewayChangeset { + pub last_seen_at: Option>>, + pub properties: Option, + pub latitude: Option, + pub longitude: Option, + pub altitude: Option, + pub tls_certificate: Option>>, +} + #[derive(Queryable, PartialEq, Debug)] pub struct GatewayListItem { pub tenant_id: Uuid, @@ -186,66 +197,14 @@ pub async fn update(gw: Gateway) -> Result { Ok(gw) } -pub async fn update_state(id: &EUI64, props: &HashMap) -> Result { - let props = fields::KeyValue::new(props.clone()); - - let gw: Gateway = diesel::update(gateway::dsl::gateway.find(&id)) - .set(( - gateway::last_seen_at.eq(Some(Utc::now())), - gateway::properties.eq(props), - )) - .get_result(&mut get_async_db_conn().await?) +pub async fn partial_update(gateway_id: EUI64, gw: &GatewayChangeset) -> Result { + let gw = diesel::update(gateway::dsl::gateway.find(&gateway_id)) + .set(gw) + .get_result::(&mut get_async_db_conn().await?) .await - .map_err(|e| Error::from_diesel(e, id.to_string()))?; - - info!( - gateway_id = %id, - "Gateway state updated" - ); - - Ok(gw) -} - -pub async fn update_state_and_loc( - id: &EUI64, - lat: f64, - lon: f64, - alt: f32, - props: &HashMap, -) -> Result { - let props = fields::KeyValue::new(props.clone()); - - let gw: Gateway = diesel::update(gateway::dsl::gateway.find(&id)) - .set(( - gateway::last_seen_at.eq(Some(Utc::now())), - gateway::latitude.eq(lat), - gateway::longitude.eq(lon), - gateway::altitude.eq(alt), - gateway::properties.eq(props), - )) - .get_result(&mut get_async_db_conn().await?) - .await - .map_err(|e| Error::from_diesel(e, id.to_string()))?; - - info!( - gateway_id = %id, - "Gateway state and location updated" - ); - - Ok(gw) -} - -pub async fn update_tls_cert(id: &EUI64, cert: &[u8]) -> Result { - let gw: Gateway = diesel::update(gateway::dsl::gateway.find(&id)) - .set(gateway::tls_certificate.eq(cert)) - .get_result(&mut get_async_db_conn().await?) - .await - .map_err(|e| Error::from_diesel(e, id.to_string()))?; - info!( - gateway_id = %id, - "Gateway tls certificate updated" - ); + .map_err(|e| Error::from_diesel(e, gateway_id.to_string()))?; + info!(gateway_id = %gateway_id, "Gateway partially updated"); Ok(gw) } diff --git a/chirpstack/src/uplink/stats.rs b/chirpstack/src/uplink/stats.rs index 39e5efa4..4ddfa32d 100644 --- a/chirpstack/src/uplink/stats.rs +++ b/chirpstack/src/uplink/stats.rs @@ -4,12 +4,12 @@ use std::hash::{Hash, Hasher}; use std::str::FromStr; use anyhow::{Context, Result}; -use chrono::{DateTime, Local}; +use chrono::{DateTime, Local, Utc}; use tracing::{error, info, span, trace, warn, Instrument, Level}; use crate::gateway::backend as gateway_backend; use crate::helpers::errors::PrintFullError; -use crate::storage::{error::Error, gateway, metrics}; +use crate::storage::{error::Error, fields, gateway, metrics}; use crate::{config, region}; use chirpstack_api::{common, gw}; use lrwn::EUI64; @@ -71,26 +71,25 @@ impl Stats { async fn update_gateway_state(&mut self) -> Result<()> { trace!("Update gateway state"); + let mut gw_cs = gateway::GatewayChangeset { + last_seen_at: Some(Some(Utc::now())), + properties: Some(fields::KeyValue::new(self.stats.metadata.clone())), + ..Default::default() + }; + if let Some(loc) = &self.stats.location { - self.gateway = Some( - gateway::update_state_and_loc( - &self.gateway_id, - loc.latitude, - loc.longitude, - loc.altitude as f32, - &self.stats.metadata, - ) - .await - .context("Update gateway state and location")?, - ); - } else { - self.gateway = Some( - gateway::update_state(&self.gateway_id, &self.stats.metadata) - .await - .context("Update gateway state")?, - ); + // Sanity check to make sure there is a location. + if !(loc.latitude == 0.0 && loc.longitude == 0.0 && loc.altitude == 0.0) { + gw_cs.latitude = Some(loc.latitude); + gw_cs.longitude = Some(loc.longitude); + gw_cs.altitude = Some(loc.longitude as f32); + } } + gateway::partial_update(self.gateway_id, &gw_cs) + .await + .context("Update gateway state")?; + Ok(()) }