gogf / gf

@@ -0,0 +1,148 @@
Loading
1 +
// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
2 +
//
3 +
// This Source Code Form is subject to the terms of the MIT License.
4 +
// If a copy of the MIT was not distributed with this file,
5 +
// You can obtain one at https://github.com/gogf/gf.
6 +
7 +
// Package apollo implements gcfg.Adapter using apollo service.
8 +
package apollo
9 +
10 +
import (
11 +
	"context"
12 +
13 +
	"github.com/apolloconfig/agollo/v4"
14 +
	apolloConfig "github.com/apolloconfig/agollo/v4/env/config"
15 +
	"github.com/apolloconfig/agollo/v4/storage"
16 +
	"github.com/gogf/gf/v2/encoding/gjson"
17 +
	"github.com/gogf/gf/v2/errors/gerror"
18 +
	"github.com/gogf/gf/v2/frame/g"
19 +
	"github.com/gogf/gf/v2/os/gcfg"
20 +
	"github.com/gogf/gf/v2/os/gctx"
21 +
	"github.com/gogf/gf/v2/util/gconv"
22 +
)
23 +
24 +
// Config is the configuration object for apollo client.
25 +
type Config struct {
26 +
	AppID             string `v:"required"` // See apolloConfig.Config.
27 +
	IP                string `v:"required"` // See apolloConfig.Config.
28 +
	Cluster           string `v:"required"` // See apolloConfig.Config.
29 +
	NamespaceName     string // See apolloConfig.Config.
30 +
	IsBackupConfig    bool   // See apolloConfig.Config.
31 +
	BackupConfigPath  string // See apolloConfig.Config.
32 +
	Secret            string // See apolloConfig.Config.
33 +
	SyncServerTimeout int    // See apolloConfig.Config.
34 +
	MustStart         bool   // See apolloConfig.Config.
35 +
	Watch             bool   // Watch updates, which updates configuration when configmap changes.
36 +
}
37 +
38 +
// Client implements gcfg.Adapter implementing using apollo service.
39 +
type Client struct {
40 +
	config Config        // Config object when created.
41 +
	client agollo.Client // Apollo client.
42 +
	value  *g.Var        // Configmap content cached. It is `*gjson.Json` value internally.
43 +
}
44 +
45 +
// New creates and returns gcfg.Adapter implementing using apollo service.
46 +
func New(ctx context.Context, config Config) (adapter gcfg.Adapter, err error) {
47 +
	// Data validation.
48 +
	err = g.Validator().Data(config).Run(ctx)
49 +
	if err != nil {
50 +
		return nil, err
51 +
	}
52 +
	if config.NamespaceName == "" {
53 +
		config.NamespaceName = storage.GetDefaultNamespace()
54 +
	}
55 +
	client := &Client{
56 +
		config: config,
57 +
		value:  g.NewVar(nil, true),
58 +
	}
59 +
	// Apollo client.
60 +
	client.client, err = agollo.StartWithConfig(func() (*apolloConfig.AppConfig, error) {
61 +
		return &apolloConfig.AppConfig{
62 +
			AppID:             config.AppID,
63 +
			Cluster:           config.Cluster,
64 +
			NamespaceName:     config.NamespaceName,
65 +
			IP:                config.IP,
66 +
			IsBackupConfig:    config.IsBackupConfig,
67 +
			BackupConfigPath:  config.BackupConfigPath,
68 +
			Secret:            config.Secret,
69 +
			SyncServerTimeout: config.SyncServerTimeout,
70 +
			MustStart:         config.MustStart,
71 +
		}, nil
72 +
	})
73 +
	if err != nil {
74 +
		return nil, gerror.Wrapf(err, `create apollo client failed with config: %+v`, config)
75 +
	}
76 +
	if config.Watch {
77 +
		client.client.AddChangeListener(client)
78 +
	}
79 +
	return client, nil
80 +
}
81 +
82 +
// Available checks and returns the backend configuration service is available.
83 +
// The optional parameter `resource` specifies certain configuration resource.
84 +
//
85 +
// Note that this function does not return error as it just does simply check for
86 +
// backend configuration service.
87 +
func (c *Client) Available(ctx context.Context, resource ...string) (ok bool) {
88 +
	if len(resource) == 0 && !c.value.IsNil() {
89 +
		return true
90 +
	}
91 +
	var namespace = c.config.NamespaceName
92 +
	if len(resource) > 0 {
93 +
		namespace = resource[0]
94 +
	}
95 +
	return c.client.GetConfig(namespace) != nil
96 +
}
97 +
98 +
// Get retrieves and returns value by specified `pattern` in current resource.
99 +
// Pattern like:
100 +
// "x.y.z" for map item.
101 +
// "x.0.y" for slice item.
102 +
func (c *Client) Get(ctx context.Context, pattern string) (value interface{}, err error) {
103 +
	if c.value.IsNil() {
104 +
		if err = c.updateLocalValue(ctx); err != nil {
105 +
			return nil, err
106 +
		}
107 +
	}
108 +
	return c.value.Val().(*gjson.Json).Get(pattern).Val(), nil
109 +
}
110 +
111 +
// Data retrieves and returns all configuration data in current resource as map.
112 +
// Note that this function may lead lots of memory usage if configuration data is too large,
113 +
// you can implement this function if necessary.
114 +
func (c *Client) Data(ctx context.Context) (data map[string]interface{}, err error) {
115 +
	if c.value.IsNil() {
116 +
		if err = c.updateLocalValue(ctx); err != nil {
117 +
			return nil, err
118 +
		}
119 +
	}
120 +
	return c.value.Val().(*gjson.Json).Map(), nil
121 +
}
122 +
123 +
// OnChange is called when config changes.
124 +
func (c *Client) OnChange(event *storage.ChangeEvent) {
125 +
	_ = c.updateLocalValue(gctx.New())
126 +
}
127 +
128 +
// OnNewestChange is called when any config changes.
129 +
func (c *Client) OnNewestChange(event *storage.FullChangeEvent) {
130 +
	// Nothing to do.
131 +
}
132 +
133 +
func (c *Client) updateLocalValue(ctx context.Context) (err error) {
134 +
	var j = gjson.New(nil)
135 +
	cache := c.client.GetConfigCache(c.config.NamespaceName)
136 +
	cache.Range(func(key, value interface{}) bool {
137 +
		err = j.Set(gconv.String(key), value)
138 +
		if err != nil {
139 +
			return false
140 +
		}
141 +
		return true
142 +
	})
143 +
	cache.Clear()
144 +
	if err == nil {
145 +
		c.value.Set(j)
146 +
	}
147 +
	return
148 +
}

