Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
5caa12f
feat(gcfg): 添加配置监听器功能
LanceAdd Sep 23, 2025
67483fc
feat(gcfg):重构配置适配器以支持上下文传递
LanceAdd Sep 27, 2025
80e31e5
Merge branch 'master' into fix/gcfg-watcher
hailaz Sep 28, 2025
e6ea72e
fix(os/gcfg): 更新操作上下文类型以支持gctx.StrKey
hailaz Sep 28, 2025
fc83375
fix(os/gcfg): 修复获取Operation Value类型
LanceAdd Sep 28, 2025
fc76c8c
fix(os/gcfg): 整 WithOperation 签名参数类型从 gctx.StrKey 到 string 以简化接口定义
LanceAdd Sep 28, 2025
d3b09ba
Apply gci import order changes
github-actions[bot] Sep 28, 2025
e60ed41
fix(contrib/config/nacos): 完善单元测试
LanceAdd Sep 28, 2025
c594e61
fix(contrib/config/nacos): 完善单元测试
LanceAdd Sep 28, 2025
8b482fc
Merge branch 'master' into fix/gcfg-watcher
joy999 Sep 28, 2025
d4f5b87
fix(contrib/config/nacos): 优化配置变更通知逻辑,简化观察者调用
hailaz Sep 29, 2025
cf35fbf
fix(os/gcfg): 添加接口实现的编译时检查
hailaz Sep 29, 2025
4294f9f
fix(contrib/config/nacos): 修复上下文获取方法,增加类型安全检查
hailaz Sep 29, 2025
6734a9a
fix(contrib/config/polaris): - 在 polaris 客户端中实现配置监听器回调功能,补充缺少的注释
LanceAdd Sep 29, 2025
c4eb06c
Merge branch 'gogf:master' into fix/gcfg-watcher
LanceAdd Sep 29, 2025
5972a83
Merge branch 'master' into fix/gcfg-watcher
hailaz Sep 30, 2025
06fc475
Merge branch 'master' into fix/gcfg-watcher
hailaz Oct 10, 2025
0e0d431
feat(contrib/config): 为 Apollo 和 Consul 配置中心添加监听器管理机制
LanceAdd Oct 10, 2025
d422c23
Apply gci import order changes
github-actions[bot] Oct 10, 2025
ac63193
feat(consul): 实现配置接口和监听接口
LanceAdd Oct 10, 2025
e7984b5
fix: 优化上下文设置方法,简化参数处理
hailaz Oct 10, 2025
4e839d0
refactor: 统一适配器上下文创建方法,简化代码结构
hailaz Oct 10, 2025
a84162c
refactor: 重命名适配器上下文方法,统一内容设置和获取逻辑
hailaz Oct 10, 2025
ad32a9e
refactor: 统一适配器上下文操作常量,简化代码结构
hailaz Oct 10, 2025
b31b5d9
refactor: 优化配置变更函数中的断言逻辑,提升可读性
hailaz Oct 10, 2025
6e546f6
feat(kubecm): 实现Kubecm配置监听和上下文适配器
LanceAdd Oct 13, 2025
902c698
Apply gci import order changes
github-actions[bot] Oct 13, 2025
851add6
feat(kubecm): 添加编译时接口实现检查
LanceAdd Oct 13, 2025
aaa9ad1
feat(kubecm): 添加注释
LanceAdd Oct 13, 2025
6863030
Merge branch 'master' into fix/gcfg-watcher
hailaz Oct 14, 2025
b7716a9
Merge branch 'master' into fix/gcfg-watcher
hailaz Oct 15, 2025
4f75591
Apply suggestion from @Copilot
hailaz Oct 15, 2025
f9659bf
Apply suggestion from @Copilot
hailaz Oct 15, 2025
c7c72c9
feat: 重构配置适配器,使用WatcherRegistry管理观察者
hailaz Oct 15, 2025
5d4a6a6
Apply gci import order changes
github-actions[bot] Oct 15, 2025
60d38de
refactor: 清理代码,移除多余的空行
hailaz Oct 15, 2025
463b5bb
Merge branch 'master' into fix/gcfg-watcher
hailaz Oct 15, 2025
258ab00
test(os/gcfg): 用 WaitGroup 替代 time.Sleep 同步 watcher 测试
hailaz Oct 15, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 43 additions & 7 deletions contrib/config/apollo/apollo.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,12 @@ import (
"github.com/gogf/gf/v2/util/gconv"
)

var (
// Compile-time checking for interface implementation.
_ gcfg.Adapter = (*Client)(nil)
_ gcfg.WatcherAdapter = (*Client)(nil)
)

