mirror of
https://gitee.com/johng/gf.git
synced 2024-12-02 12:17:53 +08:00
6cb91021cf
* feat: create polaris config * feat: improve code * feat: modify config file path Co-authored-by: John Guo <john@johng.cn>
150 lines
4.8 KiB
Go
150 lines
4.8 KiB
Go
// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
|
|
//
|
|
// This Source Code Form is subject to the terms of the MIT License.
|
|
// If a copy of the MIT was not distributed with this file,
|
|
// You can obtain one at https://github.com/gogf/gf.
|
|
|
|
// Package apollo implements gcfg.Adapter using apollo service.
|
|
package apollo
|
|
|
|
import (
|
|
"context"
|
|
|
|
"github.com/apolloconfig/agollo/v4"
|
|
apolloConfig "github.com/apolloconfig/agollo/v4/env/config"
|
|
"github.com/apolloconfig/agollo/v4/storage"
|
|
|
|
"github.com/gogf/gf/v2/encoding/gjson"
|
|
"github.com/gogf/gf/v2/errors/gerror"
|
|
"github.com/gogf/gf/v2/frame/g"
|
|
"github.com/gogf/gf/v2/os/gcfg"
|
|
"github.com/gogf/gf/v2/os/gctx"
|
|
"github.com/gogf/gf/v2/util/gconv"
|
|
)
|
|
|
|
// Config is the configuration object for apollo client.
|
|
type Config struct {
|
|
AppID string `v:"required"` // See apolloConfig.Config.
|
|
IP string `v:"required"` // See apolloConfig.Config.
|
|
Cluster string `v:"required"` // See apolloConfig.Config.
|
|
NamespaceName string // See apolloConfig.Config.
|
|
IsBackupConfig bool // See apolloConfig.Config.
|
|
BackupConfigPath string // See apolloConfig.Config.
|
|
Secret string // See apolloConfig.Config.
|
|
SyncServerTimeout int // See apolloConfig.Config.
|
|
MustStart bool // See apolloConfig.Config.
|
|
Watch bool // Watch watches remote configuration updates, which updates local configuration in memory immediately when remote configuration changes.
|
|
}
|
|
|
|
// Client implements gcfg.Adapter implementing using apollo service.
|
|
type Client struct {
|
|
config Config // Config object when created.
|
|
client agollo.Client // Apollo client.
|
|
value *g.Var // Configmap content cached. It is `*gjson.Json` value internally.
|
|
}
|
|
|
|
// New creates and returns gcfg.Adapter implementing using apollo service.
|
|
func New(ctx context.Context, config Config) (adapter gcfg.Adapter, err error) {
|
|
// Data validation.
|
|
err = g.Validator().Data(config).Run(ctx)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if config.NamespaceName == "" {
|
|
config.NamespaceName = storage.GetDefaultNamespace()
|
|
}
|
|
client := &Client{
|
|
config: config,
|
|
value: g.NewVar(nil, true),
|
|
}
|
|
// Apollo client.
|
|
client.client, err = agollo.StartWithConfig(func() (*apolloConfig.AppConfig, error) {
|
|
return &apolloConfig.AppConfig{
|
|
AppID: config.AppID,
|
|
Cluster: config.Cluster,
|
|
NamespaceName: config.NamespaceName,
|
|
IP: config.IP,
|
|
IsBackupConfig: config.IsBackupConfig,
|
|
BackupConfigPath: config.BackupConfigPath,
|
|
Secret: config.Secret,
|
|
SyncServerTimeout: config.SyncServerTimeout,
|
|
MustStart: config.MustStart,
|
|
}, nil
|
|
})
|
|
if err != nil {
|
|
return nil, gerror.Wrapf(err, `create apollo client failed with config: %+v`, config)
|
|
}
|
|
if config.Watch {
|
|
client.client.AddChangeListener(client)
|
|
}
|
|
return client, nil
|
|
}
|
|
|
|
// Available checks and returns the backend configuration service is available.
|
|
// The optional parameter `resource` specifies certain configuration resource.
|
|
//
|
|
// Note that this function does not return error as it just does simply check for
|
|
// backend configuration service.
|
|
func (c *Client) Available(ctx context.Context, resource ...string) (ok bool) {
|
|
if len(resource) == 0 && !c.value.IsNil() {
|
|
return true
|
|
}
|
|
var namespace = c.config.NamespaceName
|
|
if len(resource) > 0 {
|
|
namespace = resource[0]
|
|
}
|
|
return c.client.GetConfig(namespace) != nil
|
|
}
|
|
|
|
// Get retrieves and returns value by specified `pattern` in current resource.
|
|
// Pattern like:
|
|
// "x.y.z" for map item.
|
|
// "x.0.y" for slice item.
|
|
func (c *Client) Get(ctx context.Context, pattern string) (value interface{}, err error) {
|
|
if c.value.IsNil() {
|
|
if err = c.updateLocalValue(ctx); err != nil {
|
|
return nil, err
|
|
}
|
|
}
|
|
return c.value.Val().(*gjson.Json).Get(pattern).Val(), nil
|
|
}
|
|
|
|
// Data retrieves and returns all configuration data in current resource as map.
|
|
// Note that this function may lead lots of memory usage if configuration data is too large,
|
|
// you can implement this function if necessary.
|
|
func (c *Client) Data(ctx context.Context) (data map[string]interface{}, err error) {
|
|
if c.value.IsNil() {
|
|
if err = c.updateLocalValue(ctx); err != nil {
|
|
return nil, err
|
|
}
|
|
}
|
|
return c.value.Val().(*gjson.Json).Map(), nil
|
|
}
|
|
|
|
// OnChange is called when config changes.
|
|
func (c *Client) OnChange(event *storage.ChangeEvent) {
|
|
_ = c.updateLocalValue(gctx.New())
|
|
}
|
|
|
|
// OnNewestChange is called when any config changes.
|
|
func (c *Client) OnNewestChange(event *storage.FullChangeEvent) {
|
|
// Nothing to do.
|
|
}
|
|
|
|
func (c *Client) updateLocalValue(ctx context.Context) (err error) {
|
|
var j = gjson.New(nil)
|
|
cache := c.client.GetConfigCache(c.config.NamespaceName)
|
|
cache.Range(func(key, value interface{}) bool {
|
|
err = j.Set(gconv.String(key), value)
|
|
if err != nil {
|
|
return false
|
|
}
|
|
return true
|
|
})
|
|
cache.Clear()
|
|
if err == nil {
|
|
c.value.Set(j)
|
|
}
|
|
return
|
|
}
|