-
Notifications
You must be signed in to change notification settings - Fork 54
Add YAML config support for transport configuration in build.rs #1554
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
5 commits
Select commit
Hold shift + click to select a range
5575298
Add YAML config support for transport configuration in build.rs
claude 5f8e5c5
Fix transport type mapping and add interval field
github-actions[bot] 716f756
Add server_pubkey field to YAML config
github-actions[bot] b295966
fix
hulto bd08752
fmt
hulto File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,8 +1,166 @@ | ||
| use serde::Deserialize; | ||
| use std::collections::HashMap; | ||
| use std::env; | ||
| use std::path::PathBuf; | ||
| use which::which; | ||
|
|
||
| #[derive(Debug, Deserialize)] | ||
| struct TransportConfig { | ||
| #[serde(rename = "URI")] | ||
| uri: String, | ||
| #[serde(rename = "type")] | ||
| transport_type: String, | ||
| extra: String, | ||
| #[serde(default)] | ||
| interval: Option<u64>, | ||
| } | ||
|
|
||
| #[derive(Debug, Deserialize)] | ||
| struct YamlConfig { | ||
| transports: Vec<TransportConfig>, | ||
| #[serde(default)] | ||
| server_pubkey: Option<String>, | ||
| } | ||
|
|
||
| fn parse_yaml_config() -> Result<bool, Box<dyn std::error::Error>> { | ||
| // Check if IMIX_CONFIG is set | ||
| let config_yaml = match std::env::var("IMIX_CONFIG") { | ||
| Ok(yaml_content) => yaml_content, | ||
| Err(_) => return Ok(false), // No config set, return false | ||
| }; | ||
|
|
||
| // Check that other configuration options are not set | ||
| let has_callback_uri = std::env::var("IMIX_CALLBACK_URI").is_ok(); | ||
| let has_callback_interval = std::env::var("IMIX_CALLBACK_INTERVAL").is_ok(); | ||
| let has_transport_extra = std::env::vars().any(|(k, _)| k.starts_with("IMIX_TRANSPORT_EXTRA_")); | ||
|
|
||
| if has_callback_uri || has_callback_interval || has_transport_extra { | ||
| let mut error_msg = String::from( | ||
| "Configuration error: Cannot use IMIX_CONFIG with other configuration options.\n", | ||
| ); | ||
| error_msg.push_str( | ||
| "When IMIX_CONFIG is set, all configuration must be done through the YAML file.\n", | ||
| ); | ||
| error_msg.push_str("Found one or more of:\n"); | ||
|
|
||
| if has_callback_uri { | ||
| error_msg.push_str(" - IMIX_CALLBACK_URI\n"); | ||
| } | ||
| if has_callback_interval { | ||
| error_msg.push_str(" - IMIX_CALLBACK_INTERVAL\n"); | ||
| } | ||
| if has_transport_extra { | ||
| error_msg.push_str(" - IMIX_TRANSPORT_EXTRA_*\n"); | ||
| } | ||
|
|
||
| error_msg.push_str( | ||
| "\nPlease use ONLY the YAML config file OR use environment variables, but not both.", | ||
| ); | ||
|
|
||
| return Err(error_msg.into()); | ||
| } | ||
|
|
||
| // Parse the YAML config | ||
| let config: YamlConfig = serde_yaml::from_str(&config_yaml) | ||
| .map_err(|e| format!("Failed to parse YAML config: {}", e))?; | ||
|
|
||
| // Validate that we have at least one transport | ||
| if config.transports.is_empty() { | ||
| return Err("YAML config must contain at least one transport".into()); | ||
| } | ||
|
|
||
| // Build DSN string from transports | ||
| let mut dsn_parts = Vec::new(); | ||
|
|
||
| for transport in &config.transports { | ||
| // Validate transport type | ||
| let transport_type_lower = transport.transport_type.to_lowercase(); | ||
| if !["grpc", "http1", "dns"].contains(&transport_type_lower.as_str()) { | ||
| return Err(format!( | ||
| "Invalid transport type '{}'. Must be one of: GRPC, http1, DNS", | ||
| transport.transport_type | ||
| ) | ||
| .into()); | ||
| } | ||
|
|
||
| // Validate that extra is valid JSON | ||
| if !transport.extra.is_empty() { | ||
| serde_json::from_str::<serde_json::Value>(&transport.extra).map_err(|e| { | ||
| format!( | ||
| "Invalid JSON in 'extra' field for transport '{}': {}", | ||
| transport.uri, e | ||
| ) | ||
| })?; | ||
| } | ||
|
|
||
| // Error if URI already contains query parameters | ||
| if transport.uri.contains('?') { | ||
| return Err(format!("URI '{}' already contains query parameters. Query parameters should not be present in the URI field.", transport.uri).into()); | ||
| } | ||
|
|
||
| // Map transport type to appropriate schema | ||
| let schema = match transport_type_lower.as_str() { | ||
| "grpc" => "grpc", | ||
| "http1" => "http", | ||
| "dns" => "dns", | ||
| _ => unreachable!(), // Already validated above | ||
| }; | ||
|
|
||
| // Strip any existing schema from the URI and replace with the correct one | ||
| let uri_without_schema = transport | ||
| .uri | ||
| .split_once("://") | ||
| .map(|(_, rest)| rest) | ||
| .unwrap_or(&transport.uri); | ||
|
|
||
| // Build DSN part with correct schema and query parameters | ||
| let mut dsn_part = format!("{}://{}", schema, uri_without_schema); | ||
|
|
||
| // Add query parameters | ||
| dsn_part.push('?'); | ||
| let mut params = Vec::new(); | ||
|
|
||
| // Add interval if present | ||
| if let Some(interval) = transport.interval { | ||
| params.push(format!("interval={}", interval)); | ||
| } | ||
|
|
||
| // Add extra as query parameter if not empty | ||
| if !transport.extra.is_empty() { | ||
| let encoded_extra = urlencoding::encode(&transport.extra); | ||
| params.push(format!("extra={}", encoded_extra)); | ||
| } | ||
|
|
||
| if !params.is_empty() { | ||
| dsn_part.push_str(¶ms.join("&")); | ||
| } else { | ||
| // Remove the trailing '?' if no params were added | ||
| dsn_part.pop(); | ||
| } | ||
|
|
||
| dsn_parts.push(dsn_part); | ||
| } | ||
|
|
||
| // Join all DSN parts with semicolons | ||
| let dsn = dsn_parts.join(";"); | ||
|
|
||
| // Emit the DSN configuration | ||
| println!("cargo:rustc-env=IMIX_CALLBACK_URI={}", dsn); | ||
|
|
||
| // Emit server_pubkey if present | ||
| if let Some(ref pubkey) = config.server_pubkey { | ||
| println!("cargo:rustc-env=IMIX_SERVER_PUBKEY={}", pubkey); | ||
| println!("cargo:warning=Using server_pubkey from YAML config"); | ||
| } | ||
|
|
||
| println!( | ||
| "cargo:warning=Successfully parsed YAML config with {} transport(s)", | ||
| config.transports.len() | ||
| ); | ||
|
|
||
| Ok(true) | ||
| } | ||
|
|
||
| fn get_pub_key() { | ||
| // Check if IMIX_SERVER_PUBKEY is already set | ||
| if std::env::var("IMIX_SERVER_PUBKEY").is_ok() { | ||
|
|
@@ -95,6 +253,12 @@ fn build_extra_vars() -> Result<(), Box<dyn std::error::Error>> { | |
| } | ||
|
|
||
| fn validate_dsn_config() -> Result<(), Box<dyn std::error::Error>> { | ||
| // Skip validation if YAML config is being used | ||
| // (parse_yaml_config already handles validation in that case) | ||
| if std::env::var("IMIX_CONFIG").is_ok() { | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. doesn't need to be in this change, but ideally we can move this configuration out of the |
||
| return Ok(()); | ||
| } | ||
|
|
||
| // Check if IMIX_CALLBACK_URI contains query parameters | ||
| let callback_uri = | ||
| std::env::var("IMIX_CALLBACK_URI").unwrap_or_else(|_| "http://127.0.0.1:8000".to_string()); | ||
|
|
@@ -126,7 +290,12 @@ fn validate_dsn_config() -> Result<(), Box<dyn std::error::Error>> { | |
| } | ||
|
|
||
| fn main() -> Result<(), Box<dyn std::error::Error>> { | ||
| // Parse YAML config if present (this will emit IMIX_CALLBACK_URI if successful) | ||
| parse_yaml_config()?; | ||
|
|
||
| // Validate DSN config (skips if YAML config was used) | ||
| validate_dsn_config()?; | ||
|
|
||
| get_pub_key(); | ||
| build_extra_vars()?; | ||
|
|
||
|
|
||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add an interval field to the config.