@@ -24,65 +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- // Check if the configuration is complete; if not, load from file
38- if ! validateConfigCompletion (config ) {
39- if configFilePath != "" {
40- if err := config .loadConfigFromFile (configFilePath ); err != nil {
41- return nil , err
42- }
43- } else {
44- return nil , fmt .Errorf ("http client configuration is incomplete. Required environment variables are missing, and no configuration file path is provided. Please set the necessary environment variables or provide a valid configuration file path" )
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
4550 }
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 )
4656 }
4757
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+
4867 // Set default values if necessary
4968 setLoggerDefaultValues (config )
5069 setClientDefaultValues (config )
5170
52- // Recheck if config values are still incomplete after setting defaults
53- if validateConfigCompletion (config ) {
54- 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 )
5574 }
5675
57- return config , nil
76+ return nil
5877}
5978
60- // loadConfigFromEnv populates the ClientConfig structure with values from environment variables.
79+ // LoadConfigFromEnv populates the ClientConfig structure with values from environment variables.
6180// It updates the configuration for authentication, environment specifics, and client options
6281// based on the presence of environment variables. For each configuration option, if an environment
6382// variable is set, its value is used; otherwise, the existing value in the ClientConfig structure
64- // is retained.
65- 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+
6690 // AuthConfig
6791 config .Auth .ClientID = getEnvOrDefault ("CLIENT_ID" , config .Auth .ClientID )
92+ log .Printf ("ClientID env value found and set to: %s" , config .Auth .ClientID )
93+
6894 config .Auth .ClientSecret = getEnvOrDefault ("CLIENT_SECRET" , config .Auth .ClientSecret )
95+ log .Printf ("ClientSecret env value found and set" )
6996
7097 // EnvironmentConfig
7198 config .Environment .InstanceName = getEnvOrDefault ("INSTANCE_NAME" , config .Environment .InstanceName )
99+ log .Printf ("InstanceName env value found and set to: %s" , config .Environment .InstanceName )
100+
72101 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+
73104 config .Environment .APIType = getEnvOrDefault ("API_TYPE" , config .Environment .APIType )
105+ log .Printf ("APIType env value found and set to: %s" , config .Environment .APIType )
74106
75107 // ClientOptions
76108 config .ClientOptions .LogLevel = getEnvOrDefault ("LOG_LEVEL" , config .ClientOptions .LogLevel )
109+ log .Printf ("LogLevel env value found and set to: %s" , config .ClientOptions .LogLevel )
110+
77111 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+
78114 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+
79117 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+
80120 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+
81123 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+
82126 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+
83129 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+
84132 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+
85135 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
86148}
87149
88150// Helper function to get environment variable or default value
@@ -120,14 +182,42 @@ func parseDuration(value string, defaultVal time.Duration) time.Duration {
120182 return result
121183}
122184
123- // validateConfigCompletion checks if any essential configuration fields are missing,
124- // indicating the configuration might be incomplete and may require loading from additional sources.
125- func validateConfigCompletion (config * ClientConfig ) bool {
126- // Check if essential fields are missing; additional fields can be checked as needed
127- return config .Auth .ClientID == "" || config .Auth .ClientSecret == "" ||
128- config .Environment .InstanceName == "" || config .Environment .APIType == "" ||
129- config .ClientOptions .LogLevel == "" || config .ClientOptions .LogOutputFormat == "" ||
130- 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
131221}
132222
133223// setClientDefaultValues sets default values for the client configuration options if none are provided.
@@ -188,45 +278,3 @@ func setLoggerDefaultValues(config *ClientConfig) {
188278 // Log completion of setting default values
189279 log .Println ("Default values set for logger configuration" )
190280}
191-
192- // loadConfigFromFile loads configuration values from a JSON file into the ClientConfig struct.
193- // It opens the specified configuration file, reads its content, and unmarshals the JSON data
194- // into the ClientConfig struct. This function is crucial for initializing the client configuration
195- // with values that may not be provided through environment variables or default values.
196- // It uses Go's standard log package for logging, as the zap logger is not yet initialized when
197- // this function is called.
198- func (config * ClientConfig ) loadConfigFromFile (filePath string ) error {
199- // Open the configuration file
200- file , err := os .Open (filePath )
201- if err != nil {
202- log .Printf ("Failed to open the configuration file: %s, error: %v" , filePath , err )
203- return err
204- }
205- defer file .Close ()
206-
207- reader := bufio .NewReader (file )
208- var builder strings.Builder
209-
210- // Read the file content
211- for {
212- part , _ , err := reader .ReadLine ()
213- if err == io .EOF {
214- break
215- }
216- if err != nil {
217- log .Printf ("Failed to read the configuration file: %s, error: %v" , filePath , err )
218- return err
219- }
220- builder .Write (part )
221- }
222-
223- // Unmarshal JSON content into the ClientConfig struct
224- err = json .Unmarshal ([]byte (builder .String ()), config )
225- if err != nil {
226- log .Printf ("Failed to unmarshal the configuration file: %s, error: %v" , filePath , err )
227- return err
228- }
229-
230- log .Printf ("Configuration successfully loaded from file: %s" , filePath )
231- return nil
232- }
0 commit comments