@@ -24,63 +24,127 @@ const (
2424 DefaultTimeout = 10 * time .Second
2525)
2626
27- // SetClientConfiguration initializes and configures the HTTP client based on the provided configuration file path and logger.
28- // It loads configuration values from environment variables and, if necessary, from the provided file path.
29- // Default values are set for any missing configuration options, and a final check is performed to ensure completeness.
30- // If any essential configuration values are still missing after setting defaults, it returns an error.
31- func SetClientConfiguration (configFilePath string ) (* ClientConfig , error ) {
32- config := & ClientConfig {}
33-
34- // Load config values from environment variables
35- loadConfigFromEnv (config )
36-
37- // Load config values from file if necessary
38- if validateConfigCompletion (config ) && configFilePath != "" {
39- log .Printf ("Configuration values are incomplete from environment variables, attempting to load from config file: %s" , configFilePath )
40- if err := config .loadConfigFromFile (configFilePath ); err != nil {
41- log .Printf ("Failed to load configuration from file: %s, error: %v" , configFilePath , err )
42- return nil , err
27+ // loadConfigFromFile loads configuration values from a JSON file into the ClientConfig struct.
28+ // It opens the specified configuration file, reads its content, and unmarshals the JSON data
29+ // into the ClientConfig struct. This function is crucial for initializing the client configuration
30+ // with values that may not be provided through environment variables or default values.
31+ // It uses Go's standard log package for logging, as the zap logger is not yet initialized when
32+ // this function is called.
33+ func (config * ClientConfig ) LoadConfigFromFile (filePath string ) error {
34+ // Open the configuration file
35+ file , err := os .Open (filePath )
36+ if err != nil {
37+ log .Printf ("Failed to open the configuration file: %s, error: %v" , filePath , err )
38+ return err
39+ }
40+ defer file .Close ()
41+
42+ reader := bufio .NewReader (file )
43+ var builder strings.Builder
44+
45+ // Read the file content
46+ for {
47+ part , _ , err := reader .ReadLine ()
48+ if err == io .EOF {
49+ break
4350 }
51+ if err != nil {
52+ log .Printf ("Failed to read the configuration file: %s, error: %v" , filePath , err )
53+ return err
54+ }
55+ builder .Write (part )
4456 }
4557
58+ // Unmarshal JSON content into the ClientConfig struct
59+ err = json .Unmarshal ([]byte (builder .String ()), config )
60+ if err != nil {
61+ log .Printf ("Failed to unmarshal the configuration file: %s, error: %v" , filePath , err )
62+ return err
63+ }
64+
65+ log .Printf ("Configuration successfully loaded from file: %s" , filePath )
66+
4667 // Set default values if necessary
4768 setLoggerDefaultValues (config )
4869 setClientDefaultValues (config )
4970
50- // Recheck if config values are still incomplete after setting defaults
51- if validateConfigCompletion (config ) {
52- return nil , fmt .Errorf ("incomplete configuration values even after setting defaults" )
71+ // validate configuration
72+ if err := validateMandatoryConfiguration (config ); err != nil {
73+ return fmt .Errorf ("configuration validation failed: %w" , err )
5374 }
5475
55- return config , nil
76+ return nil
5677}
5778
58- // loadConfigFromEnv populates the ClientConfig structure with values from environment variables.
79+ // LoadConfigFromEnv populates the ClientConfig structure with values from environment variables.
5980// It updates the configuration for authentication, environment specifics, and client options
6081// based on the presence of environment variables. For each configuration option, if an environment
6182// variable is set, its value is used; otherwise, the existing value in the ClientConfig structure
62- // is retained.
63- func loadConfigFromEnv (config * ClientConfig ) {
83+ // is retained. It also sets default values if necessary and validates the final configuration,
84+ // returning an error if the configuration is incomplete.
85+ func LoadConfigFromEnv (config * ClientConfig ) (* ClientConfig , error ) {
86+ if config == nil {
87+ config = & ClientConfig {} // Initialize config if nil
88+ }
89+
6490 // AuthConfig
6591 config .Auth .ClientID = getEnvOrDefault ("CLIENT_ID" , config .Auth .ClientID )
92+ log .Printf ("ClientID env value found and set to: %s" , config .Auth .ClientID )
93+
6694 config .Auth .ClientSecret = getEnvOrDefault ("CLIENT_SECRET" , config .Auth .ClientSecret )
95+ log .Printf ("ClientSecret env value found and set" )
6796
6897 // EnvironmentConfig
6998 config .Environment .InstanceName = getEnvOrDefault ("INSTANCE_NAME" , config .Environment .InstanceName )
99+ log .Printf ("InstanceName env value found and set to: %s" , config .Environment .InstanceName )
100+
70101 config .Environment .OverrideBaseDomain = getEnvOrDefault ("OVERRIDE_BASE_DOMAIN" , config .Environment .OverrideBaseDomain )
102+ log .Printf ("OverrideBaseDomain env value found and set to: %s" , config .Environment .OverrideBaseDomain )
103+
71104 config .Environment .APIType = getEnvOrDefault ("API_TYPE" , config .Environment .APIType )
105+ log .Printf ("APIType env value found and set to: %s" , config .Environment .APIType )
72106
73107 // ClientOptions
74108 config .ClientOptions .LogLevel = getEnvOrDefault ("LOG_LEVEL" , config .ClientOptions .LogLevel )
109+ log .Printf ("LogLevel env value found and set to: %s" , config .ClientOptions .LogLevel )
110+
75111 config .ClientOptions .LogOutputFormat = getEnvOrDefault ("LOG_OUTPUT_FORMAT" , config .ClientOptions .LogOutputFormat )
112+ log .Printf ("LogOutputFormat env value found and set to: %s" , config .ClientOptions .LogOutputFormat )
113+
76114 config .ClientOptions .LogConsoleSeparator = getEnvOrDefault ("LOG_CONSOLE_SEPARATOR" , config .ClientOptions .LogConsoleSeparator )
115+ log .Printf ("LogConsoleSeparator env value found and set to: %s" , config .ClientOptions .LogConsoleSeparator )
116+
77117 config .ClientOptions .HideSensitiveData = parseBool (getEnvOrDefault ("HIDE_SENSITIVE_DATA" , strconv .FormatBool (config .ClientOptions .HideSensitiveData )))
118+ log .Printf ("HideSensitiveData env value found and set to: %t" , config .ClientOptions .HideSensitiveData )
119+
78120 config .ClientOptions .MaxRetryAttempts = parseInt (getEnvOrDefault ("MAX_RETRY_ATTEMPTS" , strconv .Itoa (config .ClientOptions .MaxRetryAttempts )), DefaultMaxRetryAttempts )
121+ log .Printf ("MaxRetryAttempts env value found and set to: %d" , config .ClientOptions .MaxRetryAttempts )
122+
79123 config .ClientOptions .EnableDynamicRateLimiting = parseBool (getEnvOrDefault ("ENABLE_DYNAMIC_RATE_LIMITING" , strconv .FormatBool (config .ClientOptions .EnableDynamicRateLimiting )))
124+ log .Printf ("EnableDynamicRateLimiting env value found and set to: %t" , config .ClientOptions .EnableDynamicRateLimiting )
125+
80126 config .ClientOptions .MaxConcurrentRequests = parseInt (getEnvOrDefault ("MAX_CONCURRENT_REQUESTS" , strconv .Itoa (config .ClientOptions .MaxConcurrentRequests )), DefaultMaxConcurrentRequests )
127+ log .Printf ("MaxConcurrentRequests env value found and set to: %d" , config .ClientOptions .MaxConcurrentRequests )
128+
81129 config .ClientOptions .TokenRefreshBufferPeriod = parseDuration (getEnvOrDefault ("TOKEN_REFRESH_BUFFER_PERIOD" , config .ClientOptions .TokenRefreshBufferPeriod .String ()), DefaultTokenBufferPeriod )
130+ log .Printf ("TokenRefreshBufferPeriod env value found and set to: %s" , config .ClientOptions .TokenRefreshBufferPeriod )
131+
82132 config .ClientOptions .TotalRetryDuration = parseDuration (getEnvOrDefault ("TOTAL_RETRY_DURATION" , config .ClientOptions .TotalRetryDuration .String ()), DefaultTotalRetryDuration )
133+ log .Printf ("TotalRetryDuration env value found and set to: %s" , config .ClientOptions .TotalRetryDuration )
134+
83135 config .ClientOptions .CustomTimeout = parseDuration (getEnvOrDefault ("CUSTOM_TIMEOUT" , config .ClientOptions .CustomTimeout .String ()), DefaultTimeout )
136+ log .Printf ("CustomTimeout env value found and set to: %s" , config .ClientOptions .CustomTimeout )
137+
138+ // Set default values if necessary
139+ setLoggerDefaultValues (config )
140+ setClientDefaultValues (config )
141+
142+ // Validate final configuration
143+ if err := validateMandatoryConfiguration (config ); err != nil {
144+ return nil , err // Return the error if the configuration is incomplete
145+ }
146+
147+ return config , nil
84148}
85149
86150// Helper function to get environment variable or default value
@@ -118,14 +182,42 @@ func parseDuration(value string, defaultVal time.Duration) time.Duration {
118182 return result
119183}
120184
121- // validateConfigCompletion checks if any essential configuration fields are missing,
122- // indicating the configuration might be incomplete and may require loading from additional sources.
123- func validateConfigCompletion (config * ClientConfig ) bool {
124- // Check if essential fields are missing; additional fields can be checked as needed
125- return config .Auth .ClientID == "" || config .Auth .ClientSecret == "" ||
126- config .Environment .InstanceName == "" || config .Environment .APIType == "" ||
127- config .ClientOptions .LogLevel == "" || config .ClientOptions .LogOutputFormat == "" ||
128- config .ClientOptions .LogConsoleSeparator == ""
185+ // validateMandatoryConfiguration checks if any essential configuration fields are missing,
186+ // and returns an error with details about the missing configurations.
187+ // This ensures the caller can understand what specific configurations need attention.
188+ func validateMandatoryConfiguration (config * ClientConfig ) error {
189+ var missingFields []string
190+
191+ // Check for missing mandatory fields and add them to the missingFields slice if necessary.
192+ if config .Auth .ClientID == "" {
193+ missingFields = append (missingFields , "Auth.ClientID" )
194+ }
195+ if config .Auth .ClientSecret == "" {
196+ missingFields = append (missingFields , "Auth.ClientSecret" )
197+ }
198+ if config .Environment .InstanceName == "" {
199+ missingFields = append (missingFields , "Environment.InstanceName" )
200+ }
201+ if config .Environment .APIType == "" {
202+ missingFields = append (missingFields , "Environment.APIType" )
203+ }
204+ if config .ClientOptions .LogLevel == "" {
205+ missingFields = append (missingFields , "ClientOptions.LogLevel" )
206+ }
207+ if config .ClientOptions .LogOutputFormat == "" {
208+ missingFields = append (missingFields , "ClientOptions.LogOutputFormat" )
209+ }
210+ if config .ClientOptions .LogConsoleSeparator == "" {
211+ missingFields = append (missingFields , "ClientOptions.LogConsoleSeparator" )
212+ }
213+
214+ // If there are missing fields, return an error detailing what is missing.
215+ if len (missingFields ) > 0 {
216+ return fmt .Errorf ("mandatory configuration missing: %s" , strings .Join (missingFields , ", " ))
217+ }
218+
219+ // If no fields are missing, return nil indicating the configuration is complete.
220+ return nil
129221}
130222
131223// setClientDefaultValues sets default values for the client configuration options if none are provided.
@@ -186,45 +278,3 @@ func setLoggerDefaultValues(config *ClientConfig) {
186278 // Log completion of setting default values
187279 log .Println ("Default values set for logger configuration" )
188280}
189-
190- // loadConfigFromFile loads configuration values from a JSON file into the ClientConfig struct.
191- // It opens the specified configuration file, reads its content, and unmarshals the JSON data
192- // into the ClientConfig struct. This function is crucial for initializing the client configuration
193- // with values that may not be provided through environment variables or default values.
194- // It uses Go's standard log package for logging, as the zap logger is not yet initialized when
195- // this function is called.
196- func (config * ClientConfig ) loadConfigFromFile (filePath string ) error {
197- // Open the configuration file
198- file , err := os .Open (filePath )
199- if err != nil {
200- log .Printf ("Failed to open the configuration file: %s, error: %v" , filePath , err )
201- return err
202- }
203- defer file .Close ()
204-
205- reader := bufio .NewReader (file )
206- var builder strings.Builder
207-
208- // Read the file content
209- for {
210- part , _ , err := reader .ReadLine ()
211- if err == io .EOF {
212- break
213- }
214- if err != nil {
215- log .Printf ("Failed to read the configuration file: %s, error: %v" , filePath , err )
216- return err
217- }
218- builder .Write (part )
219- }
220-
221- // Unmarshal JSON content into the ClientConfig struct
222- err = json .Unmarshal ([]byte (builder .String ()), config )
223- if err != nil {
224- log .Printf ("Failed to unmarshal the configuration file: %s, error: %v" , filePath , err )
225- return err
226- }
227-
228- log .Printf ("Configuration successfully loaded from file: %s" , filePath )
229- return nil
230- }
0 commit comments