diff --git a/mobile_config/src/carrier_service.rs b/mobile_config/src/carrier_service.rs index 4e5789c26..d23e5d1f6 100644 --- a/mobile_config/src/carrier_service.rs +++ b/mobile_config/src/carrier_service.rs @@ -1,28 +1,38 @@ +use std::{collections::HashMap, str::FromStr}; + use crate::{key_cache::KeyCache, telemetry, verify_public_key, GrpcResult}; use chrono::Utc; use file_store::traits::{MsgVerify, TimestampEncode}; use helium_crypto::{Keypair, PublicKey, Sign}; use helium_proto::{ + service_provider_promotions::Promotion, services::mobile_config::{ self, CarrierIncentivePromotionListReqV1, CarrierIncentivePromotionListResV1, CarrierKeyToEntityReqV1, CarrierKeyToEntityResV1, }, - Message, + Message, ServiceProvider, ServiceProviderPromotions, }; -use sqlx::{Pool, Postgres}; +use sqlx::{prelude::FromRow, Pool, Postgres}; use tonic::{Request, Response, Status}; pub struct CarrierService { key_cache: KeyCache, - pool: Pool, + mobile_config_db: Pool, + metadata_db: Pool, signing_key: Keypair, } impl CarrierService { - pub fn new(key_cache: KeyCache, pool: Pool, signing_key: Keypair) -> Self { + pub fn new( + key_cache: KeyCache, + mobile_config_db: Pool, + metadata_db: Pool, + signing_key: Keypair, + ) -> Self { Self { key_cache, - pool, + mobile_config_db, + metadata_db, signing_key, } } @@ -49,11 +59,56 @@ impl CarrierService { " select entity_key from carrier_keys where pubkey = $1 ", ) .bind(pubkey) - .fetch_one(&self.pool) + .fetch_one(&self.mobile_config_db) .await .map_err(|_| Status::internal("carrier entity key not found"))?; Ok(entity_key) } + + async fn fetch_incentive_promotions(&self) -> Result, Status> { + #[derive(Debug, FromRow)] + struct Local { + carrier_name: String, + incentive_escrow_fund_bps: i32, + start_ts: i64, + stop_ts: i64, + shares: i32, + promo_name: String, + } + + let rows = sqlx::query_as::<_, Local>( + r#" + SELECT + c.name as carrier_name, c.incentive_escrow_fund_bps, + iep.carrier, iep.start_ts, iep.stop_ts, iep.shares, iep.name as promo_name + FROM carriers c + JOIN incentive_escrow_programs iep + on c.address = iep.carrier + WHERE + iep.stop_ts > EXTRACT(EPOCH FROM NOW()) + "#, + ) + .fetch_all(&self.metadata_db) + .await + .map_err(|_| Status::internal("could not fetch incentive programs"))?; + + let mut sp_promotions: HashMap = HashMap::new(); + for row in rows { + let m = sp_promotions.entry(row.carrier_name.clone()).or_default(); + m.service_provider = ServiceProvider::from_str(&row.carrier_name) + .map_err(|err| Status::internal(format!("unknown carrier: {err:?}")))? + .into(); + m.incentive_escrow_fund_bps = row.incentive_escrow_fund_bps as u32; + m.promotions.push(Promotion { + entity: row.promo_name, + start_ts: row.start_ts as u64, + end_ts: row.stop_ts as u64, + shares: row.shares as u32, + }); + } + + Ok(sp_promotions.into_values().collect()) + } } #[tonic::async_trait] @@ -92,9 +147,10 @@ impl mobile_config::CarrierService for CarrierService { let signer = verify_public_key(&request.signature)?; self.verify_request_signature(&signer, &request)?; + let promotions = self.fetch_incentive_promotions().await?; + let mut response = CarrierIncentivePromotionListResV1 { - // TODO: db query - service_provider_promotions: vec![], + service_provider_promotions: promotions, signer: self.signing_key.public_key().into(), signature: vec![], }; diff --git a/mobile_config/src/main.rs b/mobile_config/src/main.rs index d12fd5233..e81127ab0 100644 --- a/mobile_config/src/main.rs +++ b/mobile_config/src/main.rs @@ -82,8 +82,12 @@ impl Daemon { metadata_pool.clone(), settings.signing_keypair()?, ); - let carrier_svc = - CarrierService::new(key_cache.clone(), pool.clone(), settings.signing_keypair()?); + let carrier_svc = CarrierService::new( + key_cache.clone(), + pool.clone(), + metadata_pool.clone(), + settings.signing_keypair()?, + ); let hex_boosting_svc = HexBoostingService::new( key_cache.clone(),