■ ■ ■ ■ ■ ■
v3/crates/engine/bin/engine/main.rs
skipped 18 lines 19 19 TraceableError, TraceableHttpResponse, 20 20 }; 21 21 22 + use base64::engine::Engine; 22 23 use engine::{ 23 24 authentication::{AuthConfig, AuthConfig::V1 as V1AuthConfig, AuthModeConfig}, 24 25 execute::HttpContext, skipped 4 lines 29 30 use hasura_authn_jwt::jwt; 30 31 use hasura_authn_webhook::webhook; 31 32 use lang_graphql as gql; 33 + use std::hash; 34 + use std::hash::{Hash, Hasher}; 32 35 33 36 const DEFAULT_PORT: u16 = 3000; 34 37 skipped 4 lines 39 42 struct ServerOptions { 40 43 #[arg(long, value_name = "METADATA_FILE", env = "METADATA_PATH")] 41 44 metadata_path: PathBuf, 45 + #[arg( 46 + long, 47 + value_name = "INTROSPECTION_METADATA_FILE", 48 + env = "INTROSPECTION_METADATA_FILE" 49 + )] 50 + introspection_metadata: Option<String>, 42 51 #[arg(long, value_name = "OTLP_ENDPOINT", env = "OTLP_ENDPOINT")] 43 52 otlp_endpoint: Option<String>, 44 53 #[arg(long, value_name = "AUTHN_CONFIG_FILE", env = "AUTHN_CONFIG_PATH")] skipped 83 lines 128 137 async fn start_engine(server: &ServerOptions) -> Result<(), StartupError> { 129 138 let auth_config = 130 139 read_auth_config(&server.authn_config_path).map_err(StartupError::ReadAuth)?; 131 - let (raw_metadata, schema) = 132 - read_schema(&server.metadata_path).map_err(StartupError::ReadSchema)?; 140 + let schema = read_schema(&server.metadata_path).map_err(StartupError::ReadSchema)?; 133 141 let http_context = HttpContext { 134 142 client: reqwest::Client::new(), 135 143 ndc_response_size_limit: None, skipped 3 lines 139 147 schema, 140 148 auth_config, 141 149 }); 142 - 143 - let metadata_route = Router::new().route("/metadata", get(|| async { raw_metadata })); 144 150 145 151 let graphql_route = Router::new() 146 152 .route("/graphql", post(handle_request)) skipped 33 lines 180 186 181 187 let health_route = Router::new().route("/health", get(handle_health)); 182 188 183 - let app = Router::new() 189 + let app_ = Router::new() 184 190 // serve graphiql at root 185 191 .route("/", get(graphiql)) 186 - .merge(metadata_route) 187 192 .merge(graphql_route) 188 193 .merge(explain_route) 189 194 .merge(health_route) 190 195 .layer(DefaultBodyLimit::max(10 * MB)); // Set request payload limit to 10 MB 196 + 197 + // If `--introspection-metadata` is specified we also serve the file indicated on `/metadata` 198 + // and its hash on `/metadata-hash`. This is a temporary workaround to enable the console to 199 + // interact with an engine process running locally (c.f running in the hasura cloud). 200 + let app = match &server.introspection_metadata { 201 + None => app_, 202 + Some(file) => { 203 + let file_owned = file.to_string(); 204 + let file_contents = tokio::fs::read_to_string(file_owned) 205 + .await 206 + .map_err(|err| StartupError::ReadSchema(err.into()))?; 207 + let mut hasher = hash::DefaultHasher::new(); 208 + file_contents.as_str().hash(&mut hasher); 209 + let hash = hasher.finish(); 210 + let base64_hash = base64::engine::general_purpose::STANDARD.encode(hash.to_ne_bytes()); 211 + app_.merge(Router::new().route("/metadata", get(|| async { file_contents }))) 212 + .merge(Router::new().route("/metadata-hash", get(|| async { base64_hash }))) 213 + } 214 + }; 191 215 192 216 // The "unspecified" IPv6 address will match any IPv4 or IPv6 address. 193 217 let host = net::IpAddr::V6(net::Ipv6Addr::UNSPECIFIED); skipped 211 lines 405 429 response 406 430 } 407 431 408 - fn read_schema( 409 - metadata_path: &PathBuf, 410 - ) -> Result<(String, gql::schema::Schema<GDS>), anyhow::Error> { 432 + fn read_schema(metadata_path: &PathBuf) -> Result<gql::schema::Schema<GDS>, anyhow::Error> { 411 433 let raw_metadata = std::fs::read_to_string(metadata_path)?; 412 434 let metadata = open_dds::Metadata::from_json_str(&raw_metadata)?; 413 - Ok(( raw_metadata , engine::build::build_schema(metadata)?)) 435 + Ok(engine::build::build_schema(metadata)?) 414 436 } 415 437 416 438 fn read_auth_config(path: &PathBuf) -> Result<AuthConfig, anyhow::Error> { skipped 6 lines