Changeset View
Changeset View
Standalone View
Standalone View
services/feature-flags/src/service.rs
use crate::config::CONFIG; | use crate::config::CONFIG; | ||||
use crate::constants::{PLATFORM_ANDROID, PLATFORM_IOS}; | |||||
use crate::database::{DatabaseClient, FeatureConfig, Platform}; | use crate::database::{DatabaseClient, FeatureConfig, Platform}; | ||||
use actix_web::http::header::ContentType; | |||||
use actix_web::{web, App, HttpResponse, HttpServer}; | use actix_web::{web, App, HttpResponse, HttpServer}; | ||||
use comm_services_lib::database::Error; | use comm_services_lib::database::Error; | ||||
use serde::Deserialize; | use serde::Deserialize; | ||||
use std::collections::HashSet; | use std::collections::HashSet; | ||||
pub struct FeatureFlagsService { | pub struct FeatureFlagsService { | ||||
db: DatabaseClient, | db: DatabaseClient, | ||||
} | } | ||||
Show All 14 Lines | HttpServer::new(move || { | ||||
) | ) | ||||
}) | }) | ||||
.bind(("localhost", CONFIG.http_port))? | .bind(("localhost", CONFIG.http_port))? | ||||
.run() | .run() | ||||
.await | .await | ||||
} | } | ||||
async fn features_handler( | async fn features_handler( | ||||
_client: web::Data<DatabaseClient>, | client: web::Data<DatabaseClient>, | ||||
_query: web::Query<FeatureQuery>, | query: web::Query<FeatureQuery>, | ||||
) -> Result<HttpResponse, actix_web::Error> { | ) -> HttpResponse { | ||||
Ok(HttpResponse::Ok().body("HELLO")) | let platform = match query.platform.as_str().to_uppercase().as_str() { | ||||
PLATFORM_IOS => Platform::IOS, | |||||
PLATFORM_ANDROID => Platform::ANDROID, | |||||
_ => return HttpResponse::BadRequest().finish(), | |||||
}; | |||||
match Self::enabled_features_set( | |||||
client.get_ref(), | |||||
platform, | |||||
query.code_version, | |||||
query.is_staff, | |||||
) | |||||
.await | |||||
{ | |||||
Ok(features) => { | |||||
let response_body = features.into_iter().collect::<Vec<_>>().join(","); | |||||
HttpResponse::Ok() | |||||
.content_type(ContentType::plaintext()) | |||||
.body(response_body) | |||||
} | |||||
_ => HttpResponse::InternalServerError().finish(), | |||||
} | |||||
} | } | ||||
async fn _enabled_features_set( | async fn enabled_features_set( | ||||
db: &DatabaseClient, | db: &DatabaseClient, | ||||
platform: Platform, | platform: Platform, | ||||
code_version: i32, | code_version: i32, | ||||
is_staff: bool, | is_staff: bool, | ||||
) -> Result<HashSet<String>, Error> { | ) -> Result<HashSet<String>, Error> { | ||||
let features_config = db.get_features_configuration(platform).await?; | let features_config = db.get_features_configuration(platform).await?; | ||||
Ok( | Ok( | ||||
features_config | features_config | ||||
.into_values() | .into_values() | ||||
.filter_map(|config| { | .filter_map(|config| { | ||||
Self::_feature_name_if_enabled(code_version, is_staff, config) | Self::feature_name_if_enabled(code_version, is_staff, config) | ||||
}) | }) | ||||
.collect(), | .collect(), | ||||
) | ) | ||||
} | } | ||||
fn _feature_name_if_enabled( | fn feature_name_if_enabled( | ||||
code_version: i32, | code_version: i32, | ||||
is_staff: bool, | is_staff: bool, | ||||
feature_config: FeatureConfig, | feature_config: FeatureConfig, | ||||
) -> Option<String> { | ) -> Option<String> { | ||||
feature_config | feature_config | ||||
.config | .config | ||||
.keys() | .keys() | ||||
.filter(|version| *version <= &code_version) | .filter(|version| *version <= &code_version) | ||||
Show All 11 Lines | feature_config | ||||
Some(feature_config.name) | Some(feature_config.name) | ||||
} else { | } else { | ||||
None | None | ||||
} | } | ||||
}) | }) | ||||
} | } | ||||
} | } | ||||
#[allow(dead_code)] | |||||
#[derive(Deserialize, Debug)] | #[derive(Deserialize, Debug)] | ||||
struct FeatureQuery { | struct FeatureQuery { | ||||
code_version: i32, | code_version: i32, | ||||
is_staff: bool, | is_staff: bool, | ||||
platform: String, | platform: String, | ||||
} | } |