@@ -25,18 +25,19 @@
Loading
25 25
26 26
// Client implements gcfg.Adapter.
27 27
type Client struct {
28 -
	Config        // Config object when created.
29 -
	value  *g.Var // Configmap content cached. It is `*gjson.Json` value internally.
28 +
	config Config                // Config object when created.
29 +
	client *kubernetes.Clientset // Kubernetes client.
30 +
	value  *g.Var                // Configmap content cached. It is `*gjson.Json` value internally.
30 31
}
31 32
32 33
// Config for Client.
33 34
type Config struct {
34 35
	ConfigMap  string                `v:"required"` // ConfigMap name.
35 36
	DataItem   string                `v:"required"` // DataItem is the key item in Configmap data.
36 -
	Namespace  string                // (Optional) Specify the namespace for configmap.
37 -
	RestConfig *rest.Config          // (Optional) Custom rest config for kube client.
38 -
	KubeClient *kubernetes.Clientset // (Optional) Custom kube client.
39 -
	Watch      bool                  // (Optional) Watch updates, which updates configuration when configmap changes.
37 +
	Namespace  string                // Specify the namespace for configmap.
38 +
	RestConfig *rest.Config          // Custom rest config for kube client.
39 +
	KubeClient *kubernetes.Clientset // Custom kube client.
40 +
	Watch      bool                  // Watch updates, which updates configuration when configmap changes.
40 41
}
41 42
42 43
// New creates and returns gcfg.Adapter implementing using kubernetes configmap.
@@ -60,7 +61,8 @@
Loading
60 61
		}
61 62
	}
62 63
	adapter = &Client{
63 -
		Config: config,
64 +
		config: config,
65 +
		client: config.KubeClient,
64 66
		value:  g.NewVar(nil, true),
65 67
	}
66 68
	return
@@ -77,10 +79,10 @@
Loading
77 79
	}
78 80
79 81
	var (
80 -
		namespace     = gutil.GetOrDefaultStr(Namespace(), c.Namespace)
81 -
		configMapName = gutil.GetOrDefaultStr(c.ConfigMap, configMap...)
82 +
		namespace     = gutil.GetOrDefaultStr(Namespace(), c.config.Namespace)
83 +
		configMapName = gutil.GetOrDefaultStr(c.config.ConfigMap, configMap...)
82 84
	)
83 -
	_, err := c.KubeClient.CoreV1().ConfigMaps(namespace).Get(ctx, configMapName, kubeMetaV1.GetOptions{})