// Config is the configuration object for apollo client.
type Config struct {
AppID string `v:"required"` // See apolloConfig.Config.
Expand All @@ -38,9 +44,10 @@ type Config struct {

// 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.
config Config // Config object when created.
client agollo.Client // Apollo client.
value *g.Var // Configmap content cached. It is `*gjson.Json` value internally.
watchers *gcfg.WatcherRegistry // Watchers for watching file changes.
}

// New creates and returns gcfg.Adapter implementing using apollo service.
Expand All @@ -54,8 +61,9 @@ func New(ctx context.Context, config Config) (adapter gcfg.Adapter, err error) {
config.NamespaceName = storage.GetDefaultNamespace()
}
client := &Client{
config: config,
value: g.NewVar(nil, true),
config: config,
value: g.NewVar(nil, true),
watchers: gcfg.NewWatcherRegistry(),
}
// Apollo client.
client.client, err = agollo.StartWithConfig(func() (*apolloConfig.AppConfig, error) {
Expand Down Expand Up @@ -89,7 +97,7 @@ 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
namespace := c.config.NamespaceName
if len(resource) > 0 {
namespace = resource[0]
}
Expand Down Expand Up @@ -132,18 +140,46 @@ func (c *Client) OnNewestChange(event *storage.FullChangeEvent) {
}

func (c *Client) updateLocalValue(ctx context.Context) (err error) {
var j = gjson.New(nil)
j := gjson.New(nil)
content := gjson.New(nil, true)
cache := c.client.GetConfigCache(c.config.NamespaceName)
cache.Range(func(key, value any) bool {
err = j.Set(gconv.String(key), value)
if err != nil {
return false
}
err = content.Set(gconv.String(key), value)
if err != nil {
return false
}
return true
})
cache.Clear()
if err == nil {
c.value.Set(j)
adapterCtx := NewAdapterCtx(ctx).WithOperation(gcfg.OperationUpdate).WithNamespace(c.config.NamespaceName).
WithAppId(c.config.AppID).WithCluster(c.config.Cluster).WithContent(content)
c.notifyWatchers(adapterCtx.Ctx)
}
return
}

// AddWatcher adds a watcher for the specified configuration file.
func (c *Client) AddWatcher(name string, f func(ctx context.Context)) {
c.watchers.Add(name, f)
}

// RemoveWatcher removes the watcher for the specified configuration file.
func (c *Client) RemoveWatcher(name string) {
c.watchers.Remove(name)
}

// GetWatcherNames returns all watcher names.
func (c *Client) GetWatcherNames() []string {
return c.watchers.GetNames()
}

// notifyWatchers notifies all watchers.
func (c *Client) notifyWatchers(ctx context.Context) {
c.watchers.Notify(ctx)
}
132 changes: 132 additions & 0 deletions contrib/config/apollo/apollo_adapter_ctx.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
// 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/gogf/gf/v2/encoding/gjson"
"github.com/gogf/gf/v2/os/gcfg"
"github.com/gogf/gf/v2/os/gctx"
)

const (
// ContextKeyNamespace is the context key for namespace
ContextKeyNamespace gctx.StrKey = "namespace"
// ContextKeyAppId is the context key for appId
ContextKeyAppId gctx.StrKey = "appId"
// ContextKeyCluster is the context key for cluster
ContextKeyCluster gctx.StrKey = "cluster"
)

// ApolloAdapterCtx is the context adapter for Apollo configuration
type ApolloAdapterCtx struct {
Ctx context.Context
}

// NewAdapterCtxWithCtx creates and returns a new ApolloAdapterCtx with the given context.
func NewAdapterCtxWithCtx(ctx context.Context) *ApolloAdapterCtx {
if ctx == nil {
ctx = context.Background()
}
return &ApolloAdapterCtx{Ctx: ctx}
}

// NewAdapterCtx creates and returns a new ApolloAdapterCtx.
// If context is provided, it will be used; otherwise, a background context is created.
func NewAdapterCtx(ctx ...context.Context) *ApolloAdapterCtx {
if len(ctx) > 0 {
return NewAdapterCtxWithCtx(ctx[0])
}
return NewAdapterCtxWithCtx(context.Background())
}

// GetAdapterCtx creates a new ApolloAdapterCtx with the given context
func GetAdapterCtx(ctx context.Context) *ApolloAdapterCtx {
return NewAdapterCtxWithCtx(ctx)
}

// WithOperation sets the operation in the context
func (a *ApolloAdapterCtx) WithOperation(operation gcfg.OperationType) *ApolloAdapterCtx {
a.Ctx = context.WithValue(a.Ctx, gcfg.ContextKeyOperation, operation)
return a
}

// WithNamespace sets the namespace in the context
func (a *ApolloAdapterCtx) WithNamespace(namespace string) *ApolloAdapterCtx {
a.Ctx = context.WithValue(a.Ctx, ContextKeyNamespace, namespace)
return a
}

// WithAppId sets the appId in the context
func (a *ApolloAdapterCtx) WithAppId(appId string) *ApolloAdapterCtx {
a.Ctx = context.WithValue(a.Ctx, ContextKeyAppId, appId)
return a
}

// WithCluster sets the cluster in the context
func (a *ApolloAdapterCtx) WithCluster(cluster string) *ApolloAdapterCtx {
a.Ctx = context.WithValue(a.Ctx, ContextKeyCluster, cluster)
return a
}

// WithContent sets the content in the context
func (a *ApolloAdapterCtx) WithContent(content *gjson.Json) *ApolloAdapterCtx {
a.Ctx = context.WithValue(a.Ctx, gcfg.ContextKeyContent, content)
return a
}

// GetNamespace retrieves the namespace from the context
func (a *ApolloAdapterCtx) GetNamespace() string {
if v := a.Ctx.Value(ContextKeyNamespace); v != nil {
if s, ok := v.(string); ok {
return s
}
}
return ""
}

// GetAppId retrieves the appId from the context
func (a *ApolloAdapterCtx) GetAppId() string {
if v := a.Ctx.Value(ContextKeyAppId); v != nil {
if s, ok := v.(string); ok {
return s
}
}
return ""
}

// GetCluster retrieves the cluster from the context
func (a *ApolloAdapterCtx) GetCluster() string {
if v := a.Ctx.Value(ContextKeyCluster); v != nil {
if s, ok := v.(string); ok {
return s
}
}
return ""
}

// GetContent retrieves the content from the context
func (a *ApolloAdapterCtx) GetContent() *gjson.Json {
if v := a.Ctx.Value(gcfg.ContextKeyContent); v != nil {
if s, ok := v.(*gjson.Json); ok {
return s
}
}
return gjson.New(nil)
}

// GetOperation retrieves the operation from the context
func (a *ApolloAdapterCtx) GetOperation() gcfg.OperationType {
if v := a.Ctx.Value(gcfg.ContextKeyOperation); v != nil {
if s, ok := v.(gcfg.OperationType); ok {
return s
}
}
return ""
}
51 changes: 47 additions & 4 deletions contrib/config/consul/consul.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,12 @@ import (
"github.com/gogf/gf/v2/os/glog"
)

var (
// Compile-time checking for interface implementation.
_ gcfg.Adapter = (*Client)(nil)
_ gcfg.WatcherAdapter = (*Client)(nil)
)

// Config is the configuration object for consul client.
type Config struct {
// api.Config in consul package
Expand All @@ -41,6 +47,8 @@ type Client struct {
client *api.Client
// Configmap content cached. It is `*gjson.Json` value internally.
value *g.Var
// Watchers for watching file changes.
watchers *gcfg.WatcherRegistry
}

// New creates and returns gcfg.Adapter implementing using consul service.
Expand All @@ -55,8 +63,9 @@ func New(ctx context.Context, config Config) (adapter gcfg.Adapter, err error) {
}

client := &Client{
config: config,
value: g.NewVar(nil, true),
config: config,
value: g.NewVar(nil, true),
watchers: gcfg.NewWatcherRegistry(),
}

client.client, err = api.NewClient(&config.ConsulConfig)
Expand Down Expand Up @@ -156,13 +165,26 @@ func (c *Client) addWatcher() (err error) {
if v, ok = raw.(*api.KVPair); !ok {
return
}

if err = c.doUpdate(v.Value); err != nil {
err = c.doUpdate(v.Value)
if err != nil {
c.config.Logger.Errorf(
context.Background(),
"watch config from consul path %+v update failed: %s",
c.config.Path, err,
)
} else {
var m *gjson.Json
m, err = gjson.LoadContent(v.Value, true)
if err != nil {
c.config.Logger.Errorf(
context.Background(),
"watch config from consul path %+v parse failed: %s",
c.config.Path, err,
)
} else {
adapterCtx := NewAdapterCtx().WithOperation(gcfg.OperationUpdate).WithPath(c.config.Path).WithContent(m)
c.notifyWatchers(adapterCtx.Ctx)
}
}
}

Expand All @@ -173,6 +195,7 @@ func (c *Client) addWatcher() (err error) {
return nil
}

// startAsynchronousWatch starts the asynchronous watch.
func (c *Client) startAsynchronousWatch(plan *watch.Plan) {
if err := plan.Run(c.config.ConsulConfig.Address); err != nil {
c.config.Logger.Errorf(
Expand All @@ -182,3 +205,23 @@ func (c *Client) startAsynchronousWatch(plan *watch.Plan) {
)
}
}

// AddWatcher adds a watcher for the specified configuration file.
func (c *Client) AddWatcher(name string, f func(ctx context.Context)) {
c.watchers.Add(name, f)
}

// RemoveWatcher removes the watcher for the specified configuration file.
func (c *Client) RemoveWatcher(name string) {
c.watchers.Remove(name)
}

// GetWatcherNames returns all watcher names.
func (c *Client) GetWatcherNames() []string {
return c.watchers.GetNames()
}

// notifyWatchers notifies all watchers.
func (c *Client) notifyWatchers(ctx context.Context) {
c.watchers.Notify(ctx)
}
Loading
Loading