1- use crate :: region_map;
1+ use crate :: { gateway :: db :: Gateway , region_map} ;
22use anyhow:: anyhow;
3- use futures:: stream:: BoxStream ;
3+ use chrono:: { DateTime , Utc } ;
4+ use futures:: { stream:: BoxStream , Stream , StreamExt } ;
45use helium_crypto:: PublicKeyBinary ;
56use helium_proto:: {
67 services:: iot_config:: {
78 GatewayInfo as GatewayInfoProto , GatewayMetadata as GatewayMetadataProto ,
89 } ,
910 Region ,
1011} ;
12+ use sqlx:: PgExecutor ;
1113
1214pub type GatewayInfoStream = BoxStream < ' static , GatewayInfo > ;
1315
16+ // Hotspot gain default; dbi * 10
17+ const DEFAULT_GAIN : u32 = 12 ;
18+ // Hotspot elevation default; meters above sea level
19+ const DEFAULT_ELEVATION : u32 = 0 ;
20+
21+ pub async fn get (
22+ db : impl PgExecutor < ' _ > ,
23+ address : & PublicKeyBinary ,
24+ ) -> anyhow:: Result < Option < IotMetadata > > {
25+ let gateway = Gateway :: get_by_address ( db, address) . await ?;
26+ Ok ( gateway. map ( IotMetadata :: from) )
27+ }
28+
29+ pub fn stream < ' a > (
30+ db : impl PgExecutor < ' a > + ' a ,
31+ min_last_changed_at : DateTime < Utc > ,
32+ min_location_changed_at : Option < DateTime < Utc > > ,
33+ ) -> impl Stream < Item = IotMetadata > + ' a {
34+ let stream = Gateway :: stream ( db, min_last_changed_at, min_location_changed_at) ;
35+ stream. map ( IotMetadata :: from) . boxed ( )
36+ }
37+
1438#[ derive( Clone , Debug ) ]
1539pub struct GatewayMetadata {
1640 pub location : u64 ,
@@ -26,9 +50,17 @@ pub struct GatewayInfo {
2650 pub is_full_hotspot : bool ,
2751}
2852
53+ pub struct IotMetadata {
54+ pub address : PublicKeyBinary ,
55+ pub location : Option < u64 > ,
56+ pub elevation : i32 ,
57+ pub gain : i32 ,
58+ pub is_full_hotspot : bool ,
59+ }
60+
2961impl GatewayInfo {
3062 pub fn chain_metadata_to_info (
31- meta : db :: IotMetadata ,
63+ meta : IotMetadata ,
3264 region_map : & region_map:: RegionMapReader ,
3365 ) -> Self {
3466 let metadata = if let Some ( location) = meta. location {
@@ -112,69 +144,14 @@ impl TryFrom<GatewayInfo> for GatewayInfoProto {
112144 }
113145}
114146
115- pub ( crate ) mod db {
116- use futures:: stream:: { Stream , StreamExt } ;
117- use helium_crypto:: PublicKeyBinary ;
118- use sqlx:: { PgExecutor , Row } ;
119- use std:: str:: FromStr ;
120-
121- // Hotspot gain default; dbi * 10
122- const DEFAULT_GAIN : i32 = 12 ;
123- // Hotspot elevation default; meters above sea level
124- const DEFAULT_ELEVATION : i32 = 0 ;
125-
126- pub struct IotMetadata {
127- pub address : PublicKeyBinary ,
128- pub location : Option < u64 > ,
129- pub elevation : i32 ,
130- pub gain : i32 ,
131- pub is_full_hotspot : bool ,
132- }
133-
134- const GET_METADATA_SQL : & str = r#"
135- select kta.entity_key, infos.location::bigint, CAST(infos.elevation AS integer), CAST(infos.gain as integer), infos.is_full_hotspot
136- from iot_hotspot_infos infos
137- join key_to_assets kta on infos.asset = kta.asset
138- "# ;
139-
140- pub async fn get_info (
141- db : impl PgExecutor < ' _ > ,
142- address : & PublicKeyBinary ,
143- ) -> anyhow:: Result < Option < IotMetadata > > {
144- let entity_key = bs58:: decode ( address. to_string ( ) ) . into_vec ( ) ?;
145- let mut query: sqlx:: QueryBuilder < sqlx:: Postgres > =
146- sqlx:: QueryBuilder :: new ( GET_METADATA_SQL ) ;
147- query. push ( " where kta.entity_key = $1 " ) ;
148- Ok ( query
149- . build_query_as :: < IotMetadata > ( )
150- . bind ( entity_key)
151- . fetch_optional ( db)
152- . await ?)
153- }
154-
155- pub fn all_info_stream < ' a > (
156- db : impl PgExecutor < ' a > + ' a ,
157- ) -> impl Stream < Item = IotMetadata > + ' a {
158- sqlx:: query_as :: < _ , IotMetadata > ( GET_METADATA_SQL )
159- . fetch ( db)
160- . filter_map ( |metadata| async move { metadata. ok ( ) } )
161- . boxed ( )
162- }
163-
164- impl sqlx:: FromRow < ' _ , sqlx:: postgres:: PgRow > for IotMetadata {
165- fn from_row ( row : & sqlx:: postgres:: PgRow ) -> sqlx:: Result < Self > {
166- Ok ( Self {
167- address : PublicKeyBinary :: from_str (
168- & bs58:: encode ( row. get :: < & [ u8 ] , & str > ( "entity_key" ) ) . into_string ( ) ,
169- )
170- . map_err ( |err| sqlx:: Error :: Decode ( Box :: new ( err) ) ) ?,
171- location : row. get :: < Option < i64 > , & str > ( "location" ) . map ( |v| v as u64 ) ,
172- elevation : row
173- . get :: < Option < i32 > , & str > ( "elevation" )
174- . unwrap_or ( DEFAULT_ELEVATION ) ,
175- gain : row. get :: < Option < i32 > , & str > ( "gain" ) . unwrap_or ( DEFAULT_GAIN ) ,
176- is_full_hotspot : row. get ( "is_full_hotspot" ) ,
177- } )
147+ impl From < Gateway > for IotMetadata {
148+ fn from ( gateway : Gateway ) -> Self {
149+ Self {
150+ address : gateway. address ,
151+ location : gateway. location ,
152+ elevation : gateway. elevation . unwrap_or ( DEFAULT_ELEVATION ) as i32 ,
153+ gain : gateway. gain . unwrap_or ( DEFAULT_GAIN ) as i32 ,
154+ is_full_hotspot : gateway. is_full_hotspot . unwrap_or ( false ) ,
178155 }
179156 }
180157}
0 commit comments