85 +
	_, err := c.config.KubeClient.CoreV1().ConfigMaps(namespace).Get(ctx, configMapName, kubeMetaV1.GetOptions{})
84 86
	if err != nil {
85 87
		return false
86 88
	}
@@ -114,7 +116,7 @@
Loading
114 116
115 117
// init retrieves and caches the configmap content.
116 118
func (c *Client) updateLocalValueAndWatch(ctx context.Context) (err error) {
117 -
	var namespace = gutil.GetOrDefaultStr(Namespace(), c.Namespace)
119 +
	var namespace = gutil.GetOrDefaultStr(Namespace(), c.config.Namespace)
118 120
	err = c.doUpdate(ctx, namespace)
119 121
	if err != nil {
120 122
		return err
@@ -127,19 +129,19 @@
Loading
127 129
}
128 130
129 131
func (c *Client) doUpdate(ctx context.Context, namespace string) (err error) {
130 -
	cm, err := c.KubeClient.CoreV1().ConfigMaps(namespace).Get(ctx, c.ConfigMap, kubeMetaV1.GetOptions{})
132 +
	cm, err := c.client.CoreV1().ConfigMaps(namespace).Get(ctx, c.config.ConfigMap, kubeMetaV1.GetOptions{})
131 133
	if err != nil {
132 134
		return gerror.Wrapf(
133 135
			err,
134 136
			`retrieve configmap "%s" from namespace "%s" failed`,
135 -
			c.ConfigMap, namespace,
137 +
			c.config.ConfigMap, namespace,
136 138
		)
137 139
	}
138 140
	var j *gjson.Json
139 -
	if j, err = gjson.LoadContent(cm.Data[c.DataItem]); err != nil {
141 +
	if j, err = gjson.LoadContent(cm.Data[c.config.DataItem]); err != nil {
140 142
		return gerror.Wrapf(
141 143
			err,
142 -
			`parse config map item from %s[%s] failed`, c.ConfigMap, c.DataItem,
144 +
			`parse config map item from %s[%s] failed`, c.config.ConfigMap, c.config.DataItem,
143 145
		)
144 146
	}
145 147
	c.value.Set(j)
@@ -147,19 +149,19 @@
Loading
147 149
}
148 150
149 151
func (c *Client) doWatch(ctx context.Context, namespace string) (err error) {
150 -
	if !c.Watch {
152 +
	if !c.config.Watch {
151 153
		return nil
152 154
	}
153 155
	var watchHandler watch.Interface
154 -
	watchHandler, err = c.KubeClient.CoreV1().ConfigMaps(namespace).Watch(ctx, kubeMetaV1.ListOptions{
155 -
		FieldSelector: fmt.Sprintf(`metadata.name=%s`, c.ConfigMap),
156 +
	watchHandler, err = c.client.CoreV1().ConfigMaps(namespace).Watch(ctx, kubeMetaV1.ListOptions{
157 +
		FieldSelector: fmt.Sprintf(`metadata.name=%s`, c.config.ConfigMap),
156 158
		Watch:         true,
157 159
	})
158 160
	if err != nil {
159 161
		return gerror.Wrapf(
160 162
			err,
161 163
			`watch configmap "%s" from namespace "%s" failed`,
162 -
			c.ConfigMap, namespace,
164 +
			c.config.ConfigMap, namespace,
163 165
		)
164 166
	}
165 167
	go func() {
Files Coverage
container 95.54%
contrib 69.99%
crypto 80.10%
database 70.29%
debug/gdebug 53.26%
encoding 81.70%
errors 77.88%
frame 53.52%
i18n/gi18n 81.13%
internal 79.29%
net 64.38%
os 70.06%
test/gtest 56.64%
text 89.77%
util 77.34%
Project Totals (580 files) 76.50%
3158026948
go-1.17-386
3158026948
go-1.17-amd64
3158026948
go-1.16-386
3158026948
go-1.18-amd64
3158026948
go-1.15-386
3158026948
go-1.16-amd64
3158026948
go-1.15-amd64
3158026948
go-1.18-386
3158026948
go-1.18-amd64

No yaml found.

Create your codecov.yml to customize your Codecov experience

Sunburst
The inner-most circle is the entire project, moving away from the center are folders then, finally, a single file. The size and color of each slice is representing the number of statements and the coverage, respectively.
Icicle
The top section represents the entire project. Proceeding with folders and finally individual files. The size and color of each slice is representing the number of statements and the coverage, respectively.
Grid
Each block represents a single file in the project. The size and color of each block is represented by the number of statements and the coverage, respectively.
Loading