Update updating gw loc + tls cert.

This refactors the multiple update functions into a single function
accepting a change-set struct. This also adds a sanity check to make
sure we are not updating the gw loc when lat / lon / alt are all set to
0.
This commit is contained in:
Orne Brocaar 2024-03-14 12:20:11 +00:00
parent 8c875c3bf1
commit 0cd5dd8d31
3 changed files with 44 additions and 80 deletions

View File

@ -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,

View File

@ -40,6 +40,17 @@ impl Gateway {
}
}
#[derive(AsChangeset, Debug, Clone, Default)]
#[diesel(table_name = gateway)]
pub struct GatewayChangeset {
pub last_seen_at: Option<Option<DateTime<Utc>>>,
pub properties: Option<fields::KeyValue>,
pub latitude: Option<f64>,
pub longitude: Option<f64>,
pub altitude: Option<f32>,
pub tls_certificate: Option<Option<Vec<u8>>>,
}
#[derive(Queryable, PartialEq, Debug)]
pub struct GatewayListItem {
pub tenant_id: Uuid,
@ -186,66 +197,14 @@ pub async fn update(gw: Gateway) -> Result<Gateway, Error> {
Ok(gw)
}
pub async fn update_state(id: &EUI64, props: &HashMap<String, String>) -> Result<Gateway, Error> {
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<Gateway, Error> {
let gw = diesel::update(gateway::dsl::gateway.find(&gateway_id))
.set(gw)
.get_result::<Gateway>(&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<String, String>,
) -> Result<Gateway, Error> {
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<Gateway, Error> {
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)
}

View File

@ -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(())
}