From 81369c0ec24d2841b81093cdd2be3649ca6b3ced Mon Sep 17 00:00:00 2001 From: Young Xu Date: Mon, 7 Apr 2025 00:35:40 +0800 Subject: [PATCH] chore: change chinese comment to english Signed-off-by: Young Xu --- agcache/cache.go | 34 +++++++- agcache/memory/memory.go | 48 ++++++++--- client.go | 112 ++++++++++++++++++------- cluster/load_balance.go | 17 +++- cluster/roundrobin/round_robin.go | 16 +++- component/common.go | 13 ++- component/log/log.go | 76 +++++++++++------ component/notify/componet_notify.go | 32 +++++-- component/remote/abs.go | 20 ++++- component/remote/async.go | 79 +++++++++++++++++- component/remote/remote.go | 40 +++++++-- component/remote/sync.go | 46 +++++++++- component/serverlist/sync.go | 37 ++++++-- constant/config_file_format.go | 26 ++++-- env/app_config.go | 59 +++++++++++-- env/config/apollo_config.go | 59 +++++++++---- env/config/config.go | 125 ++++++++++++++++++++-------- env/config/json/json_config.go | 25 +++++- env/file/file_handler.go | 26 +++++- env/file/json/json.go | 60 ++++++++++--- env/file/json/raw.go | 39 ++++++++- env/request_config.go | 25 ++++-- env/server/server.go | 65 +++++++++++---- extension/cache.go | 15 +++- extension/file.go | 16 +++- extension/format_parser.go | 19 ++++- extension/load_balance.go | 16 +++- extension/sign.go | 17 +++- protocol/auth/auth.go | 16 +++- protocol/auth/sign/sign.go | 53 ++++++++++-- protocol/http/request.go | 83 ++++++++++++++---- start.go | 49 +++++++++-- storage/change_event.go | 68 +++++++++++---- storage/event_dispatch.go | 34 ++++++-- storage/repository.go | 113 ++++++++++++++++--------- test-application.json | 1 + utils/parse/normal/parser.go | 15 +++- utils/parse/parser.go | 12 ++- utils/parse/properties/parser.go | 16 +++- utils/parse/yaml/parser.go | 32 ++++++- utils/parse/yml/parser.go | 32 ++++++- utils/utils.go | 38 +++++++-- 42 files changed, 1398 insertions(+), 326 deletions(-) create mode 100644 test-application.json diff --git a/agcache/cache.go b/agcache/cache.go index 7803c01b..151f9ef8 100644 --- a/agcache/cache.go +++ b/agcache/cache.go @@ -14,23 +14,51 @@ package agcache -// CacheInterface 自定义缓存组件接口 +// CacheInterface defines the contract for custom cache implementations type CacheInterface interface { + // Set stores a key-value pair in the cache with an expiration time + // Parameters: + // - key: The unique identifier for the cache entry + // - value: The data to be stored + // - expireSeconds: Time in seconds after which the entry should expire + // Returns: + // - error: Any error that occurred during the operation Set(key string, value interface{}, expireSeconds int) (err error) + // EntryCount returns the total number of entries in the cache + // Returns: + // - entryCount: The current number of entries stored in the cache EntryCount() (entryCount int64) + // Get retrieves a value from the cache by its key + // Parameters: + // - key: The unique identifier for the cache entry + // Returns: + // - value: The stored value if found + // - error: Error if the key doesn't exist or any other error occurs Get(key string) (value interface{}, err error) + // Del removes an entry from the cache by its key + // Parameters: + // - key: The unique identifier of the entry to be deleted + // Returns: + // - affected: True if the key was found and deleted, false otherwise Del(key string) (affected bool) + // Range iterates over all key/value pairs in the cache + // Parameters: + // - f: The function to be executed for each cache entry + // Return false from f to stop iteration Range(f func(key, value interface{}) bool) + // Clear removes all entries from the cache Clear() } -// CacheFactory 缓存组件工厂接口 +// CacheFactory defines the interface for creating cache instances type CacheFactory interface { - //Create 创建缓存组件 + // Create instantiates and returns a new cache implementation + // Returns: + // - CacheInterface: A new instance of a cache implementation Create() CacheInterface } diff --git a/agcache/memory/memory.go b/agcache/memory/memory.go index 266adad6..4032b19f 100644 --- a/agcache/memory/memory.go +++ b/agcache/memory/memory.go @@ -22,26 +22,41 @@ import ( "github.com/apolloconfig/agollo/v4/agcache" ) -// DefaultCache 默认缓存 +// DefaultCache implements a thread-safe in-memory cache using sync.Map type DefaultCache struct { - defaultCache sync.Map - count int64 + defaultCache sync.Map // The underlying thread-safe map for storing cache entries + count int64 // Counter for tracking the number of cache entries } -// Set 获取缓存 +// Set stores a key-value pair in the cache +// Parameters: +// - key: The unique identifier for the cache entry +// - value: The data to be stored +// - expireSeconds: Time in seconds after which the entry should expire (currently not implemented) +// +// Returns: +// - error: Always returns nil as the operation cannot fail func (d *DefaultCache) Set(key string, value interface{}, expireSeconds int) (err error) { d.defaultCache.Store(key, value) atomic.AddInt64(&d.count, int64(1)) return nil } -// EntryCount 获取实体数量 +// EntryCount returns the total number of entries in the cache +// Returns: +// - entryCount: The current number of entries stored in the cache func (d *DefaultCache) EntryCount() (entryCount int64) { c := atomic.LoadInt64(&d.count) return c } -// Get 获取缓存 +// Get retrieves a value from the cache by its key +// Parameters: +// - key: The unique identifier for the cache entry +// +// Returns: +// - value: The stored value if found +// - error: Error if the key doesn't exist in the cache func (d *DefaultCache) Get(key string) (value interface{}, err error) { v, ok := d.defaultCache.Load(key) if !ok { @@ -50,29 +65,40 @@ func (d *DefaultCache) Get(key string) (value interface{}, err error) { return v, nil } -// Range 遍历缓存 +// Range iterates over all key/value pairs in the cache +// Parameters: +// - f: The function to be executed for each cache entry +// Return false from f to stop iteration func (d *DefaultCache) Range(f func(key, value interface{}) bool) { d.defaultCache.Range(f) } -// Del 删除缓存 +// Del removes an entry from the cache by its key +// Parameters: +// - key: The unique identifier of the entry to be deleted +// +// Returns: +// - affected: Always returns true regardless of whether the key existed func (d *DefaultCache) Del(key string) (affected bool) { d.defaultCache.Delete(key) atomic.AddInt64(&d.count, int64(-1)) return true } -// Clear 清除所有缓存 +// Clear removes all entries from the cache +// This operation reinitializes the underlying sync.Map and resets the counter func (d *DefaultCache) Clear() { d.defaultCache = sync.Map{} atomic.StoreInt64(&d.count, int64(0)) } -// DefaultCacheFactory 构造默认缓存组件工厂类 +// DefaultCacheFactory is a factory for creating new instances of DefaultCache type DefaultCacheFactory struct { } -// Create 创建默认缓存组件 +// Create instantiates and returns a new DefaultCache instance +// Returns: +// - agcache.CacheInterface: A new instance of DefaultCache func (d *DefaultCacheFactory) Create() agcache.CacheInterface { return &DefaultCache{} } diff --git a/client.go b/client.go index ecd67084..2f42ba23 100644 --- a/client.go +++ b/client.go @@ -41,56 +41,79 @@ import ( "github.com/apolloconfig/agollo/v4/utils/parse/yml" ) +// separator is used to split string values in configuration const separator = "," +// init initializes the default components and extensions for the Apollo client func init() { extension.SetCacheFactory(&memory.DefaultCacheFactory{}) extension.SetLoadBalance(&roundrobin.RoundRobin{}) extension.SetFileHandler(&jsonFile.FileHandler{}) extension.SetHTTPAuth(&sign.AuthSignature{}) - // file parser + // Register file parsers for different configuration formats extension.AddFormatParser(constant.DEFAULT, &normal.Parser{}) extension.AddFormatParser(constant.Properties, &properties.Parser{}) extension.AddFormatParser(constant.YML, &yml.Parser{}) extension.AddFormatParser(constant.YAML, &yaml.Parser{}) } +// syncApolloConfig is used to synchronize Apollo configurations var syncApolloConfig = remote.CreateSyncApolloConfig() -// Client apollo 客户端接口 +// Client defines the interface for Apollo configuration client +// It provides methods to access and manage Apollo configurations type Client interface { + // GetConfig retrieves the configuration for a specific namespace GetConfig(namespace string) *storage.Config + // GetConfigAndInit retrieves and initializes the configuration for a specific namespace GetConfigAndInit(namespace string) *storage.Config + // GetConfigCache returns the cache interface for a specific namespace GetConfigCache(namespace string) agcache.CacheInterface + // GetDefaultConfigCache returns the cache interface for the default namespace GetDefaultConfigCache() agcache.CacheInterface + // GetApolloConfigCache returns the cache interface for Apollo configurations GetApolloConfigCache() agcache.CacheInterface + // GetValue retrieves a configuration value by key GetValue(key string) string + // GetStringValue retrieves a string configuration value with default fallback GetStringValue(key string, defaultValue string) string + // GetIntValue retrieves an integer configuration value with default fallback GetIntValue(key string, defaultValue int) int + // GetFloatValue retrieves a float configuration value with default fallback GetFloatValue(key string, defaultValue float64) float64 + // GetBoolValue retrieves a boolean configuration value with default fallback GetBoolValue(key string, defaultValue bool) bool + // GetStringSliceValue retrieves a string slice configuration value with default fallback GetStringSliceValue(key string, defaultValue []string) []string + // GetIntSliceValue retrieves an integer slice configuration value with default fallback GetIntSliceValue(key string, defaultValue []int) []int + // AddChangeListener adds a listener for configuration changes AddChangeListener(listener storage.ChangeListener) + // RemoveChangeListener removes a configuration change listener RemoveChangeListener(listener storage.ChangeListener) + // GetChangeListeners returns the list of configuration change listeners GetChangeListeners() *list.List + // UseEventDispatch enables event dispatch for configuration changes UseEventDispatch() + // Close stops the configuration polling Close() } -// internalClient apollo 客户端实例 +// internalClient represents the internal implementation of the Apollo client type internalClient struct { - initAppConfigFunc func() (*config.AppConfig, error) + initAppConfigFunc func() (*config.AppConfig, error) // nolint: unused appConfig *config.AppConfig cache *storage.Cache configComponent *notify.ConfigComponent } +// getAppConfig returns the current application configuration func (c *internalClient) getAppConfig() config.AppConfig { return *c.appConfig } +// create initializes a new internal client instance func create() *internalClient { appConfig := env.InitFileConfig() return &internalClient{ @@ -98,14 +121,17 @@ func create() *internalClient { } } -// Start 根据默认文件启动 +// Start initializes the Apollo client with default configuration +// Returns a Client interface and any error that occurred during initialization func Start() (Client, error) { return StartWithConfig(nil) } -// StartWithConfig 根据配置启动 +// StartWithConfig initializes the Apollo client with custom configuration +// loadAppConfig is a function that provides custom application configuration +// Returns a Client interface and any error that occurred during initialization func StartWithConfig(loadAppConfig func() (*config.AppConfig, error)) (Client, error) { - // 有了配置之后才能进行初始化 + // Initialize configuration appConfig, err := env.InitConfig(loadAppConfig) if err != nil { return nil, err @@ -119,21 +145,23 @@ func StartWithConfig(loadAppConfig func() (*config.AppConfig, error)) (Client, e c.cache = storage.CreateNamespaceConfig(appConfig.NamespaceName) appConfig.Init() + // Initialize server list synchronization serverlist.InitSyncServerIPList(c.getAppConfig) - //first sync + // First synchronization of configurations configs := syncApolloConfig.Sync(c.getAppConfig) if len(configs) == 0 && appConfig != nil && appConfig.MustStart { return nil, errors.New("start failed cause no config was read") } + // Update cache with synchronized configurations for _, apolloConfig := range configs { c.cache.UpdateApolloConfig(apolloConfig, c.getAppConfig) } log.Debug("init notifySyncConfigServices finished") - //start long poll sync config + // Start long polling for configuration updates configComponent := ¬ify.ConfigComponent{} configComponent.SetAppConfig(c.getAppConfig) configComponent.SetCache(c.cache) @@ -145,12 +173,15 @@ func StartWithConfig(loadAppConfig func() (*config.AppConfig, error)) (Client, e return c, nil } -// GetConfig 根据namespace获取apollo配置 +// GetConfig retrieves the configuration for a specific namespace +// If the namespace is empty, returns nil func (c *internalClient) GetConfig(namespace string) *storage.Config { return c.GetConfigAndInit(namespace) } -// GetConfigAndInit 根据namespace获取apollo配置 +// GetConfigAndInit retrieves and initializes the configuration for a specific namespace +// If the configuration doesn't exist, it will synchronize with the Apollo server +// Returns nil if the namespace is empty func (c *internalClient) GetConfigAndInit(namespace string) *storage.Config { if namespace == "" { return nil @@ -159,7 +190,7 @@ func (c *internalClient) GetConfigAndInit(namespace string) *storage.Config { cfg := c.cache.GetConfig(namespace) if cfg == nil { - //sync config + // Synchronize configuration from Apollo server apolloConfig := syncApolloConfig.SyncWithNamespace(namespace, c.getAppConfig) if apolloConfig != nil { c.SyncAndUpdate(namespace, apolloConfig) @@ -171,8 +202,10 @@ func (c *internalClient) GetConfigAndInit(namespace string) *storage.Config { return cfg } +// SyncAndUpdate synchronizes and updates the configuration for a specific namespace +// It updates the appConfig, notification map, and cache with the new configuration func (c *internalClient) SyncAndUpdate(namespace string, apolloConfig *config.ApolloConfig) { - // update appConfig only if namespace does not exist yet + // Update appConfig only if namespace does not exist yet namespaces := strings.Split(c.appConfig.NamespaceName, ",") exists := false for _, n := range namespaces { @@ -185,14 +218,15 @@ func (c *internalClient) SyncAndUpdate(namespace string, apolloConfig *config.Ap c.appConfig.NamespaceName += "," + namespace } - // update notification + // Update notification map c.appConfig.GetNotificationsMap().UpdateNotify(namespace, 0) - // update cache + // Update cache with new configuration c.cache.UpdateApolloConfig(apolloConfig, c.getAppConfig) } -// GetConfigCache 根据namespace获取apollo配置的缓存 +// GetConfigCache returns the cache interface for a specific namespace +// Returns nil if the configuration doesn't exist func (c *internalClient) GetConfigCache(namespace string) agcache.CacheInterface { config := c.GetConfigAndInit(namespace) if config == nil { @@ -202,7 +236,8 @@ func (c *internalClient) GetConfigCache(namespace string) agcache.CacheInterface return config.GetCache() } -// GetDefaultConfigCache 获取默认缓存 +// GetDefaultConfigCache returns the cache interface for the default namespace +// Returns nil if the default configuration doesn't exist func (c *internalClient) GetDefaultConfigCache() agcache.CacheInterface { config := c.GetConfigAndInit(storage.GetDefaultNamespace()) if config != nil { @@ -211,46 +246,58 @@ func (c *internalClient) GetDefaultConfigCache() agcache.CacheInterface { return nil } -// GetApolloConfigCache 获取默认namespace的apollo配置 +// GetApolloConfigCache returns the cache interface for Apollo configurations +// This is an alias for GetDefaultConfigCache func (c *internalClient) GetApolloConfigCache() agcache.CacheInterface { return c.GetDefaultConfigCache() } -// GetValue 获取配置 +// GetValue retrieves a configuration value by key from the default namespace +// Returns the value as a string func (c *internalClient) GetValue(key string) string { return c.GetConfig(storage.GetDefaultNamespace()).GetValue(key) } -// GetStringValue 获取string配置值 +// GetStringValue retrieves a string configuration value with default fallback +// Returns the default value if the key doesn't exist func (c *internalClient) GetStringValue(key string, defaultValue string) string { return c.GetConfig(storage.GetDefaultNamespace()).GetStringValue(key, defaultValue) } -// GetIntValue 获取int配置值 +// GetIntValue retrieves an integer configuration value with default fallback +// Returns the default value if the key doesn't exist or cannot be converted to int func (c *internalClient) GetIntValue(key string, defaultValue int) int { return c.GetConfig(storage.GetDefaultNamespace()).GetIntValue(key, defaultValue) } -// GetFloatValue 获取float配置值 +// GetFloatValue retrieves a float configuration value with default fallback +// Returns the default value if the key doesn't exist or cannot be converted to float func (c *internalClient) GetFloatValue(key string, defaultValue float64) float64 { return c.GetConfig(storage.GetDefaultNamespace()).GetFloatValue(key, defaultValue) } -// GetBoolValue 获取bool 配置值 +// GetBoolValue retrieves a boolean configuration value with default fallback +// Returns the default value if the key doesn't exist or cannot be converted to bool func (c *internalClient) GetBoolValue(key string, defaultValue bool) bool { return c.GetConfig(storage.GetDefaultNamespace()).GetBoolValue(key, defaultValue) } -// GetStringSliceValue 获取[]string 配置值 +// GetStringSliceValue retrieves a string slice configuration value with default fallback +// The values are split by the separator constant +// Returns the default value if the key doesn't exist func (c *internalClient) GetStringSliceValue(key string, defaultValue []string) []string { return c.GetConfig(storage.GetDefaultNamespace()).GetStringSliceValue(key, separator, defaultValue) } -// GetIntSliceValue 获取[]int 配置值 +// GetIntSliceValue retrieves an integer slice configuration value with default fallback +// The values are split by the separator constant +// Returns the default value if the key doesn't exist or values cannot be converted to integers func (c *internalClient) GetIntSliceValue(key string, defaultValue []int) []int { return c.GetConfig(storage.GetDefaultNamespace()).GetIntSliceValue(key, separator, defaultValue) } +// getConfigValue retrieves a raw configuration value from the default namespace cache +// Returns utils.Empty if the key doesn't exist or there's an error func (c *internalClient) getConfigValue(key string) interface{} { cache := c.GetDefaultConfigCache() if cache == nil { @@ -266,27 +313,32 @@ func (c *internalClient) getConfigValue(key string) interface{} { return value } -// AddChangeListener 增加变更监控 +// AddChangeListener adds a listener for configuration changes +// The listener will be notified when configuration changes occur func (c *internalClient) AddChangeListener(listener storage.ChangeListener) { c.cache.AddChangeListener(listener) } -// RemoveChangeListener 增加变更监控 +// RemoveChangeListener removes a configuration change listener +// The listener will no longer receive configuration change notifications func (c *internalClient) RemoveChangeListener(listener storage.ChangeListener) { c.cache.RemoveChangeListener(listener) } -// GetChangeListeners 获取配置修改监听器列表 +// GetChangeListeners returns the list of configuration change listeners +// Returns a list.List containing all registered listeners func (c *internalClient) GetChangeListeners() *list.List { return c.cache.GetChangeListeners() } -// UseEventDispatch 添加为某些key分发event功能 +// UseEventDispatch enables event dispatch for configuration changes +// This will add a default event dispatcher as a change listener func (c *internalClient) UseEventDispatch() { c.AddChangeListener(storage.UseEventDispatch()) } -// Close 停止轮询 +// Close stops the configuration polling and cleanup resources +// This should be called when the client is no longer needed func (c *internalClient) Close() { c.configComponent.Stop() } diff --git a/cluster/load_balance.go b/cluster/load_balance.go index e261fb8f..204cd36c 100644 --- a/cluster/load_balance.go +++ b/cluster/load_balance.go @@ -18,8 +18,21 @@ import ( "github.com/apolloconfig/agollo/v4/env/config" ) -// LoadBalance 负载均衡器 +// LoadBalance defines the interface for load balancing strategies. +// Implementations of this interface can provide different algorithms +// for distributing load across multiple Apollo configuration servers. type LoadBalance interface { - //Load 负载均衡,获取对应服务信息 + // Load performs server selection based on the implemented load balancing strategy + // Parameters: + // - servers: A map of server addresses to their corresponding ServerInfo objects + // + // Returns: + // - *config.ServerInfo: The selected server based on the load balancing algorithm + // Returns nil if no available server is found + // + // This method should handle server selection logic including: + // - Checking server availability + // - Implementing specific load balancing algorithms (e.g., round-robin, weighted random) + // - Handling failure scenarios Load(servers map[string]*config.ServerInfo) *config.ServerInfo } diff --git a/cluster/roundrobin/round_robin.go b/cluster/roundrobin/round_robin.go index 6c9ce4d4..611e0e92 100644 --- a/cluster/roundrobin/round_robin.go +++ b/cluster/roundrobin/round_robin.go @@ -18,11 +18,23 @@ import ( "github.com/apolloconfig/agollo/v4/env/config" ) -// RoundRobin 轮询调度 +// RoundRobin implements a simple round-robin load balancing strategy. +// This implementation currently provides a basic server selection mechanism +// that returns the first available server from the server list. type RoundRobin struct { } -// Load 负载均衡 +// Load performs load balancing across the provided servers +// Parameters: +// - servers: A map of server addresses to their corresponding ServerInfo objects +// +// Returns: +// - *config.ServerInfo: The selected server for the current request +// Returns nil if no available server is found +// +// Note: The current implementation selects the first available server +// that is not marked as down. A more sophisticated round-robin algorithm +// could be implemented to ensure better load distribution. func (r *RoundRobin) Load(servers map[string]*config.ServerInfo) *config.ServerInfo { var returnServer *config.ServerInfo for _, server := range servers { diff --git a/component/common.go b/component/common.go index b65c5b27..940b1b51 100644 --- a/component/common.go +++ b/component/common.go @@ -14,12 +14,21 @@ package component -// AbsComponent 定时组件 +// AbsComponent defines the interface for components that require periodic execution +// This interface is used by various Apollo components that need to run continuously +// or on a scheduled basis, such as configuration synchronization and server list updates type AbsComponent interface { + // Start initiates the component's main execution loop + // Implementations should handle their own scheduling and error recovery Start() } -// StartRefreshConfig 开始定时服务 +// StartRefreshConfig begins the execution of a periodic component +// Parameters: +// - component: An implementation of AbsComponent that needs to be started +// +// This function is responsible for initiating the component's execution cycle +// and is typically called during system initialization func StartRefreshConfig(component AbsComponent) { component.Start() } diff --git a/component/log/log.go b/component/log/log.go index 729979fb..3dd80724 100644 --- a/component/log/log.go +++ b/component/log/log.go @@ -14,113 +14,141 @@ package log -// Logger logger 对象 +// Logger is the global logger instance used throughout the application var Logger LoggerInterface func init() { Logger = &DefaultLogger{} } -// InitLogger 初始化logger对象 +// InitLogger initializes the logger with a custom implementation +// Parameters: +// - ILogger: The logger implementation to be used func InitLogger(ILogger LoggerInterface) { Logger = ILogger } -// LoggerInterface 日志接口 +// LoggerInterface defines the contract for logger implementations +// This interface provides methods for different logging levels and formats type LoggerInterface interface { + // Debugf logs debug messages with formatting Debugf(format string, params ...interface{}) + // Infof logs information messages with formatting Infof(format string, params ...interface{}) + // Warnf logs warning messages with formatting Warnf(format string, params ...interface{}) + // Errorf logs error messages with formatting Errorf(format string, params ...interface{}) + // Debug logs debug messages Debug(v ...interface{}) + // Info logs information messages Info(v ...interface{}) + // Warn logs warning messages Warn(v ...interface{}) + // Error logs error messages Error(v ...interface{}) } -// Debugf debug 格式化 +// Debugf formats and logs a debug message using the global logger +// Parameters: +// - format: The format string +// - params: The parameters to be formatted func Debugf(format string, params ...interface{}) { Logger.Debugf(format, params...) } -// Infof 打印info +// Infof formats and logs an information message using the global logger +// Parameters: +// - format: The format string +// - params: The parameters to be formatted func Infof(format string, params ...interface{}) { Logger.Infof(format, params...) } -// Warnf warn格式化 +// Warnf formats and logs a warning message using the global logger +// Parameters: +// - format: The format string +// - params: The parameters to be formatted func Warnf(format string, params ...interface{}) { Logger.Warnf(format, params...) } -// Errorf error格式化 +// Errorf formats and logs an error message using the global logger +// Parameters: +// - format: The format string +// - params: The parameters to be formatted func Errorf(format string, params ...interface{}) { Logger.Errorf(format, params...) } -// Debug 打印debug +// Debug logs a debug message using the global logger +// Parameters: +// - v: The values to be logged func Debug(v ...interface{}) { Logger.Debug(v...) } -// Info 打印Info +// Info logs an information message using the global logger +// Parameters: +// - v: The values to be logged func Info(v ...interface{}) { Logger.Info(v...) } -// Warn 打印Warn +// Warn logs a warning message using the global logger +// Parameters: +// - v: The values to be logged func Warn(v ...interface{}) { Logger.Warn(v...) } -// Error 打印Error +// Error logs an error message using the global logger +// Parameters: +// - v: The values to be logged func Error(v ...interface{}) { Logger.Error(v...) } -// DefaultLogger 默认日志实现 +// DefaultLogger provides a basic implementation of the LoggerInterface +// This implementation is used as a fallback when no custom logger is provided type DefaultLogger struct { } -// Debugf debug 格式化 +// Debugf implements debug level formatted logging (empty implementation) func (d *DefaultLogger) Debugf(format string, params ...interface{}) { - } -// Infof 打印info +// Infof implements info level formatted logging (empty implementation) func (d *DefaultLogger) Infof(format string, params ...interface{}) { - } -// Warnf warn格式化 +// Warnf implements warning level formatted logging (empty implementation) func (d *DefaultLogger) Warnf(format string, params ...interface{}) { } -// Errorf error格式化 +// Errorf implements error level formatted logging (empty implementation) func (d *DefaultLogger) Errorf(format string, params ...interface{}) { } -// Debug 打印debug +// Debug implements debug level logging (empty implementation) func (d *DefaultLogger) Debug(v ...interface{}) { - } -// Info 打印Info +// Info implements info level logging (empty implementation) func (d *DefaultLogger) Info(v ...interface{}) { - } -// Warn 打印Warn +// Warn implements warning level logging (empty implementation) func (d *DefaultLogger) Warn(v ...interface{}) { } -// Error 打印Error +// Error implements error level logging (empty implementation) func (d *DefaultLogger) Error(v ...interface{}) { } diff --git a/component/notify/componet_notify.go b/component/notify/componet_notify.go index ee4e4767..f042a5b0 100644 --- a/component/notify/componet_notify.go +++ b/component/notify/componet_notify.go @@ -23,27 +23,42 @@ import ( ) const ( - longPollInterval = 2 * time.Second //2s + // longPollInterval defines the interval for long polling operations + // The client will check for configuration updates every 2 seconds + longPollInterval = 2 * time.Second ) -// ConfigComponent 配置组件 +// ConfigComponent handles the configuration synchronization process +// It maintains a long-polling mechanism to fetch updates from Apollo server type ConfigComponent struct { + // appConfigFunc is a function that returns the current application configuration appConfigFunc func() config.AppConfig - cache *storage.Cache - stopCh chan interface{} + // cache stores the configuration data + cache *storage.Cache + // stopCh is used to signal the termination of the polling process + stopCh chan interface{} } -// SetAppConfig nolint +// SetAppConfig sets the function that provides application configuration +// Parameters: +// - appConfigFunc: A function that returns the current AppConfig func (c *ConfigComponent) SetAppConfig(appConfigFunc func() config.AppConfig) { c.appConfigFunc = appConfigFunc } -// SetCache nolint +// SetCache sets the cache instance for storing configuration data +// Parameters: +// - cache: The storage cache instance to be used func (c *ConfigComponent) SetCache(cache *storage.Cache) { c.cache = cache } -// Start 启动配置组件定时器 +// Start initiates the configuration synchronization process +// This method: +// 1. Initializes the stop channel if not already initialized +// 2. Creates a timer for periodic synchronization +// 3. Starts a loop that continuously checks for configuration updates +// 4. Updates the local cache when new configurations are received func (c *ConfigComponent) Start() { if c.stopCh == nil { c.stopCh = make(chan interface{}) @@ -67,7 +82,8 @@ loop: } } -// Stop 停止配置组件定时器 +// Stop terminates the configuration synchronization process +// This method closes the stop channel, which will cause the polling loop to exit func (c *ConfigComponent) Stop() { if c.stopCh != nil { close(c.stopCh) diff --git a/component/remote/abs.go b/component/remote/abs.go index ca249304..ab12abb1 100644 --- a/component/remote/abs.go +++ b/component/remote/abs.go @@ -23,11 +23,26 @@ import ( "github.com/apolloconfig/agollo/v4/protocol/http" ) -// AbsApolloConfig 抽象 apollo 配置 +// AbsApolloConfig represents an abstract Apollo configuration handler +// It provides base functionality for interacting with Apollo configuration server type AbsApolloConfig struct { + // remoteApollo is the interface for remote Apollo operations remoteApollo ApolloConfig } +// SyncWithNamespace synchronizes configuration for a specific namespace from Apollo server +// Parameters: +// - namespace: The configuration namespace to sync +// - appConfigFunc: Function that provides the application configuration +// +// Returns: +// - *config.ApolloConfig: The synchronized configuration, or nil if sync fails +// +// This method: +// 1. Validates the input parameters +// 2. Constructs the connection configuration +// 3. Makes HTTP request to Apollo server +// 4. Handles any errors during synchronization func (a *AbsApolloConfig) SyncWithNamespace(namespace string, appConfigFunc func() config.AppConfig) *config.ApolloConfig { if appConfigFunc == nil { panic("can not find apollo config!please confirm!") @@ -35,6 +50,7 @@ func (a *AbsApolloConfig) SyncWithNamespace(namespace string, appConfigFunc func appConfig := appConfigFunc() urlSuffix := a.remoteApollo.GetSyncURI(appConfig, namespace) + // Configure connection parameters for Apollo server c := &env.ConnectConfig{ URI: urlSuffix, AppID: appConfig.AppID, @@ -42,10 +58,12 @@ func (a *AbsApolloConfig) SyncWithNamespace(namespace string, appConfigFunc func Timeout: notifyConnectTimeout, IsRetry: true, } + // Override timeout if specified in application config if appConfig.SyncServerTimeout > 0 { c.Timeout = time.Duration(appConfig.SyncServerTimeout) * time.Second } + // Execute synchronization request with error recovery callback := a.remoteApollo.CallBack(namespace) apolloConfig, err := http.RequestRecovery(appConfig, c, &callback) if err != nil { diff --git a/component/remote/async.go b/component/remote/async.go index 1bdd978f..57862235 100644 --- a/component/remote/async.go +++ b/component/remote/async.go @@ -31,23 +31,36 @@ import ( ) const ( - //notify timeout - notifyConnectTimeout = 10 * time.Minute //10m + // notifyConnectTimeout defines the timeout duration for notification connections + // Default value is 10 minutes to maintain long polling connections + notifyConnectTimeout = 10 * time.Minute + // defaultContentKey is the key used to store configuration content defaultContentKey = "content" ) -// CreateAsyncApolloConfig 创建异步 apollo 配置 +// CreateAsyncApolloConfig creates and initializes a new asynchronous Apollo configuration instance +// Returns: +// - ApolloConfig: A new instance of asyncApolloConfig func CreateAsyncApolloConfig() ApolloConfig { a := &asyncApolloConfig{} a.remoteApollo = a return a } +// asyncApolloConfig implements asynchronous configuration management for Apollo +// It extends AbsApolloConfig to provide async-specific functionality type asyncApolloConfig struct { AbsApolloConfig } +// GetNotifyURLSuffix constructs the URL suffix for notification API +// Parameters: +// - notifications: JSON string containing notification information +// - config: Application configuration +// +// Returns: +// - string: The constructed URL suffix for notifications endpoint func (*asyncApolloConfig) GetNotifyURLSuffix(notifications string, config config.AppConfig) string { return fmt.Sprintf("notifications/v2?appId=%s&cluster=%s¬ifications=%s", url.QueryEscape(config.AppID), @@ -55,6 +68,13 @@ func (*asyncApolloConfig) GetNotifyURLSuffix(notifications string, config config url.QueryEscape(notifications)) } +// GetSyncURI constructs the URL for synchronizing configuration +// Parameters: +// - config: Application configuration +// - namespaceName: The namespace to sync +// +// Returns: +// - string: The constructed URL for config sync endpoint func (*asyncApolloConfig) GetSyncURI(config config.AppConfig, namespaceName string) string { return fmt.Sprintf("configs/%s/%s/%s?releaseKey=%s&ip=%s&label=%s", url.QueryEscape(config.AppID), @@ -65,6 +85,12 @@ func (*asyncApolloConfig) GetSyncURI(config config.AppConfig, namespaceName stri url.QueryEscape(config.Label)) } +// Sync synchronizes configurations from remote Apollo server +// Parameters: +// - appConfigFunc: Function that provides application configuration +// +// Returns: +// - []*config.ApolloConfig: Array of synchronized Apollo configurations func (a *asyncApolloConfig) Sync(appConfigFunc func() config.AppConfig) []*config.ApolloConfig { appConfig := appConfigFunc() remoteConfigs, err := a.notifyRemoteConfig(appConfigFunc, utils.Empty) @@ -77,7 +103,7 @@ func (a *asyncApolloConfig) Sync(appConfigFunc func() config.AppConfig) []*confi if len(remoteConfigs) == 0 || len(apolloConfigs) > 0 { return apolloConfigs } - //只是拉去有变化的配置, 并更新拉取成功的namespace的notify ID + // just fetch the changed configurations, and update the namespace that has been fetched successfully for _, notifyConfig := range remoteConfigs { apolloConfig := a.SyncWithNamespace(notifyConfig.NamespaceName, appConfigFunc) if apolloConfig != nil { @@ -88,6 +114,12 @@ func (a *asyncApolloConfig) Sync(appConfigFunc func() config.AppConfig) []*confi return apolloConfigs } +// CallBack creates a callback handler for HTTP requests +// Parameters: +// - namespace: The namespace for which the callback is created +// +// Returns: +// - http.CallBack: Callback structure with success and error handlers func (*asyncApolloConfig) CallBack(namespace string) http.CallBack { return http.CallBack{ SuccessCallBack: createApolloConfigWithJSON, @@ -96,6 +128,14 @@ func (*asyncApolloConfig) CallBack(namespace string) http.CallBack { } } +// notifyRemoteConfig handles the long polling notification process +// Parameters: +// - appConfigFunc: Function that provides application configuration +// - namespace: The namespace to monitor +// +// Returns: +// - []*config.Notification: Array of notifications +// - error: Any error that occurred during the process func (a *asyncApolloConfig) notifyRemoteConfig(appConfigFunc func() config.AppConfig, namespace string) ([]*config.Notification, error) { if appConfigFunc == nil { panic("can not find apollo config!please confirm!") @@ -125,10 +165,20 @@ func (a *asyncApolloConfig) notifyRemoteConfig(appConfigFunc func() config.AppCo return notifies.([]*config.Notification), err } +// touchApolloConfigCache is a no-op function for cache touching operations +// Returns: +// - error: Always returns nil func touchApolloConfigCache() error { return nil } +// toApolloConfig converts response body to Apollo notification array +// Parameters: +// - resBody: Raw response body from Apollo server +// +// Returns: +// - []*config.Notification: Parsed notification array +// - error: Any error during parsing func toApolloConfig(resBody []byte) ([]*config.Notification, error) { remoteConfig := make([]*config.Notification, 0) @@ -141,6 +191,13 @@ func toApolloConfig(resBody []byte) ([]*config.Notification, error) { return remoteConfig, nil } +// loadBackupConfig loads configuration from backup files when remote sync fails +// Parameters: +// - namespace: The namespace to load +// - appConfig: Application configuration +// +// Returns: +// - []*config.ApolloConfig: Array of configurations loaded from backup func loadBackupConfig(namespace string, appConfig config.AppConfig) []*config.ApolloConfig { apolloConfigs := make([]*config.ApolloConfig, 0) config.SplitNamespaces(namespace, func(namespace string) { @@ -157,6 +214,20 @@ func loadBackupConfig(namespace string, appConfig config.AppConfig) []*config.Ap return apolloConfigs } +// createApolloConfigWithJSON creates Apollo configuration from JSON response +// Parameters: +// - b: Raw JSON bytes +// - callback: HTTP callback handler +// +// Returns: +// - interface{}: Created Apollo configuration +// - error: Any error during creation +// +// This function: +// 1. Unmarshals JSON into Apollo config +// 2. Determines appropriate parser based on namespace +// 3. Parses configuration content +// 4. Updates configuration map func createApolloConfigWithJSON(b []byte, callback http.CallBack) (o interface{}, err error) { apolloConfig := &config.ApolloConfig{} err = json.Unmarshal(b, apolloConfig) diff --git a/component/remote/remote.go b/component/remote/remote.go index 173e71d7..dfb5624b 100644 --- a/component/remote/remote.go +++ b/component/remote/remote.go @@ -19,16 +19,44 @@ import ( "github.com/apolloconfig/agollo/v4/protocol/http" ) -// ApolloConfig apollo 配置 +// ApolloConfig defines the interface for interacting with Apollo Configuration Center +// This interface provides methods for both synchronous and asynchronous configuration updates type ApolloConfig interface { - // GetNotifyURLSuffix 获取异步更新路径 + // GetNotifyURLSuffix constructs the URL suffix for long polling notifications + // Parameters: + // - notifications: JSON string containing notification information + // - config: Application configuration instance + // Returns: + // - string: The constructed URL suffix for notifications endpoint GetNotifyURLSuffix(notifications string, config config.AppConfig) string - // GetSyncURI 获取同步路径 + + // GetSyncURI constructs the URL for synchronizing configuration + // Parameters: + // - config: Application configuration instance + // - namespaceName: The namespace to synchronize + // Returns: + // - string: The constructed URL for configuration synchronization GetSyncURI(config config.AppConfig, namespaceName string) string - // Sync 同步获取 Apollo 配置 + + // Sync synchronizes all configurations from Apollo server + // Parameters: + // - appConfigFunc: Function that provides application configuration + // Returns: + // - []*config.ApolloConfig: Array of synchronized Apollo configurations Sync(appConfigFunc func() config.AppConfig) []*config.ApolloConfig - // CallBack 根据 namespace 获取 callback 方法 + + // CallBack creates a callback handler for specific namespace + // Parameters: + // - namespace: The namespace for which the callback is created + // Returns: + // - http.CallBack: Callback structure with success and error handlers CallBack(namespace string) http.CallBack - // SyncWithNamespace 通过 namespace 同步 apollo 配置 + + // SyncWithNamespace synchronizes configuration for a specific namespace + // Parameters: + // - namespace: The namespace to synchronize + // - appConfigFunc: Function that provides application configuration + // Returns: + // - *config.ApolloConfig: The synchronized configuration for the specified namespace SyncWithNamespace(namespace string, appConfigFunc func() config.AppConfig) *config.ApolloConfig } diff --git a/component/remote/sync.go b/component/remote/sync.go index 9b4b2f8a..27f2d70e 100644 --- a/component/remote/sync.go +++ b/component/remote/sync.go @@ -28,21 +28,34 @@ import ( "github.com/apolloconfig/agollo/v4/utils" ) -// CreateSyncApolloConfig 创建同步获取 Apollo 配置 +// CreateSyncApolloConfig creates a new instance of synchronous Apollo configuration client +// Returns: +// - ApolloConfig: A new instance of syncApolloConfig func CreateSyncApolloConfig() ApolloConfig { a := &syncApolloConfig{} a.remoteApollo = a return a } +// syncApolloConfig implements synchronous configuration management for Apollo +// It extends AbsApolloConfig to provide sync-specific functionality type syncApolloConfig struct { AbsApolloConfig } +// GetNotifyURLSuffix returns an empty string as notifications are not used in sync mode +// This method is implemented to satisfy the ApolloConfig interface func (*syncApolloConfig) GetNotifyURLSuffix(notifications string, config config.AppConfig) string { return "" } +// GetSyncURI constructs the URL for synchronous configuration retrieval +// Parameters: +// - config: Application configuration instance +// - namespaceName: The namespace to retrieve +// +// Returns: +// - string: The constructed URL for fetching JSON configuration files func (*syncApolloConfig) GetSyncURI(config config.AppConfig, namespaceName string) string { return fmt.Sprintf("configfiles/json/%s/%s/%s?&ip=%s&label=%s", url.QueryEscape(config.AppID), @@ -52,6 +65,12 @@ func (*syncApolloConfig) GetSyncURI(config config.AppConfig, namespaceName strin url.QueryEscape(config.Label)) } +// CallBack creates a callback handler for processing JSON configuration files +// Parameters: +// - namespace: The namespace for which the callback is created +// +// Returns: +// - http.CallBack: Callback structure with JSON processing handlers func (*syncApolloConfig) CallBack(namespace string) http.CallBack { return http.CallBack{ SuccessCallBack: processJSONFiles, @@ -60,6 +79,20 @@ func (*syncApolloConfig) CallBack(namespace string) http.CallBack { } } +// processJSONFiles processes the JSON response from Apollo server +// Parameters: +// - b: Raw JSON bytes from the response +// - callback: Callback containing namespace information +// +// Returns: +// - interface{}: Processed Apollo configuration +// - error: Any error during processing +// +// This function: +// 1. Creates a new Apollo configuration instance +// 2. Unmarshals JSON into configurations +// 3. Applies appropriate format parser based on namespace +// 4. Processes configuration content func processJSONFiles(b []byte, callback http.CallBack) (o interface{}, err error) { apolloConfig := &config.ApolloConfig{} apolloConfig.NamespaceName = callback.Namespace @@ -96,6 +129,17 @@ func processJSONFiles(b []byte, callback http.CallBack) (o interface{}, err erro return apolloConfig, nil } +// Sync synchronizes configurations for all namespaces +// Parameters: +// - appConfigFunc: Function that provides application configuration +// +// Returns: +// - []*config.ApolloConfig: Array of synchronized configurations +// +// This method: +// 1. Retrieves configurations for each namespace +// 2. Falls back to backup configurations if sync fails +// 3. Aggregates all configurations into a single array func (a *syncApolloConfig) Sync(appConfigFunc func() config.AppConfig) []*config.ApolloConfig { appConfig := appConfigFunc() configs := make([]*config.ApolloConfig, 0, 8) diff --git a/component/serverlist/sync.go b/component/serverlist/sync.go index 01794de7..5f2afe81 100644 --- a/component/serverlist/sync.go +++ b/component/serverlist/sync.go @@ -27,26 +27,34 @@ import ( ) const ( - //refresh ip list - refreshIPListInterval = 20 * time.Minute //20m + // refreshIPListInterval defines the interval for refreshing server IP list + // The client will update the server list every 20 minutes + refreshIPListInterval = 20 * time.Minute ) func init() { - } -// InitSyncServerIPList 初始化同步服务器信息列表 +// InitSyncServerIPList initializes the synchronization of server information list +// Parameters: +// - appConfig: Function that provides application configuration +// +// This function starts a goroutine to periodically refresh the server list func InitSyncServerIPList(appConfig func() config.AppConfig) { go component.StartRefreshConfig(&SyncServerIPListComponent{appConfig}) } -// SyncServerIPListComponent set timer for update ip list -// interval : 20m +// SyncServerIPListComponent implements periodic server list synchronization +// It maintains a timer to update the IP list every 20 minutes type SyncServerIPListComponent struct { appConfig func() config.AppConfig } -// Start 启动同步服务器列表 +// Start begins the server list synchronization process +// This method: +// 1. Performs initial synchronization +// 2. Sets up a timer for periodic updates +// 3. Continuously monitors for timer events func (s *SyncServerIPListComponent) Start() { SyncServerIPList(s.appConfig) log.Debug("syncServerIpList started") @@ -91,7 +99,20 @@ func SyncServerIPList(appConfigFunc func() config.AppConfig) (map[string]*config return m, err } -// SyncServerIPListSuccessCallBack 同步服务器列表成功后的回调 +// SyncServerIPListSuccessCallBack handles the successful response from server list synchronization +// Parameters: +// - responseBody: Raw response bytes from the server +// - callback: HTTP callback handler containing context information +// +// Returns: +// - interface{}: Map of server information processed from response +// - error: Any error during response processing +// +// This function: +// 1. Logs the received server information +// 2. Unmarshals JSON response into server info structures +// 3. Validates the server list +// 4. Creates a map of servers indexed by homepage URL func SyncServerIPListSuccessCallBack(responseBody []byte, callback http.CallBack) (o interface{}, err error) { log.Debug("get all server info:", string(responseBody)) diff --git a/constant/config_file_format.go b/constant/config_file_format.go index 0a9e8757..46107a3d 100644 --- a/constant/config_file_format.go +++ b/constant/config_file_format.go @@ -14,20 +14,32 @@ package constant -// ConfigFileFormat 配置文件类型 +// ConfigFileFormat represents the supported configuration file formats in Apollo +// It is used to determine the appropriate parser for different configuration file types type ConfigFileFormat string const ( - //Properties Properties + // Properties represents Java properties file format (.properties) + // This format is commonly used for storing key-value pairs in Java applications Properties ConfigFileFormat = ".properties" - //XML XML + + // XML represents XML file format (.xml) + // Used for structured configuration data in XML format XML ConfigFileFormat = ".xml" - //JSON JSON + + // JSON represents JSON file format (.json) + // Used for structured configuration data in JSON format JSON ConfigFileFormat = ".json" - //YML YML + + // YML represents YAML file format (.yml) + // A human-readable format commonly used for configuration files YML ConfigFileFormat = ".yml" - //YAML YAML + + // YAML represents YAML file format (.yaml) + // Alternative extension for YAML format files YAML ConfigFileFormat = ".yaml" - // DEFAULT DEFAULT + + // DEFAULT represents the default format (empty string) + // Used when no specific format is specified or detected DEFAULT ConfigFileFormat = "" ) diff --git a/env/app_config.go b/env/app_config.go index c8b42bf4..cda65b89 100644 --- a/env/app_config.go +++ b/env/app_config.go @@ -25,19 +25,29 @@ import ( ) const ( - appConfigFile = "app.properties" + // appConfigFile defines the default configuration file name + appConfigFile = "app.properties" + // appConfigFilePath defines the environment variable name for custom config path appConfigFilePath = "AGOLLO_CONF" - defaultCluster = "default" + // defaultCluster defines the default cluster name + defaultCluster = "default" + // defaultNamespace defines the default namespace name defaultNamespace = "application" ) var ( + // executeConfigFileOnce ensures thread-safe initialization of config file executor executeConfigFileOnce sync.Once - configFileExecutor config.File + // configFileExecutor handles configuration file operations + configFileExecutor config.File ) -// InitFileConfig 使用文件初始化配置 +// InitFileConfig initializes configuration from the default properties file +// Returns: +// - *config.AppConfig: Initialized configuration object, nil if initialization fails +// +// This function attempts to load configuration using default settings func InitFileConfig() *config.AppConfig { // default use application.properties if initConfig, err := InitConfig(nil); err == nil { @@ -46,13 +56,30 @@ func InitFileConfig() *config.AppConfig { return nil } -// InitConfig 使用指定配置初始化配置 +// InitConfig initializes configuration using a custom loader function +// Parameters: +// - loadAppConfig: Custom function for loading application configuration +// +// Returns: +// - *config.AppConfig: Initialized configuration object +// - error: Any error that occurred during initialization func InitConfig(loadAppConfig func() (*config.AppConfig, error)) (*config.AppConfig, error) { //init config file return getLoadAppConfig(loadAppConfig) } -// set load app config's function +// getLoadAppConfig handles the actual configuration loading process +// Parameters: +// - loadAppConfig: Optional custom function for loading application configuration +// +// Returns: +// - *config.AppConfig: Loaded configuration object +// - error: Any error that occurred during loading +// +// This function: +// 1. Uses custom loader if provided +// 2. Falls back to environment variable for config path +// 3. Uses default config file if no custom path is specified func getLoadAppConfig(loadAppConfig func() (*config.AppConfig, error)) (*config.AppConfig, error) { if loadAppConfig != nil { return loadAppConfig() @@ -69,7 +96,11 @@ func getLoadAppConfig(loadAppConfig func() (*config.AppConfig, error)) (*config. return c.(*config.AppConfig), e } -// GetConfigFileExecutor 获取文件执行器 +// GetConfigFileExecutor returns a singleton instance of the configuration file executor +// Returns: +// - config.File: Thread-safe instance of configuration file executor +// +// This function ensures the executor is initialized only once using sync.Once func GetConfigFileExecutor() config.File { executeConfigFileOnce.Do(func() { configFileExecutor = &jsonConfig.ConfigFile{} @@ -77,7 +108,19 @@ func GetConfigFileExecutor() config.File { return configFileExecutor } -// Unmarshal 反序列化 +// Unmarshal deserializes configuration data from bytes into AppConfig structure +// Parameters: +// - b: Byte array containing configuration data +// +// Returns: +// - interface{}: Unmarshaled configuration object +// - error: Any error that occurred during unmarshaling +// +// This function: +// 1. Creates AppConfig with default values +// 2. Unmarshals JSON data into the config +// 3. Initializes the configuration +// 4. Returns the initialized config object func Unmarshal(b []byte) (interface{}, error) { appConfig := &config.AppConfig{ Cluster: defaultCluster, diff --git a/env/config/apollo_config.go b/env/config/apollo_config.go index 4ff59c37..8855b72e 100644 --- a/env/config/apollo_config.go +++ b/env/config/apollo_config.go @@ -20,20 +20,28 @@ import ( "github.com/apolloconfig/agollo/v4/utils" ) -// CurrentApolloConfig 当前 apollo 返回的配置信息 +// CurrentApolloConfig represents the current configuration information returned by Apollo +// It maintains a thread-safe map of namespace to connection configurations type CurrentApolloConfig struct { - l sync.RWMutex - configs map[string]*ApolloConnConfig + l sync.RWMutex // Lock for thread-safe operations + configs map[string]*ApolloConnConfig // Map of namespace to connection configurations } -// CreateCurrentApolloConfig nolint +// CreateCurrentApolloConfig creates a new instance of CurrentApolloConfig +// Returns: +// - *CurrentApolloConfig: A new instance with initialized configuration map func CreateCurrentApolloConfig() *CurrentApolloConfig { return &CurrentApolloConfig{ configs: make(map[string]*ApolloConnConfig, 1), } } -// SetCurrentApolloConfig 设置apollo配置 +// Set stores the Apollo connection configuration for a specific namespace +// Parameters: +// - namespace: The configuration namespace +// - connConfig: The connection configuration to be stored +// +// Thread-safe operation using mutex lock func (c *CurrentApolloConfig) Set(namespace string, connConfig *ApolloConnConfig) { c.l.Lock() defer c.l.Unlock() @@ -41,7 +49,11 @@ func (c *CurrentApolloConfig) Set(namespace string, connConfig *ApolloConnConfig c.configs[namespace] = connConfig } -// GetCurrentApolloConfig 获取Apollo链接配置 +// Get retrieves all Apollo connection configurations +// Returns: +// - map[string]*ApolloConnConfig: Map of namespace to connection configurations +// +// Thread-safe operation using read lock func (c *CurrentApolloConfig) Get() map[string]*ApolloConnConfig { c.l.RLock() defer c.l.RUnlock() @@ -49,7 +61,14 @@ func (c *CurrentApolloConfig) Get() map[string]*ApolloConnConfig { return c.configs } -// GetCurrentApolloConfigReleaseKey 获取release key +// GetReleaseKey retrieves the release key for a specific namespace +// Parameters: +// - namespace: The configuration namespace +// +// Returns: +// - string: The release key if found, empty string otherwise +// +// Thread-safe operation using read lock func (c *CurrentApolloConfig) GetReleaseKey(namespace string) string { c.l.RLock() defer c.l.RUnlock() @@ -61,22 +80,28 @@ func (c *CurrentApolloConfig) GetReleaseKey(namespace string) string { return config.ReleaseKey } -// ApolloConnConfig apollo链接配置 +// ApolloConnConfig defines the connection configuration for Apollo +// This structure contains the basic information needed to connect to Apollo server type ApolloConnConfig struct { - AppID string `json:"appId"` - Cluster string `json:"cluster"` - NamespaceName string `json:"namespaceName"` - ReleaseKey string `json:"releaseKey"` - sync.RWMutex + AppID string `json:"appId"` // Application ID + Cluster string `json:"cluster"` // Cluster name + NamespaceName string `json:"namespaceName"` // Configuration namespace + ReleaseKey string `json:"releaseKey"` // Release key for version control + sync.RWMutex // Embedded mutex for thread-safe operations } -// ApolloConfig apollo配置 +// ApolloConfig represents a complete Apollo configuration +// It extends ApolloConnConfig with actual configuration values type ApolloConfig struct { - ApolloConnConfig - Configurations map[string]interface{} `json:"configurations"` + ApolloConnConfig // Embedded connection configuration + Configurations map[string]interface{} `json:"configurations"` // Key-value pairs of configurations } -// Init 初始化 +// Init initializes an Apollo configuration with basic connection information +// Parameters: +// - appID: Application identifier +// - cluster: Cluster name +// - namespace: Configuration namespace func (a *ApolloConfig) Init(appID string, cluster string, namespace string) { a.AppID = appID a.Cluster = cluster diff --git a/env/config/config.go b/env/config/config.go index fd42a84c..80150f8d 100644 --- a/env/config/config.go +++ b/env/config/config.go @@ -25,55 +25,74 @@ import ( ) var ( + // defaultNotificationID represents the default notification ID for new configurations defaultNotificationID = int64(-1) - Comma = "," + // Comma is the delimiter used for splitting namespace strings + Comma = "," ) -// File 读写配置文件 +// File defines the interface for reading and writing configuration files type File interface { + // Load reads and unmarshals a configuration file + // Parameters: + // - fileName: Path to the configuration file + // - unmarshal: Function to unmarshal the file content + // Returns: + // - interface{}: Unmarshaled configuration + // - error: Any error that occurred during loading Load(fileName string, unmarshal func([]byte) (interface{}, error)) (interface{}, error) + // Write saves configuration content to a file + // Parameters: + // - content: Configuration content to write + // - configPath: Target file path + // Returns: + // - error: Any error that occurred during writing Write(content interface{}, configPath string) error } -// AppConfig 配置文件 +// AppConfig represents the application configuration for Apollo client type AppConfig struct { - AppID string `json:"appId"` - Cluster string `json:"cluster"` - NamespaceName string `json:"namespaceName"` - IP string `json:"ip"` - IsBackupConfig bool `default:"true" json:"isBackupConfig"` - BackupConfigPath string `json:"backupConfigPath"` - Secret string `json:"secret"` - Label string `json:"label"` - SyncServerTimeout int `json:"syncServerTimeout"` - // MustStart 可用于控制第一次同步必须成功 - MustStart bool `default:"false"` - notificationsMap *notificationsMap - currentConnApolloConfig *CurrentApolloConfig -} - -// ServerInfo 服务器信息 + AppID string `json:"appId"` // Unique identifier for the application + Cluster string `json:"cluster"` // Cluster name (e.g., dev, prod) + NamespaceName string `json:"namespaceName"` // Namespace for configuration isolation + IP string `json:"ip"` // Apollo server IP/host + IsBackupConfig bool `default:"true" json:"isBackupConfig"` // Whether to backup configurations + BackupConfigPath string `json:"backupConfigPath"` // Path for backup configuration files + Secret string `json:"secret"` // Authentication secret + Label string `json:"label"` // Configuration label + SyncServerTimeout int `json:"syncServerTimeout"` // Timeout for server synchronization + // MustStart controls whether the first sync must succeed + MustStart bool `default:"false"` + notificationsMap *notificationsMap // Manages configuration change notifications + currentConnApolloConfig *CurrentApolloConfig // Current Apollo connection configuration +} + +// ServerInfo contains information about an Apollo server instance type ServerInfo struct { - AppName string `json:"appName"` - InstanceID string `json:"instanceId"` - HomepageURL string `json:"homepageUrl"` - IsDown bool `json:"-"` + AppName string `json:"appName"` // Name of the Apollo application + InstanceID string `json:"instanceId"` // Unique identifier for the server instance + HomepageURL string `json:"homepageUrl"` // Base URL of the server + IsDown bool `json:"-"` // Indicates if the server is unavailable } -// GetIsBackupConfig whether backup config after fetch config from apollo -// false : no -// true : yes (default) +// GetIsBackupConfig returns whether to backup configuration after fetching from Apollo +// Returns: +// - bool: true if backup is enabled (default), false otherwise func (a *AppConfig) GetIsBackupConfig() bool { return a.IsBackupConfig } -// GetBackupConfigPath GetBackupConfigPath +// GetBackupConfigPath returns the path where configuration backups are stored +// Returns: +// - string: The configured backup path func (a *AppConfig) GetBackupConfigPath() string { return a.BackupConfigPath } -// GetHost GetHost +// GetHost returns the Apollo server host URL with proper formatting +// Returns: +// - string: The formatted host URL, ensuring it ends with a forward slash func (a *AppConfig) GetHost() string { u, err := url.Parse(a.IP) if err != nil { @@ -85,19 +104,23 @@ func (a *AppConfig) GetHost() string { return u.String() } -// Init 初始化notificationsMap +// Init initializes the AppConfig instance +// This method sets up the current Apollo configuration and notifications map func (a *AppConfig) Init() { a.currentConnApolloConfig = CreateCurrentApolloConfig() a.initAllNotifications(nil) } -// Notification 用于保存 apollo Notification 信息 +// Notification represents a configuration change notification from Apollo type Notification struct { NamespaceName string `json:"namespaceName"` NotificationID int64 `json:"notificationId"` } -// InitAllNotifications 初始化notificationsMap +// initAllNotifications initializes the notifications map for all configured namespaces +// Parameters: +// - callback: Optional function to be executed for each namespace during initialization +// The callback can be used for custom processing of each namespace func (a *AppConfig) initAllNotifications(callback func(namespace string)) { ns := SplitNamespaces(a.NamespaceName, callback) a.notificationsMap = ¬ificationsMap{ @@ -105,7 +128,18 @@ func (a *AppConfig) initAllNotifications(callback func(namespace string)) { } } -// SplitNamespaces 根据namespace字符串分割后,并执行callback函数 +// SplitNamespaces splits a comma-separated namespace string and initializes notifications +// Parameters: +// - namespacesStr: Comma-separated string of namespace names +// - callback: Optional function to be executed for each namespace after splitting +// +// Returns: +// - sync.Map: Thread-safe map containing namespace names as keys and defaultNotificationID as values +// +// This function: +// 1. Splits the input string by comma +// 2. Processes each namespace individually +// 3. Initializes each namespace with default notification ID func SplitNamespaces(namespacesStr string, callback func(namespace string)) sync.Map { namespaces := sync.Map{} split := strings.Split(namespacesStr, Comma) @@ -118,12 +152,23 @@ func SplitNamespaces(namespacesStr string, callback func(namespace string)) sync return namespaces } -// GetNotificationsMap 获取notificationsMap +// GetNotificationsMap returns the notifications map for the application +// Returns: +// - *notificationsMap: Thread-safe map containing all namespace notifications +// +// This map is used to track configuration changes across different namespaces func (a *AppConfig) GetNotificationsMap() *notificationsMap { return a.notificationsMap } -// GetServicesConfigURL 获取服务器列表url +// GetServicesConfigURL constructs the URL for fetching service configurations +// Returns: +// - string: Complete URL with proper encoding for accessing Apollo configuration services +// +// The URL includes: +// 1. Base host URL +// 2. Application ID +// 3. Client IP address func (a *AppConfig) GetServicesConfigURL() string { return fmt.Sprintf("%sservices/config?appId=%s&ip=%s", a.GetHost(), @@ -143,9 +188,12 @@ func (a *AppConfig) GetCurrentApolloConfig() *CurrentApolloConfig { // map[string]int64 type notificationsMap struct { - notifications sync.Map + notifications sync.Map // Thread-safe map storing notification IDs by namespace } +// UpdateAllNotifications updates notification IDs for multiple configurations +// Parameters: +// - remoteConfigs: Array of notifications from the remote server func (n *notificationsMap) UpdateAllNotifications(remoteConfigs []*Notification) { for _, remoteConfig := range remoteConfigs { if remoteConfig.NamespaceName == "" { @@ -192,6 +240,13 @@ func (n *notificationsMap) GetNotifications() sync.Map { return n.notifications } +// GetNotifies returns a JSON string of notifications for the specified namespace +// If namespace is empty, returns notifications for all namespaces +// Parameters: +// - namespace: Target namespace, or empty string for all namespaces +// +// Returns: +// - string: JSON representation of notifications func (n *notificationsMap) GetNotifies(namespace string) string { notificationArr := make([]*Notification, 0) if namespace == "" { diff --git a/env/config/json/json_config.go b/env/config/json/json_config.go index 0cf30412..49c688b6 100644 --- a/env/config/json/json_config.go +++ b/env/config/json/json_config.go @@ -24,11 +24,19 @@ import ( "github.com/apolloconfig/agollo/v4/utils" ) -// ConfigFile json文件读写 +// ConfigFile implements JSON file read and write operations for Apollo configuration +// This type provides methods to load and save Apollo configurations in JSON format type ConfigFile struct { } -// Load json文件读 +// Load reads and parses a JSON configuration file +// Parameters: +// - fileName: The path to the JSON configuration file +// - unmarshal: A function that defines how to unmarshal the file content +// +// Returns: +// - interface{}: The parsed configuration object +// - error: Any error that occurred during reading or parsing func (t *ConfigFile) Load(fileName string, unmarshal func([]byte) (interface{}, error)) (interface{}, error) { fs, err := ioutil.ReadFile(fileName) if err != nil { @@ -44,7 +52,18 @@ func (t *ConfigFile) Load(fileName string, unmarshal func([]byte) (interface{}, return config, nil } -// Write json文件写 +// Write saves Apollo configuration to a JSON file +// Parameters: +// - content: The configuration content to be written +// - configPath: The target file path where the configuration will be saved +// +// Returns: +// - error: Any error that occurred during the write operation +// +// This method: +// 1. Validates the input content +// 2. Creates or overwrites the target file +// 3. Encodes the content as JSON func (t *ConfigFile) Write(content interface{}, configPath string) error { if content == nil { log.Error("content is null can not write backup file") diff --git a/env/file/file_handler.go b/env/file/file_handler.go index 1968a2b9..93129636 100644 --- a/env/file/file_handler.go +++ b/env/file/file_handler.go @@ -18,9 +18,33 @@ import ( "github.com/apolloconfig/agollo/v4/env/config" ) -// FileHandler 备份文件读写 +// FileHandler defines the interface for handling Apollo configuration file operations +// This interface provides methods for reading, writing, and managing configuration files type FileHandler interface { + // WriteConfigFile writes Apollo configuration to a backup file + // Parameters: + // - config: Apollo configuration to be written + // - configPath: Target path for the configuration file + // Returns: + // - error: Any error that occurred during the write operation WriteConfigFile(config *config.ApolloConfig, configPath string) error + + // GetConfigFile constructs the configuration file path + // Parameters: + // - configDir: Base directory for configuration files + // - appID: Application identifier + // - namespace: Configuration namespace + // Returns: + // - string: Complete file path for the configuration file GetConfigFile(configDir string, appID string, namespace string) string + + // LoadConfigFile reads and parses an Apollo configuration file + // Parameters: + // - configDir: Base directory for configuration files + // - appID: Application identifier + // - namespace: Configuration namespace + // Returns: + // - *config.ApolloConfig: Parsed configuration object + // - error: Any error that occurred during loading LoadConfigFile(configDir string, appID string, namespace string) (*config.ApolloConfig, error) } diff --git a/env/file/json/json.go b/env/file/json/json.go index 5796b283..f6055cb0 100644 --- a/env/file/json/json.go +++ b/env/file/json/json.go @@ -26,28 +26,38 @@ import ( jsonConfig "github.com/apolloconfig/agollo/v4/env/config/json" ) -// Suffix 默认文件保存类型 +// Suffix defines the default file extension for JSON configuration files const Suffix = ".json" var ( - //jsonFileConfig 处理文件的json格式存取 + // jsonFileConfig handles JSON format file operations for configurations jsonFileConfig = &jsonConfig.ConfigFile{} - //configFileMap 存取namespace文件地址 + + // configFileMap stores the mapping between namespace and file paths + // Key: "{appID}-{namespace}", Value: full file path configFileMap = make(map[string]string, 1) - //configFileMapLock configFileMap的读取锁 + + // configFileMapLock provides thread-safe access to configFileMap configFileMapLock sync.Mutex - //configFileDirMap 存取 configFileDir 文件所在地址,用于判断是否已经存在目录 + // configFileDirMap caches directory existence status + // Key: directory path, Value: whether directory exists configFileDirMap = make(map[string]bool, 1) - //configFileDirMapLock configFileDirMap的读取锁 + + // configFileDirMapLock provides thread-safe access to configFileDirMap configFileDirMapLock sync.Mutex ) -// FileHandler 默认备份文件读写 +// FileHandler implements the default backup file operations for Apollo configurations type FileHandler struct { } -// WriteConfigFile write config to file +// createDir ensures the configuration directory exists +// Parameters: +// - configPath: Target directory path to create +// +// Returns: +// - error: Any error that occurred during directory creation func (fileHandler *FileHandler) createDir(configPath string) error { if configPath == "" { return nil @@ -66,7 +76,13 @@ func (fileHandler *FileHandler) createDir(configPath string) error { return nil } -// WriteConfigFile write config to file +// WriteConfigFile writes Apollo configuration to a JSON file +// Parameters: +// - config: Apollo configuration to be written +// - configPath: Target directory path for the configuration file +// +// Returns: +// - error: Any error that occurred during the write operation func (fileHandler *FileHandler) WriteConfigFile(config *config.ApolloConfig, configPath string) error { err := fileHandler.createDir(configPath) if err != nil { @@ -75,7 +91,16 @@ func (fileHandler *FileHandler) WriteConfigFile(config *config.ApolloConfig, con return jsonFileConfig.Write(config, fileHandler.GetConfigFile(configPath, config.AppID, config.NamespaceName)) } -// GetConfigFile get real config file +// GetConfigFile generates and caches the full configuration file path +// Parameters: +// - configDir: Base directory for configuration files +// - appID: Application identifier +// - namespace: Configuration namespace +// +// Returns: +// - string: Complete file path for the configuration file +// +// Thread-safe operation using mutex lock func (fileHandler *FileHandler) GetConfigFile(configDir string, appID string, namespace string) string { key := fmt.Sprintf("%s-%s", appID, namespace) configFileMapLock.Lock() @@ -92,7 +117,20 @@ func (fileHandler *FileHandler) GetConfigFile(configDir string, appID string, na return configFileMap[namespace] } -// LoadConfigFile load config from file +// LoadConfigFile reads and parses an Apollo configuration from JSON file +// Parameters: +// - configDir: Base directory for configuration files +// - appID: Application identifier +// - namespace: Configuration namespace +// +// Returns: +// - *config.ApolloConfig: Parsed configuration object +// - error: Any error that occurred during loading +// +// This method: +// 1. Constructs the file path +// 2. Reads the JSON file +// 3. Decodes the content into ApolloConfig structure func (fileHandler *FileHandler) LoadConfigFile(configDir string, appID string, namespace string) (*config.ApolloConfig, error) { configFilePath := fileHandler.GetConfigFile(configDir, appID, namespace) log.Infof("load config file from: %s", configFilePath) diff --git a/env/file/json/raw.go b/env/file/json/raw.go index c80bd851..692f864a 100644 --- a/env/file/json/raw.go +++ b/env/file/json/raw.go @@ -25,15 +25,31 @@ import ( ) var ( - raw file.FileHandler + // raw is the singleton instance of FileHandler for raw file operations + raw file.FileHandler + // rawOnce ensures thread-safe initialization of the raw FileHandler rawOnce sync.Once ) -// rawFileHandler 写入备份文件时,同时写入原始内容和namespace类型 +// rawFileHandler extends FileHandler to write both raw content and namespace type +// when backing up configuration files. It provides functionality to store +// configurations in their original format alongside the JSON representation type rawFileHandler struct { *FileHandler } +// writeWithRaw writes the raw configuration content to a file +// Parameters: +// - config: Apollo configuration containing the raw content +// - configDir: Target directory for the configuration file +// +// Returns: +// - error: Any error that occurred during the write operation +// +// This function: +// 1. Constructs the file path using namespace +// 2. Creates a new file +// 3. Writes the raw content if available func writeWithRaw(config *config.ApolloConfig, configDir string) error { filePath := "" if configDir != "" { @@ -56,7 +72,18 @@ func writeWithRaw(config *config.ApolloConfig, configDir string) error { return nil } -// WriteConfigFile write config to file +// WriteConfigFile implements the FileHandler interface for raw file handling +// Parameters: +// - config: Apollo configuration to be written +// - configPath: Target directory path for the configuration file +// +// Returns: +// - error: Any error that occurred during the write operation +// +// This method: +// 1. Creates the target directory if needed +// 2. Writes the raw content to a separate file +// 3. Writes the JSON format configuration func (fileHandler *rawFileHandler) WriteConfigFile(config *config.ApolloConfig, configPath string) error { err := fileHandler.createDir(configPath) if err != nil { @@ -70,7 +97,11 @@ func (fileHandler *rawFileHandler) WriteConfigFile(config *config.ApolloConfig, return jsonFileConfig.Write(config, fileHandler.GetConfigFile(configPath, config.AppID, config.NamespaceName)) } -// GetRawFileHandler 获取 rawFileHandler 实例 +// GetRawFileHandler returns a singleton instance of the raw file handler +// Returns: +// - file.FileHandler: Thread-safe singleton instance of rawFileHandler +// +// This function uses sync.Once to ensure the handler is initialized only once func GetRawFileHandler() file.FileHandler { rawOnce.Do(func() { raw = &rawFileHandler{} diff --git a/env/request_config.go b/env/request_config.go index 828dd157..57122409 100644 --- a/env/request_config.go +++ b/env/request_config.go @@ -18,16 +18,29 @@ import ( "time" ) -// ConnectConfig 网络请求配置 +// ConnectConfig defines the configuration for network requests to Apollo server +// This structure contains all necessary parameters for establishing and managing +// HTTP connections with the Apollo configuration service type ConnectConfig struct { - //设置到http.client中timeout字段 + // Timeout specifies the maximum duration for HTTP requests + // This value will be set to http.Client's timeout field + // A zero or negative value means no timeout Timeout time.Duration - //连接接口的uri + + // URI specifies the endpoint URL for the Apollo API + // This should be the complete base URL for the Apollo server URI string - //是否重试 + + // IsRetry indicates whether to retry failed requests + // true: enable retry mechanism + // false: disable retry mechanism IsRetry bool - //appID + + // AppID uniquely identifies the application in Apollo + // This ID is used for authentication and configuration management AppID string - //密钥 + + // Secret is the authentication key for the application + // Used for signing requests to ensure secure communication Secret string } diff --git a/env/server/server.go b/env/server/server.go index 4e3bc79a..c6066fa3 100644 --- a/env/server/server.go +++ b/env/server/server.go @@ -22,25 +22,30 @@ import ( "github.com/apolloconfig/agollo/v4/env/config" ) -// ip -> server +// Global variables for managing Apollo server connections var ( - ipMap map[string]*Info + // ipMap stores the mapping between config service IP and server information + ipMap = make(map[string]*Info) + // serverLock provides thread-safe access to ipMap serverLock sync.Mutex - //next try connect period - 60 second + // nextTryConnectPeriod defines the waiting period (in seconds) before next connection attempt nextTryConnectPeriod int64 = 30 ) -func init() { - ipMap = make(map[string]*Info) -} - +// Info represents Apollo server information and connection status type Info struct { - //real servers ip - serverMap map[string]*config.ServerInfo + // serverMap stores the mapping of server URLs to their detailed information + serverMap map[string]*config.ServerInfo + // nextTryConnTime indicates the timestamp for the next connection attempt nextTryConnTime int64 } -// GetServersLen 获取服务器数组 +// GetServers retrieves the server information map for a given configuration IP +// Parameters: +// - configIp: The configuration service IP address +// +// Returns: +// - map[string]*config.ServerInfo: Map of server information, nil if not found func GetServers(configIp string) map[string]*config.ServerInfo { serverLock.Lock() defer serverLock.Unlock() @@ -50,7 +55,12 @@ func GetServers(configIp string) map[string]*config.ServerInfo { return ipMap[configIp].serverMap } -// GetServersLen 获取服务器数组长度 +// GetServersLen returns the number of available servers for a given configuration IP +// Parameters: +// - configIp: The configuration service IP address +// +// Returns: +// - int: Number of available servers func GetServersLen(configIp string) int { serverLock.Lock() defer serverLock.Unlock() @@ -61,6 +71,10 @@ func GetServersLen(configIp string) int { return len(s.serverMap) } +// SetServers updates the server information for a given configuration IP +// Parameters: +// - configIp: The configuration service IP address +// - serverMap: New server information map to be set func SetServers(configIp string, serverMap map[string]*config.ServerInfo) { serverLock.Lock() defer serverLock.Unlock() @@ -69,7 +83,15 @@ func SetServers(configIp string, serverMap map[string]*config.ServerInfo) { } } -// SetDownNode 设置失效节点 +// SetDownNode marks a server node as unavailable +// Parameters: +// - configService: The configuration service identifier +// - serverHost: The host address of the server to be marked down +// +// This function: +// 1. Initializes server map if not exists +// 2. Updates next connection attempt time if needed +// 3. Marks specified server as down func SetDownNode(configService string, serverHost string) { serverLock.Lock() defer serverLock.Unlock() @@ -102,9 +124,14 @@ func SetDownNode(configService string, serverHost string) { } } -// IsConnectDirectly is connect by ip directly -// false : yes -// true : no +// IsConnectDirectly determines whether to connect to the server directly +// Parameters: +// - configIp: The configuration service IP address +// +// Returns: +// - bool: true if should use meta server, false if should connect directly +// +// Note: The return value is inverse of the actual behavior for historical reasons func IsConnectDirectly(configIp string) bool { serverLock.Lock() defer serverLock.Unlock() @@ -119,7 +146,13 @@ func IsConnectDirectly(configIp string) bool { return false } -// SetNextTryConnTime if this connect is fail will set this time +// SetNextTryConnTime updates the next connection attempt time for a server +// Parameters: +// - configIp: The configuration service IP address +// - nextPeriod: Time period in seconds to wait before next attempt +// If 0, uses default nextTryConnectPeriod +// +// This function ensures proper initialization of server info if not exists func SetNextTryConnTime(configIp string, nextPeriod int64) { serverLock.Lock() defer serverLock.Unlock() diff --git a/extension/cache.go b/extension/cache.go index e3bdc5ca..2d1890f9 100644 --- a/extension/cache.go +++ b/extension/cache.go @@ -17,15 +17,26 @@ package extension import "github.com/apolloconfig/agollo/v4/agcache" var ( + // globalCacheFactory is the singleton instance of the cache factory + // It provides a centralized way to create and manage cache instances globalCacheFactory agcache.CacheFactory ) -// GetCacheFactory 获取CacheFactory +// GetCacheFactory returns the global cache factory instance +// Returns: +// - agcache.CacheFactory: The current cache factory implementation +// +// This function is used to obtain the cache factory for creating new cache instances func GetCacheFactory() agcache.CacheFactory { return globalCacheFactory } -// SetCacheFactory 替换CacheFactory +// SetCacheFactory updates the global cache factory implementation +// Parameters: +// - cacheFactory: New cache factory implementation to be used +// +// This function allows for custom cache implementations to be injected +// into the Apollo client for different caching strategies func SetCacheFactory(cacheFactory agcache.CacheFactory) { globalCacheFactory = cacheFactory } diff --git a/extension/file.go b/extension/file.go index 42ee2afd..8455cf04 100644 --- a/extension/file.go +++ b/extension/file.go @@ -16,14 +16,26 @@ package extension import "github.com/apolloconfig/agollo/v4/env/file" +// fileHandler is the global file handler instance for managing backup files +// It provides functionality for reading and writing Apollo configuration backups var fileHandler file.FileHandler -// SetFileHandler 设置备份文件处理 +// SetFileHandler sets the global file handler implementation +// Parameters: +// - inFile: New file handler implementation to be used +// +// This function allows for custom file handling implementations to be injected +// into the Apollo client for different backup strategies or storage methods func SetFileHandler(inFile file.FileHandler) { fileHandler = inFile } -// GetFileHandler 获取备份文件处理 +// GetFileHandler returns the current global file handler instance +// Returns: +// - file.FileHandler: The current file handler implementation +// +// This function is used to obtain the file handler for backup operations +// such as reading or writing configuration files func GetFileHandler() file.FileHandler { return fileHandler } diff --git a/extension/format_parser.go b/extension/format_parser.go index 18226a61..1147be9d 100644 --- a/extension/format_parser.go +++ b/extension/format_parser.go @@ -19,14 +19,29 @@ import ( "github.com/apolloconfig/agollo/v4/utils/parse" ) +// formatParser is a global map that stores content parsers for different configuration file formats +// Key: ConfigFileFormat - represents the format of the configuration file (e.g., JSON, YAML, Properties) +// Value: ContentParser - the corresponding parser implementation for that format var formatParser = make(map[constant.ConfigFileFormat]parse.ContentParser, 0) -// AddFormatParser 设置 formatParser +// AddFormatParser registers a new content parser for a specific configuration format +// Parameters: +// - key: The format of the configuration file (e.g., JSON, YAML, Properties) +// - contentParser: The parser implementation for the specified format +// +// This function enables support for parsing different configuration file formats +// by registering appropriate parser implementations func AddFormatParser(key constant.ConfigFileFormat, contentParser parse.ContentParser) { formatParser[key] = contentParser } -// GetFormatParser 获取 formatParser +// GetFormatParser retrieves the content parser for a specific configuration format +// Parameters: +// - key: The format of the configuration file to get the parser for +// +// Returns: +// - parse.ContentParser: The parser implementation for the specified format +// Returns nil if no parser is registered for the given format func GetFormatParser(key constant.ConfigFileFormat) parse.ContentParser { return formatParser[key] } diff --git a/extension/load_balance.go b/extension/load_balance.go index 97da7467..503b6acd 100644 --- a/extension/load_balance.go +++ b/extension/load_balance.go @@ -16,14 +16,26 @@ package extension import "github.com/apolloconfig/agollo/v4/cluster" +// defaultLoadBalance is the global load balancer instance +// It provides functionality for distributing requests across multiple Apollo server nodes var defaultLoadBalance cluster.LoadBalance -// SetLoadBalance 设置负载均衡器 +// SetLoadBalance sets the global load balancer implementation +// Parameters: +// - loadBalance: New load balancer implementation to be used +// +// This function allows for custom load balancing strategies to be injected +// into the Apollo client for different server selection algorithms func SetLoadBalance(loadBalance cluster.LoadBalance) { defaultLoadBalance = loadBalance } -// GetLoadBalance 获取负载均衡器 +// GetLoadBalance returns the current global load balancer instance +// Returns: +// - cluster.LoadBalance: The current load balancer implementation +// +// This function is used to obtain the load balancer for server selection +// during Apollo client operations func GetLoadBalance() cluster.LoadBalance { return defaultLoadBalance } diff --git a/extension/sign.go b/extension/sign.go index ce1ea02e..327e1d80 100644 --- a/extension/sign.go +++ b/extension/sign.go @@ -18,14 +18,27 @@ import ( "github.com/apolloconfig/agollo/v4/protocol/auth" ) +// authSign is the global HTTP authentication handler instance +// It provides functionality for signing and authenticating requests +// to the Apollo configuration service var authSign auth.HTTPAuth -// SetHTTPAuth 设置HttpAuth +// SetHTTPAuth sets the global HTTP authentication implementation +// Parameters: +// - httpAuth: New HTTP authentication implementation to be used +// +// This function allows for custom authentication strategies to be injected +// into the Apollo client for different security requirements func SetHTTPAuth(httpAuth auth.HTTPAuth) { authSign = httpAuth } -// GetHTTPAuth 获取HttpAuth +// GetHTTPAuth returns the current global HTTP authentication instance +// Returns: +// - auth.HTTPAuth: The current HTTP authentication implementation +// +// This function is used to obtain the authentication handler for +// securing requests to the Apollo configuration service func GetHTTPAuth() auth.HTTPAuth { return authSign } diff --git a/protocol/auth/auth.go b/protocol/auth/auth.go index 28dcd0a6..91339362 100644 --- a/protocol/auth/auth.go +++ b/protocol/auth/auth.go @@ -14,8 +14,20 @@ package auth -// HTTPAuth http 授权 +// HTTPAuth defines the interface for HTTP authentication in Apollo client +// This interface provides methods for generating authentication headers +// for secure communication with Apollo configuration service type HTTPAuth interface { - // HTTPHeaders 根据 @url 获取 http 授权请求头 + // HTTPHeaders generates HTTP authentication headers for Apollo API requests + // Parameters: + // - url: The target API endpoint URL + // - appID: Application identifier used for authentication + // - secret: Secret key used for generating signatures + // Returns: + // - map[string][]string: A map of HTTP headers where: + // - key: HTTP header name (e.g., "Authorization", "Timestamp") + // - value: Array of header values + // The implementation should generate all necessary headers for Apollo authentication, + // including authorization signature and timestamp HTTPHeaders(url string, appID string, secret string) map[string][]string } diff --git a/protocol/auth/sign/sign.go b/protocol/auth/sign/sign.go index 26f08ecc..33edcf3f 100644 --- a/protocol/auth/sign/sign.go +++ b/protocol/auth/sign/sign.go @@ -26,31 +26,59 @@ import ( ) const ( + // httpHeaderAuthorization is the HTTP header key for authorization httpHeaderAuthorization = "Authorization" - httpHeaderTimestamp = "Timestamp" + // httpHeaderTimestamp is the HTTP header key for request timestamp + httpHeaderTimestamp = "Timestamp" + // authorizationFormat defines the format for Apollo authorization header + // Format: "Apollo {appID}:{signature}" authorizationFormat = "Apollo %s:%s" + // delimiter used to separate components in the string to be signed delimiter = "\n" - question = "?" + // question mark used in URL query string + question = "?" ) var ( + // h is the default hash function (SHA1) used for signature generation h = sha1.New ) -// SetHash set hash function +// SetHash updates the hash function used for signature generation +// Parameters: +// - f: New hash function to be used +// +// Returns: +// - func() hash.Hash: The previous hash function +// +// This function allows for custom hash implementations to be used func SetHash(f func() hash.Hash) func() hash.Hash { o := h h = f return o } -// AuthSignature apollo 授权 +// AuthSignature implements Apollo's signature-based authentication +// It provides functionality to generate authentication headers for Apollo API requests type AuthSignature struct { } -// HTTPHeaders HTTPHeaders +// HTTPHeaders generates the authentication headers for Apollo API requests +// Parameters: +// - url: The target API endpoint URL +// - appID: Application identifier +// - secret: Authentication secret key +// +// Returns: +// - map[string][]string: HTTP headers containing authorization and timestamp +// +// This method: +// 1. Generates current timestamp +// 2. Extracts path and query from URL +// 3. Creates signature using timestamp, path, and secret +// 4. Formats headers according to Apollo's requirements func (t *AuthSignature) HTTPHeaders(url string, appID string, secret string) map[string][]string { ms := time.Now().UnixNano() / int64(time.Millisecond) timestamp := strconv.FormatInt(ms, 10) @@ -70,6 +98,13 @@ func (t *AuthSignature) HTTPHeaders(url string, appID string, secret string) map return headers } +// signString generates a signature for the given string using HMAC-SHA1 +// Parameters: +// - stringToSign: The string to be signed +// - accessKeySecret: The secret key for signing +// +// Returns: +// - string: Base64-encoded signature func signString(stringToSign string, accessKeySecret string) string { key := []byte(accessKeySecret) mac := hmac.New(h, key) @@ -77,6 +112,14 @@ func signString(stringToSign string, accessKeySecret string) string { return base64.StdEncoding.EncodeToString(mac.Sum(nil)) } +// url2PathWithQuery extracts the path and query string from a URL +// Parameters: +// - rawURL: The complete URL to parse +// +// Returns: +// - string: Combined path and query string, or empty string if parsing fails +// +// Format: /path?query=value func url2PathWithQuery(rawURL string) string { u, err := url.Parse(rawURL) if err != nil { diff --git a/protocol/http/request.go b/protocol/http/request.go index 9dffae5b..46287fdf 100644 --- a/protocol/http/request.go +++ b/protocol/http/request.go @@ -35,26 +35,38 @@ import ( ) var ( - //for on error retry - onErrorRetryInterval = 2 * time.Second //2s + // onErrorRetryInterval defines the waiting period between retry attempts + // when a request fails (2 seconds) + onErrorRetryInterval = 2 * time.Second - connectTimeout = 1 * time.Second //1s + // connectTimeout defines the default connection timeout (1 second) + connectTimeout = 1 * time.Second - //max retries connect apollo + // maxRetries defines the maximum number of retry attempts for Apollo server connections maxRetries = 5 - //defaultMaxConnsPerHost defines the maximum number of concurrent connections + // defaultMaxConnsPerHost defines the maximum number of concurrent connections per host defaultMaxConnsPerHost = 512 - //defaultTimeoutBySecond defines the default timeout for http connections + + // defaultTimeoutBySecond defines the default timeout for HTTP connections defaultTimeoutBySecond = 1 * time.Second - //defaultKeepAliveSecond defines the connection time + + // defaultKeepAliveSecond defines the duration to keep connections alive defaultKeepAliveSecond = 60 * time.Second - // once for single http.Transport + + // once ensures thread-safe initialization of the HTTP transport once sync.Once - // defaultTransport http.Transport + + // defaultTransport is the shared HTTP transport configuration defaultTransport *http.Transport ) +// getDefaultTransport returns a configured HTTP transport with connection pooling +// Parameters: +// - insecureSkipVerify: Whether to skip SSL certificate verification +// +// Returns: +// - *http.Transport: Configured transport instance func getDefaultTransport(insecureSkipVerify bool) *http.Transport { once.Do(func() { defaultTransport = &http.Transport{ @@ -75,18 +87,30 @@ func getDefaultTransport(insecureSkipVerify bool) *http.Transport { return defaultTransport } -// CallBack 请求回调函数 +// CallBack defines the callback functions for handling HTTP responses type CallBack struct { - SuccessCallBack func([]byte, CallBack) (interface{}, error) + // SuccessCallBack handles successful responses (HTTP 200) + SuccessCallBack func([]byte, CallBack) (interface{}, error) + // NotModifyCallBack handles not modified responses (HTTP 304) NotModifyCallBack func() error - AppConfigFunc func() config.AppConfig - Namespace string + // AppConfigFunc provides application configuration + AppConfigFunc func() config.AppConfig + // Namespace identifies the configuration namespace + Namespace string } -// Request 建立网络请求 +// Request performs an HTTP request to the Apollo server with retry mechanism +// Parameters: +// - requestURL: Target URL for the request +// - connectionConfig: Connection configuration including timeout and credentials +// - callBack: Callback functions for handling different response scenarios +// +// Returns: +// - interface{}: Response data processed by callback functions +// - error: Any error that occurred during the request func Request(requestURL string, connectionConfig *env.ConnectConfig, callBack *CallBack) (interface{}, error) { client := &http.Client{} - //如有设置自定义超时时间即使用 + // Use custom timeout if set if connectionConfig != nil && connectionConfig.Timeout != 0 { client.Timeout = connectionConfig.Timeout } else { @@ -123,7 +147,7 @@ func Request(requestURL string, connectionConfig *env.ConnectConfig, callBack *C return nil, errors.New("generate connect Apollo request fail") } - //增加header选项 + // Add header options httpAuth := extension.GetHTTPAuth() if httpAuth != nil { headers := httpAuth.HTTPHeaders(requestURL, connectionConfig.AppID, connectionConfig.Secret) @@ -189,7 +213,21 @@ func Request(requestURL string, connectionConfig *env.ConnectConfig, callBack *C return nil, err } -// RequestRecovery 可以恢复的请求 +// RequestRecovery performs requests with automatic server failover +// Parameters: +// - appConfig: Application configuration containing server information +// - connectConfig: Connection configuration for the request +// - callBack: Callback functions for handling responses +// +// Returns: +// - interface{}: Processed response data +// - error: Any error that occurred during the request +// +// This function implements a failover mechanism by: +// 1. Using load balancing to select a server +// 2. Attempting the request +// 3. Marking failed servers as down +// 4. Retrying with different servers until successful func RequestRecovery(appConfig config.AppConfig, connectConfig *env.ConnectConfig, callBack *CallBack) (interface{}, error) { @@ -213,6 +251,17 @@ func RequestRecovery(appConfig config.AppConfig, } } +// loadBalance selects an Apollo server using the configured load balancing strategy +// Parameters: +// - appConfig: Application configuration containing server information +// +// Returns: +// - string: Selected server's homepage URL, empty if no server available +// +// This function: +// 1. Checks if direct connection is required +// 2. Uses load balancer to select a server if needed +// 3. Returns the appropriate server URL func loadBalance(appConfig config.AppConfig) string { if !server.IsConnectDirectly(appConfig.GetHost()) { return appConfig.GetHost() diff --git a/start.go b/start.go index f5522cd8..cb90728e 100644 --- a/start.go +++ b/start.go @@ -23,35 +23,74 @@ import ( "github.com/apolloconfig/agollo/v4/protocol/auth" ) -// SetSignature 设置自定义 http 授权控件 +// SetSignature configures a custom HTTP authentication component +// Parameters: +// - auth: Custom implementation of HTTPAuth interface for request authentication +// +// This function allows users to: +// 1. Override the default authentication mechanism +// 2. Implement custom authentication logic for Apollo server requests +// Note: If auth is nil, the function will have no effect func SetSignature(auth auth.HTTPAuth) { if auth != nil { extension.SetHTTPAuth(auth) } } -// SetBackupFileHandler 设置自定义备份文件处理组件 +// SetBackupFileHandler configures a custom backup file handler component +// Parameters: +// - file: Custom implementation of FileHandler interface for backup operations +// +// This function enables: +// 1. Custom backup file storage mechanisms +// 2. Custom backup file formats +// 3. Custom backup locations +// Note: If file is nil, the function will have no effect func SetBackupFileHandler(file file.FileHandler) { if file != nil { extension.SetFileHandler(file) } } -// SetLoadBalance 设置自定义负载均衡组件 +// SetLoadBalance configures a custom load balancing component +// Parameters: +// - loadBalance: Custom implementation of LoadBalance interface +// +// This function allows: +// 1. Custom server selection strategies +// 2. Custom load balancing algorithms +// 3. Custom health check mechanisms +// Note: If loadBalance is nil, the function will have no effect func SetLoadBalance(loadBalance cluster.LoadBalance) { if loadBalance != nil { extension.SetLoadBalance(loadBalance) } } -// SetLogger 设置自定义logger组件 +// SetLogger configures a custom logging component +// Parameters: +// - loggerInterface: Custom implementation of LoggerInterface +// +// This function enables: +// 1. Custom log formatting +// 2. Custom log levels +// 3. Custom log output destinations +// Note: If loggerInterface is nil, the function will have no effect func SetLogger(loggerInterface log.LoggerInterface) { if loggerInterface != nil { log.InitLogger(loggerInterface) } } -// SetCache 设置自定义cache组件 +// SetCache configures a custom cache component +// Parameters: +// - cacheFactory: Custom implementation of CacheFactory interface +// +// This function allows: +// 1. Custom cache storage mechanisms +// 2. Custom cache eviction policies +// 3. Custom cache serialization methods +// Note: If cacheFactory is nil, the function will have no effect func SetCache(cacheFactory agcache.CacheFactory) { if cacheFactory != nil { extension.SetCacheFactory(cacheFactory) diff --git a/storage/change_event.go b/storage/change_event.go index 9ee8b22a..bf27210a 100644 --- a/storage/change_event.go +++ b/storage/change_event.go @@ -15,48 +15,71 @@ package storage const ( + // ADDED represents a new configuration item being added ADDED ConfigChangeType = iota + // MODIFIED represents an existing configuration item being modified MODIFIED + // DELETED represents an existing configuration item being removed DELETED ) -// ChangeListener 监听器 +// ChangeListener defines the interface for configuration change event handlers +// Implementations can react to both incremental and full configuration changes type ChangeListener interface { - //OnChange 增加变更监控 + // OnChange handles incremental configuration changes + // Parameters: + // - event: Contains details about specific property changes OnChange(event *ChangeEvent) - //OnNewestChange 监控最新变更 + // OnNewestChange handles full configuration changes + // Parameters: + // - event: Contains the complete new configuration state OnNewestChange(event *FullChangeEvent) } -// config change type +// ConfigChangeType represents the type of configuration change type ConfigChangeType int -// config change event +// baseChangeEvent contains common fields for all change events type baseChangeEvent struct { - Namespace string + // Namespace identifies the configuration namespace + Namespace string + // NotificationID is the unique identifier for this change notification NotificationID int64 } -// config change event +// ChangeEvent represents an incremental configuration change +// It contains information about specific property changes type ChangeEvent struct { baseChangeEvent + // Changes maps property keys to their change details Changes map[string]*ConfigChange } +// ConfigChange contains details about a single property's change type ConfigChange struct { - OldValue interface{} - NewValue interface{} + // OldValue contains the previous value of the property + OldValue interface{} + // NewValue contains the updated value of the property + NewValue interface{} + // ChangeType indicates how the property changed (ADDED/MODIFIED/DELETED) ChangeType ConfigChangeType } -// all config change event +// FullChangeEvent represents a complete configuration state change type FullChangeEvent struct { baseChangeEvent + // Changes maps property keys to their new values Changes map[string]interface{} } -// create modify config change +// createModifyConfigChange creates a ConfigChange for modified properties +// Parameters: +// - oldValue: The previous value of the property +// - newValue: The updated value of the property +// +// Returns: +// - *ConfigChange: A change record with MODIFIED type func createModifyConfigChange(oldValue interface{}, newValue interface{}) *ConfigChange { return &ConfigChange{ OldValue: oldValue, @@ -65,7 +88,12 @@ func createModifyConfigChange(oldValue interface{}, newValue interface{}) *Confi } } -// create add config change +// createAddConfigChange creates a ConfigChange for new properties +// Parameters: +// - newValue: The value of the new property +// +// Returns: +// - *ConfigChange: A change record with ADDED type func createAddConfigChange(newValue interface{}) *ConfigChange { return &ConfigChange{ NewValue: newValue, @@ -73,7 +101,12 @@ func createAddConfigChange(newValue interface{}) *ConfigChange { } } -// create delete config change +// createDeletedConfigChange creates a ConfigChange for removed properties +// Parameters: +// - oldValue: The last value of the property before deletion +// +// Returns: +// - *ConfigChange: A change record with DELETED type func createDeletedConfigChange(oldValue interface{}) *ConfigChange { return &ConfigChange{ OldValue: oldValue, @@ -81,7 +114,14 @@ func createDeletedConfigChange(oldValue interface{}) *ConfigChange { } } -// base on changeList create Change event +// createConfigChangeEvent creates a new ChangeEvent from a set of changes +// Parameters: +// - changes: Map of property keys to their change details +// - nameSpace: The configuration namespace +// - notificationID: Unique identifier for this change notification +// +// Returns: +// - *ChangeEvent: A new change event containing all changes func createConfigChangeEvent(changes map[string]*ConfigChange, nameSpace string, notificationID int64) *ChangeEvent { c := &ChangeEvent{ Changes: changes, diff --git a/storage/event_dispatch.go b/storage/event_dispatch.go index bf57c55d..ec81f7b0 100644 --- a/storage/event_dispatch.go +++ b/storage/event_dispatch.go @@ -23,39 +23,46 @@ import ( ) const ( + // fmtInvalidKey is the error message format for invalid key patterns fmtInvalidKey = "invalid key format for key %s" ) var ( - //ErrNilListener 为没有找到listener的错误 + // ErrNilListener represents an error when a nil listener is provided ErrNilListener = errors.New("nil listener") ) -// Event generated when any config changes +// Event represents a configuration change event +// It contains the type of change, the affected key, and the new value type Event struct { EventType ConfigChangeType Key string Value interface{} } -// Listener All Listener should implement this Interface +// Listener is an interface that all event listeners must implement +// It defines the Event method that will be called when configuration changes occur type Listener interface { Event(event *Event) } -// Dispatcher is the observer +// Dispatcher manages the event distribution system +// It maintains a map of keys to their registered listeners type Dispatcher struct { listeners map[string][]Listener } -// UseEventDispatch 用于开启事件分发功能 +// UseEventDispatch creates and initializes a new event dispatcher +// Returns a new Dispatcher instance with an initialized listeners map func UseEventDispatch() *Dispatcher { eventDispatch := new(Dispatcher) eventDispatch.listeners = make(map[string][]Listener) return eventDispatch } -// RegisterListener 是为某些key注释Listener的方法 +// RegisterListener registers a listener for specific configuration keys +// The keys can be regular expressions to match multiple configuration keys +// Returns an error if the listener is nil or if any key pattern is invalid func (d *Dispatcher) RegisterListener(listenerObject Listener, keys ...string) error { log.Infof("start add key %v add listener", keys) if listenerObject == nil { @@ -85,12 +92,16 @@ func (d *Dispatcher) RegisterListener(listenerObject Listener, keys ...string) e return nil } +// invalidKey checks if a key pattern is a valid regular expression +// Returns true if the pattern is invalid, false otherwise func invalidKey(key string) bool { _, err := regexp.Compile(key) return err != nil } -// UnRegisterListener 用于为某些key注释Listener +// UnRegisterListener removes a listener from specific configuration keys +// The keys can be regular expressions to match multiple configuration keys +// Returns an error if the listener is nil func (d *Dispatcher) UnRegisterListener(listenerObj Listener, keys ...string) error { if listenerObj == nil { return ErrNilListener @@ -117,7 +128,8 @@ func (d *Dispatcher) UnRegisterListener(listenerObj Listener, keys ...string) er return nil } -// OnChange 实现Apollo的ChangeEvent处理 +// OnChange implements the ChangeEvent handler for Apollo configuration changes +// It processes the change event and dispatches events to registered listeners func (d *Dispatcher) OnChange(changeEvent *ChangeEvent) { if changeEvent == nil { return @@ -128,10 +140,14 @@ func (d *Dispatcher) OnChange(changeEvent *ChangeEvent) { } } +// OnNewestChange handles the latest configuration change events +// This method is currently empty and reserved for future implementation func (d *Dispatcher) OnNewestChange(event *FullChangeEvent) { } +// dispatchEvent dispatches a configuration change event to all matching listeners +// It matches the event key against registered key patterns and notifies matching listeners func (d *Dispatcher) dispatchEvent(eventKey string, event *ConfigChange) { for regKey, listenerList := range d.listeners { matched, err := regexp.MatchString(regKey, eventKey) @@ -148,6 +164,8 @@ func (d *Dispatcher) dispatchEvent(eventKey string, event *ConfigChange) { } } +// convertToEvent converts a ConfigChange to an Event +// It sets the appropriate value based on the change type func convertToEvent(key string, event *ConfigChange) *Event { e := &Event{ EventType: event.ChangeType, diff --git a/storage/repository.go b/storage/repository.go index 552cf749..f6b34f6b 100644 --- a/storage/repository.go +++ b/storage/repository.go @@ -31,22 +31,26 @@ import ( ) const ( - // 1 minute + // configCacheExpireTime defines the expiration time for configuration cache in seconds configCacheExpireTime = 120 + // defaultNamespace is the default namespace for Apollo configuration defaultNamespace = "application" + // propertiesFormat is the format string for properties file output propertiesFormat = "%s=%v\n" ) -// Cache apollo 配置缓存 +// Cache represents the Apollo configuration cache +// It maintains a thread-safe storage for configurations and manages change listeners type Cache struct { apolloConfigCache sync.Map changeListeners *list.List rw sync.RWMutex } -// GetConfig 根据namespace获取apollo配置 +// GetConfig retrieves the configuration for a specific namespace +// Returns nil if the namespace is empty or not found func (c *Cache) GetConfig(namespace string) *Config { if namespace == "" { return nil @@ -61,7 +65,8 @@ func (c *Cache) GetConfig(namespace string) *Config { return config.(*Config) } -// CreateNamespaceConfig 根据namespace初始化agollo内容配置 +// CreateNamespaceConfig initializes Apollo configuration for the given namespace +// It creates a new cache instance and initializes configurations for each namespace func CreateNamespaceConfig(namespace string) *Cache { // config from apollo var apolloConfigCache sync.Map @@ -78,6 +83,8 @@ func CreateNamespaceConfig(namespace string) *Cache { } } +// initConfig initializes a new Config instance for the given namespace +// It sets up the cache and initialization flags func initConfig(namespace string, factory agcache.CacheFactory) *Config { c := &Config{ namespace: namespace, @@ -88,7 +95,8 @@ func initConfig(namespace string, factory agcache.CacheFactory) *Config { return c } -// Config apollo配置项 +// Config represents an Apollo configuration item +// It contains the namespace, cache, and initialization state type Config struct { namespace string cache agcache.CacheInterface @@ -96,22 +104,24 @@ type Config struct { waitInit sync.WaitGroup } -// GetIsInit 获取标志 +// GetIsInit returns the initialization status of the configuration func (c *Config) GetIsInit() bool { return c.isInit.Load().(bool) } -// GetWaitInit 获取标志 +// GetWaitInit returns the WaitGroup for initialization synchronization func (c *Config) GetWaitInit() *sync.WaitGroup { return &c.waitInit } -// GetCache 获取cache +// GetCache returns the cache interface for this configuration func (c *Config) GetCache() agcache.CacheInterface { return c.cache } -// getConfigValue 获取配置值 +// getConfigValue retrieves a configuration value by key +// If waitInit is true, it will wait for initialization to complete +// Returns nil if the key doesn't exist or there's an error func (c *Config) getConfigValue(key string, waitInit bool) interface{} { b := c.GetIsInit() if !b { @@ -135,7 +145,8 @@ func (c *Config) getConfigValue(key string, waitInit bool) interface{} { return value } -// GetValueImmediately 获取配置值(string),立即返回,初始化未完成直接返回错误 +// GetValueImmediately retrieves a string configuration value without waiting for initialization +// Returns empty string if the key doesn't exist or there's an error func (c *Config) GetValueImmediately(key string) string { value := c.getConfigValue(key, false) if value == nil { @@ -150,7 +161,8 @@ func (c *Config) GetValueImmediately(key string) string { return v } -// GetStringValueImmediately 获取配置值(string),立即返回,初始化未完成直接返回错误 +// GetStringValueImmediately retrieves a string configuration value with default fallback +// Returns the default value if the key doesn't exist func (c *Config) GetStringValueImmediately(key string, defaultValue string) string { value := c.GetValueImmediately(key) if value == utils.Empty { @@ -160,7 +172,8 @@ func (c *Config) GetStringValueImmediately(key string, defaultValue string) stri return value } -// GetStringSliceValueImmediately 获取配置值([]string),立即返回,初始化未完成直接返回错误 +// GetStringSliceValueImmediately retrieves a string slice configuration value without waiting +// Returns the default value if the key doesn't exist or conversion fails func (c *Config) GetStringSliceValueImmediately(key string, defaultValue []string) []string { value := c.getConfigValue(key, false) if value == nil { @@ -175,7 +188,8 @@ func (c *Config) GetStringSliceValueImmediately(key string, defaultValue []strin return v } -// GetIntSliceValueImmediately 获取配置值([]int),立即返回,初始化未完成直接返回错误 +// GetIntSliceValueImmediately retrieves an integer slice configuration value without waiting +// Returns the default value if the key doesn't exist or conversion fails func (c *Config) GetIntSliceValueImmediately(key string, defaultValue []int) []int { value := c.getConfigValue(key, false) if value == nil { @@ -190,7 +204,8 @@ func (c *Config) GetIntSliceValueImmediately(key string, defaultValue []int) []i return v } -// GetSliceValueImmediately 获取配置值([]interface),立即返回,初始化未完成直接返回错误 +// GetSliceValueImmediately retrieves an interface slice configuration value without waiting +// Returns the default value if the key doesn't exist or conversion fails func (c *Config) GetSliceValueImmediately(key string, defaultValue []interface{}) []interface{} { value := c.getConfigValue(key, false) if value == nil { @@ -205,7 +220,8 @@ func (c *Config) GetSliceValueImmediately(key string, defaultValue []interface{} return v } -// GetIntValueImmediately 获取配置值(int),获取不到则取默认值,立即返回,初始化未完成直接返回错误 +// GetIntValueImmediately retrieves an integer configuration value without waiting +// Returns the default value if the key doesn't exist or conversion fails func (c *Config) GetIntValueImmediately(key string, defaultValue int) int { value := c.getConfigValue(key, false) if value == nil { @@ -232,7 +248,8 @@ func (c *Config) GetIntValueImmediately(key string, defaultValue int) int { return v } -// GetFloatValueImmediately 获取配置值(float),获取不到则取默认值,立即返回,初始化未完成直接返回错误 +// GetFloatValueImmediately retrieves a float configuration value without waiting +// Returns the default value if the key doesn't exist or conversion fails func (c *Config) GetFloatValueImmediately(key string, defaultValue float64) float64 { value := c.getConfigValue(key, false) if value == nil { @@ -259,7 +276,8 @@ func (c *Config) GetFloatValueImmediately(key string, defaultValue float64) floa return v } -// GetBoolValueImmediately 获取配置值(bool),获取不到则取默认值,立即返回,初始化未完成直接返回错误 +// GetBoolValueImmediately retrieves a boolean configuration value without waiting +// Returns the default value if the key doesn't exist or conversion fails func (c *Config) GetBoolValueImmediately(key string, defaultValue bool) bool { value := c.getConfigValue(key, false) if value == nil { @@ -286,7 +304,8 @@ func (c *Config) GetBoolValueImmediately(key string, defaultValue bool) bool { return v } -// GetValue 获取配置值(string) +// GetValue retrieves a string configuration value, waiting for initialization if necessary +// Returns empty string if the key doesn't exist or conversion fails func (c *Config) GetValue(key string) string { value := c.getConfigValue(key, true) if value == nil { @@ -301,7 +320,8 @@ func (c *Config) GetValue(key string) string { return v } -// GetStringValue 获取配置值(string),获取不到则取默认值 +// GetStringValue retrieves a string configuration value with default fallback +// Returns the default value if the key doesn't exist func (c *Config) GetStringValue(key string, defaultValue string) string { value := c.GetValue(key) if value == utils.Empty { @@ -311,7 +331,9 @@ func (c *Config) GetStringValue(key string, defaultValue string) string { return value } -// GetStringSliceValue 获取配置值([]string) +// GetStringSliceValue retrieves a string slice configuration value +// The values are split by the separator if the value is a string +// Returns the default value if the key doesn't exist or conversion fails func (c *Config) GetStringSliceValue(key, separator string, defaultValue []string) []string { value := c.getConfigValue(key, true) if value == nil { @@ -330,7 +352,9 @@ func (c *Config) GetStringSliceValue(key, separator string, defaultValue []strin return v } -// GetIntSliceValue 获取配置值([]int) +// GetIntSliceValue retrieves an integer slice configuration value +// The values are split by the separator if the value is a string +// Returns the default value if the key doesn't exist or conversion fails func (c *Config) GetIntSliceValue(key, separator string, defaultValue []int) []int { value := c.getConfigValue(key, true) if value == nil { @@ -356,7 +380,8 @@ func (c *Config) GetIntSliceValue(key, separator string, defaultValue []int) []i return v } -// GetSliceValue 获取配置值([]interface) +// GetSliceValue retrieves an interface slice configuration value +// Returns the default value if the key doesn't exist or conversion fails func (c *Config) GetSliceValue(key string, defaultValue []interface{}) []interface{} { value := c.getConfigValue(key, true) if value == nil { @@ -371,7 +396,8 @@ func (c *Config) GetSliceValue(key string, defaultValue []interface{}) []interfa return v } -// GetIntValue 获取配置值(int),获取不到则取默认值 +// GetIntValue retrieves an integer configuration value with default fallback +// Returns the default value if the key doesn't exist or conversion fails func (c *Config) GetIntValue(key string, defaultValue int) int { value := c.getConfigValue(key, true) if value == nil { @@ -397,7 +423,8 @@ func (c *Config) GetIntValue(key string, defaultValue int) int { return v } -// GetFloatValue 获取配置值(float),获取不到则取默认值 +// GetFloatValue retrieves a float configuration value with default fallback +// Returns the default value if the key doesn't exist or conversion fails func (c *Config) GetFloatValue(key string, defaultValue float64) float64 { value := c.getConfigValue(key, true) if value == nil { @@ -423,7 +450,8 @@ func (c *Config) GetFloatValue(key string, defaultValue float64) float64 { return v } -// GetBoolValue 获取配置值(bool),获取不到则取默认值 +// GetBoolValue retrieves a boolean configuration value with default fallback +// Returns the default value if the key doesn't exist or conversion fails func (c *Config) GetBoolValue(key string, defaultValue bool) bool { value := c.getConfigValue(key, true) if value == nil { @@ -449,8 +477,8 @@ func (c *Config) GetBoolValue(key string, defaultValue bool) bool { return v } -// UpdateApolloConfig 根据config server返回的内容更新内存 -// 并判断是否需要写备份文件 +// UpdateApolloConfig updates the in-memory configuration based on the server response +// It also determines whether to write a backup file func (c *Cache) UpdateApolloConfig(apolloConfig *config.ApolloConfig, appConfigFunc func() config.AppConfig) { if apolloConfig == nil { log.Error("apolloConfig is null, can't update!") @@ -484,7 +512,8 @@ func (c *Cache) UpdateApolloConfig(apolloConfig *config.ApolloConfig, appConfigF } } -// UpdateApolloConfigCache 根据conf[ig server返回的内容更新内存 +// UpdateApolloConfigCache updates the in-memory cache based on the server response +// It returns a map of configuration changes func (c *Cache) UpdateApolloConfigCache(configurations map[string]interface{}, expireTime int, namespace string) map[string]*ConfigChange { config := c.GetConfig(namespace) if config == nil { @@ -518,8 +547,7 @@ func (c *Cache) UpdateApolloConfigCache(configurations map[string]interface{}, e changes := make(map[string]*ConfigChange) - // update new - // keys + // update new keys for key, value := range configurations { // key state insert or update // insert @@ -540,9 +568,9 @@ func (c *Cache) UpdateApolloConfigCache(configurations map[string]interface{}, e delete(mp, key) } - // remove del keys + // remove deleted keys for key := range mp { - // get old value and del + // get old value and delete oldValue, _ := config.cache.Get(key) changes[key] = createDeletedConfigChange(oldValue) @@ -553,11 +581,12 @@ func (c *Cache) UpdateApolloConfigCache(configurations map[string]interface{}, e return changes } -// GetContent 获取配置文件内容 +// GetContent retrieves the configuration content in properties format func (c *Config) GetContent() string { return convertToProperties(c.cache) } +// convertToProperties converts the cache content to properties format func convertToProperties(cache agcache.CacheInterface) string { properties := utils.Empty if cache == nil { @@ -570,12 +599,13 @@ func convertToProperties(cache agcache.CacheInterface) string { return properties } -// GetDefaultNamespace 获取默认命名空间 +// GetDefaultNamespace returns the default namespace for Apollo configuration func GetDefaultNamespace() string { return defaultNamespace } -// AddChangeListener 增加变更监控 +// AddChangeListener adds a change listener to the cache +// The listener will be notified when configuration changes occur func (c *Cache) AddChangeListener(listener ChangeListener) { if listener == nil { return @@ -585,7 +615,8 @@ func (c *Cache) AddChangeListener(listener ChangeListener) { c.changeListeners.PushBack(listener) } -// RemoveChangeListener 删除变更监控 +// RemoveChangeListener removes a change listener from the cache +// The listener will no longer receive configuration change notifications func (c *Cache) RemoveChangeListener(listener ChangeListener) { if listener == nil { return @@ -600,7 +631,8 @@ func (c *Cache) RemoveChangeListener(listener ChangeListener) { } } -// GetChangeListeners 获取配置修改监听器列表 +// GetChangeListeners returns the list of configuration change listeners +// Returns a new list containing all registered listeners func (c *Cache) GetChangeListeners() *list.List { if c.changeListeners == nil { return nil @@ -612,13 +644,14 @@ func (c *Cache) GetChangeListeners() *list.List { return l } -// push config change event +// pushChangeEvent pushes a configuration change event to all listeners func (c *Cache) pushChangeEvent(event *ChangeEvent) { c.pushChange(func(listener ChangeListener) { go listener.OnChange(event) }) } +// pushNewestChanges pushes the latest configuration changes to all listeners func (c *Cache) pushNewestChanges(namespace string, configuration map[string]interface{}, notificationID int64) { e := &FullChangeEvent{ Changes: configuration, @@ -630,8 +663,10 @@ func (c *Cache) pushNewestChanges(namespace string, configuration map[string]int }) } +// pushChange executes the given function for each change listener +// It handles the case when there are no listeners func (c *Cache) pushChange(f func(ChangeListener)) { - // if channel is null ,mean no listener,don't need to push msg + // if channel is null, mean no listener, don't need to push msg listeners := c.GetChangeListeners() if listeners == nil || listeners.Len() == 0 { return diff --git a/test-application.json b/test-application.json new file mode 100644 index 00000000..91c6744c --- /dev/null +++ b/test-application.json @@ -0,0 +1 @@ +{"appId":"test","cluster":"","namespaceName":"application","releaseKey":"","configurations":{"key1":"value1","key2":"value2"}} diff --git a/utils/parse/normal/parser.go b/utils/parse/normal/parser.go index 5d761d70..0e159b64 100644 --- a/utils/parse/normal/parser.go +++ b/utils/parse/normal/parser.go @@ -14,11 +14,22 @@ package normal -// Parser 默认内容转换器 +// Parser represents the default content parser implementation +// It provides basic parsing functionality for Apollo configuration content +// This parser is used when no specific format parser is registered type Parser struct { } -// Parse 内存内容默认转换器 +// Parse converts configuration content to a key-value map +// Parameters: +// - configContent: The configuration content to parse, can be of any type +// +// Returns: +// - map[string]interface{}: Parsed configuration as key-value pairs +// - error: Any error that occurred during parsing +// +// Note: This is a default implementation that returns nil values, +// intended to be used as a fallback when no specific parser is available func (d *Parser) Parse(configContent interface{}) (map[string]interface{}, error) { return nil, nil } diff --git a/utils/parse/parser.go b/utils/parse/parser.go index 9fbae85e..98391664 100644 --- a/utils/parse/parser.go +++ b/utils/parse/parser.go @@ -14,7 +14,17 @@ package parse -// ContentParser 内容转换 +// ContentParser defines the interface for configuration content parsing +// This interface is used by Apollo to support different configuration formats +// (e.g., Properties, YAML, JSON) through format-specific implementations type ContentParser interface { + // Parse converts configuration content from its original format to a key-value map + // Parameters: + // - configContent: The configuration content to parse, type depends on the format + // Returns: + // - map[string]interface{}: Parsed configuration as key-value pairs + // - error: Any error that occurred during parsing + // Implementations should handle format-specific parsing logic and + // return a consistent map structure regardless of the input format Parse(configContent interface{}) (map[string]interface{}, error) } diff --git a/utils/parse/properties/parser.go b/utils/parse/properties/parser.go index 2f23d608..7ce85095 100644 --- a/utils/parse/properties/parser.go +++ b/utils/parse/properties/parser.go @@ -14,11 +14,23 @@ package properties -// Parser properties转换器 +// Parser implements the properties file format parser +// It provides functionality to parse Java-style properties format +// configuration content in Apollo configuration system type Parser struct { } -// Parse 内存内容=>properties文件转换器 +// Parse converts properties format configuration content to a key-value map +// Parameters: +// - configContent: The configuration content to parse, expected to be in +// properties format (e.g., key=value pairs, one per line) +// +// Returns: +// - map[string]interface{}: Parsed configuration as key-value pairs +// - error: Any error that occurred during parsing +// +// This parser is specifically designed to handle Java-style properties +// format configuration files in Apollo func (d *Parser) Parse(configContent interface{}) (map[string]interface{}, error) { return nil, nil } diff --git a/utils/parse/yaml/parser.go b/utils/parse/yaml/parser.go index 84952ad4..93703cc7 100644 --- a/utils/parse/yaml/parser.go +++ b/utils/parse/yaml/parser.go @@ -22,17 +22,34 @@ import ( "github.com/apolloconfig/agollo/v4/utils" ) +// vp is a global Viper instance for YAML parsing +// Using a single instance to improve performance var vp = viper.New() +// init initializes the Viper instance with YAML configuration type func init() { vp.SetConfigType("yaml") } -// Parser properties转换器 +// Parser implements the YAML format parser for Apollo configuration system +// It provides functionality to parse YAML format configuration content +// using the Viper library for robust YAML parsing capabilities type Parser struct { } -// Parse 内存内容=>yml文件转换器 +// Parse converts YAML format configuration content to a key-value map +// Parameters: +// - configContent: The configuration content to parse, expected to be +// a string containing YAML formatted data +// +// Returns: +// - map[string]interface{}: Parsed configuration as key-value pairs +// - error: Any error that occurred during parsing +// +// This method: +// 1. Validates and converts input to string +// 2. Uses Viper to parse YAML content +// 3. Converts parsed content to a flat key-value map func (d *Parser) Parse(configContent interface{}) (map[string]interface{}, error) { content, ok := configContent.(string) if !ok { @@ -43,7 +60,7 @@ func (d *Parser) Parse(configContent interface{}) (map[string]interface{}, error } buffer := bytes.NewBufferString(content) - // 使用viper解析 + // Use Viper to parse the YAML content err := vp.ReadConfig(buffer) if err != nil { return nil, err @@ -52,6 +69,15 @@ func (d *Parser) Parse(configContent interface{}) (map[string]interface{}, error return convertToMap(vp), nil } +// convertToMap converts Viper's parsed configuration to a flat key-value map +// Parameters: +// - vp: Viper instance containing parsed configuration +// +// Returns: +// - map[string]interface{}: Flattened key-value pairs from YAML configuration +// +// This function extracts all keys and their values from Viper's parsed +// configuration and stores them in a simple map structure func convertToMap(vp *viper.Viper) map[string]interface{} { if vp == nil { return nil diff --git a/utils/parse/yml/parser.go b/utils/parse/yml/parser.go index 39d3faaf..9168e685 100644 --- a/utils/parse/yml/parser.go +++ b/utils/parse/yml/parser.go @@ -22,17 +22,34 @@ import ( "github.com/apolloconfig/agollo/v4/utils" ) +// vp is a global Viper instance for YML parsing +// Using a single instance to improve performance var vp = viper.New() +// init initializes the Viper instance with YML configuration type func init() { vp.SetConfigType("yml") } -// Parser properties转换器 +// Parser implements the YML format parser for Apollo configuration system +// It provides functionality to parse YML format configuration content +// using the Viper library for robust YML parsing capabilities type Parser struct { } -// Parse 内存内容=>yml文件转换器 +// Parse converts YML format configuration content to a key-value map +// Parameters: +// - configContent: The configuration content to parse, expected to be +// a string containing YML formatted data +// +// Returns: +// - map[string]interface{}: Parsed configuration as key-value pairs +// - error: Any error that occurred during parsing +// +// This method: +// 1. Validates and converts input to string +// 2. Uses Viper to parse YML content +// 3. Converts parsed content to a flat key-value map func (d *Parser) Parse(configContent interface{}) (map[string]interface{}, error) { content, ok := configContent.(string) if !ok { @@ -43,7 +60,7 @@ func (d *Parser) Parse(configContent interface{}) (map[string]interface{}, error } buffer := bytes.NewBufferString(content) - // 使用viper解析 + // Use Viper to parse the YML content err := vp.ReadConfig(buffer) if err != nil { return nil, err @@ -52,6 +69,15 @@ func (d *Parser) Parse(configContent interface{}) (map[string]interface{}, error return convertToMap(vp), nil } +// convertToMap converts Viper's parsed configuration to a flat key-value map +// Parameters: +// - vp: Viper instance containing parsed configuration +// +// Returns: +// - map[string]interface{}: Flattened key-value pairs from YML configuration +// +// This function extracts all keys and their values from Viper's parsed +// configuration and stores them in a simple map structure func convertToMap(vp *viper.Viper) map[string]interface{} { if vp == nil { return nil diff --git a/utils/utils.go b/utils/utils.go index ee20ddc1..2142af98 100644 --- a/utils/utils.go +++ b/utils/utils.go @@ -22,16 +22,27 @@ import ( ) const ( - //Empty 空字符串 + // Empty represents an empty string constant + // Used throughout the application for string comparisons and defaults Empty = "" ) var ( + // internalIPOnce ensures the internal IP is retrieved only once internalIPOnce sync.Once - internalIP = "" + // internalIP stores the cached internal IP address of the machine + internalIP = "" ) -// GetInternal 获取内部ip +// GetInternal retrieves the internal IPv4 address of the machine +// Returns: +// - string: The first non-loopback IPv4 address found +// +// This function: +// 1. Uses sync.Once to ensure single execution +// 2. Retrieves all network interface addresses +// 3. Finds the first non-loopback IPv4 address +// 4. Caches the result for subsequent calls func GetInternal() string { internalIPOnce.Do(func() { addrs, err := net.InterfaceAddrs() @@ -50,12 +61,29 @@ func GetInternal() string { return internalIP } -// IsNotNil 判断是否nil +// IsNotNil checks if an object is not nil +// Parameters: +// - object: The interface{} to check +// +// Returns: +// - bool: true if the object is not nil, false otherwise +// +// This is a convenience wrapper around IsNilObject with inverted logic func IsNotNil(object interface{}) bool { return !IsNilObject(object) } -// IsNilObject 判断是否空对象 +// IsNilObject determines if an object is nil or effectively nil +// Parameters: +// - object: The interface{} to check +// +// Returns: +// - bool: true if the object is nil or a nil interface value +// +// This function performs a thorough nil check that handles: +// 1. Direct nil values +// 2. nil interface values (chan, func, interface, map, pointer, slice) +// 3. Zero-value interfaces of reference types func IsNilObject(object interface{}) bool { if object == nil { return true