Skip to content

Commit

Permalink
add conf paladin
Browse files Browse the repository at this point in the history
  • Loading branch information
felixhao committed Apr 4, 2019
1 parent 7fc7de2 commit 1f5de24
Show file tree
Hide file tree
Showing 16 changed files with 1,647 additions and 0 deletions.
2 changes: 2 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
module github.com/bilibili/Kratos

require (
github.com/BurntSushi/toml v0.3.1
github.com/fatih/color v1.7.0
github.com/fsnotify/fsnotify v1.4.7
github.com/go-playground/locales v0.12.1 // indirect
github.com/go-playground/universal-translator v0.16.0 // indirect
github.com/gogo/protobuf v1.2.0
Expand Down
72 changes: 72 additions & 0 deletions pkg/conf/paladin/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
#### paladin

##### 项目简介

paladin 是一个config SDK客户端,包括了file、mock几个抽象功能,方便使用本地文件或者sven配置中心,并且集成了对象自动reload功能。


local files:
```
demo -conf=/data/conf/app/msm-servie.toml
// or dir
demo -conf=/data/conf/app/
```
example:
```
type exampleConf struct {
Bool bool
Int int64
Float float64
String string
}
func (e *exampleConf) Set(text string) error {
var ec exampleConf
if err := toml.Unmarshal([]byte(text), &ec); err != nil {
return err
}
*e = ec
return nil
}
func ExampleClient() {
if err := paladin.Init(); err != nil {
panic(err)
}
var (
ec exampleConf
eo exampleConf
m paladin.TOML
strs []string
)
// config unmarshal
if err := paladin.Get("example.toml").UnmarshalTOML(&ec); err != nil {
panic(err)
}
// config setter
if err := paladin.Watch("example.toml", &ec); err != nil {
panic(err)
}
// paladin map
if err := paladin.Watch("example.toml", &m); err != nil {
panic(err)
}
s, err := m.Value("key").String()
b, err := m.Value("key").Bool()
i, err := m.Value("key").Int64()
f, err := m.Value("key").Float64()
// value slice
err = m.Value("strings").Slice(&strs)
// watch key
for event := range paladin.WatchEvent(context.TODO(), "key") {
fmt.Println(event)
}
}
```

##### 编译环境

- **请只用 Golang v1.12.x 以上版本编译执行**

##### 依赖包
49 changes: 49 additions & 0 deletions pkg/conf/paladin/client.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package paladin

import (
"context"
)

const (
// EventAdd config add event.
EventAdd EventType = iota
// EventUpdate config update event.
EventUpdate
// EventRemove config remove event.
EventRemove
)

// EventType is config event.
type EventType int

// Event is watch event.
type Event struct {
Event EventType
Key string
Value string
}

// Watcher is config watcher.
type Watcher interface {
WatchEvent(context.Context, ...string) <-chan Event
Close() error
}

// Setter is value setter.
type Setter interface {
Set(string) error
}

// Getter is value getter.
type Getter interface {
// Get a config value by a config key(may be a sven filename).
Get(string) *Value
// GetAll return all config key->value map.
GetAll() *Map
}

// Client is config client.
type Client interface {
Watcher
Getter
}
86 changes: 86 additions & 0 deletions pkg/conf/paladin/default.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
package paladin

import (
"context"
"flag"

"github.com/bilibili/Kratos/pkg/log"
)

var (
// DefaultClient default client.
DefaultClient Client
confPath string
vars = make(map[string][]Setter) // NOTE: no thread safe
)

func init() {
flag.StringVar(&confPath, "conf", "", "default config path")
}

// Init init config client.
func Init() (err error) {
if confPath != "" {
DefaultClient, err = NewFile(confPath)
} else {
// TODO: config service
return
}
if err != nil {
return
}
go func() {
for event := range DefaultClient.WatchEvent(context.Background()) {
if event.Event != EventUpdate && event.Event != EventAdd {
continue
}
if sets, ok := vars[event.Key]; ok {
for _, s := range sets {
if err := s.Set(event.Value); err != nil {
log.Error("paladin: vars:%v event:%v error(%v)", s, event, err)
}
}
}
}
}()
return
}

// Watch watch on a key. The configuration implements the setter interface, which is invoked when the configuration changes.
func Watch(key string, s Setter) error {
v := DefaultClient.Get(key)
str, err := v.Raw()
if err != nil {
return err
}
if err := s.Set(str); err != nil {
return err
}
vars[key] = append(vars[key], s)
return nil
}

// WatchEvent watch on multi keys. Events are returned when the configuration changes.
func WatchEvent(ctx context.Context, keys ...string) <-chan Event {
return DefaultClient.WatchEvent(ctx, keys...)
}

// Get return value by key.
func Get(key string) *Value {
return DefaultClient.Get(key)
}

// GetAll return all config map.
func GetAll() *Map {
return DefaultClient.GetAll()
}

// Keys return values key.
func Keys() []string {
return DefaultClient.GetAll().Keys()
}

// Close close watcher.
func Close() error {
return DefaultClient.Close()
}
112 changes: 112 additions & 0 deletions pkg/conf/paladin/example_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
package paladin_test

import (
"context"
"fmt"

"github.com/bilibili/Kratos/pkg/conf/paladin"

"github.com/BurntSushi/toml"
)

type exampleConf struct {
Bool bool
Int int64
Float float64
String string
Strings []string
}

func (e *exampleConf) Set(text string) error {
var ec exampleConf
if err := toml.Unmarshal([]byte(text), &ec); err != nil {
return err
}
*e = ec
return nil
}

// ExampleClient is a example client usage.
// exmaple.toml:
/*
bool = true
int = 100
float = 100.1
string = "text"
strings = ["a", "b", "c"]
*/
func ExampleClient() {
if err := paladin.Init(); err != nil {
panic(err)
}
var ec exampleConf
// var setter
if err := paladin.Watch("example.toml", &ec); err != nil {
panic(err)
}
if err := paladin.Get("example.toml").UnmarshalTOML(&ec); err != nil {
panic(err)
}
// use exampleConf
// watch event key
go func() {
for event := range paladin.WatchEvent(context.TODO(), "key") {
fmt.Println(event)
}
}()
}

// ExampleMap is a example map usage.
// exmaple.toml:
/*
bool = true
int = 100
float = 100.1
string = "text"
strings = ["a", "b", "c"]
[object]
string = "text"
bool = true
int = 100
float = 100.1
strings = ["a", "b", "c"]
*/
func ExampleMap() {
var (
m paladin.TOML
strs []string
)
// paladin toml
if err := paladin.Watch("example.toml", &m); err != nil {
panic(err)
}
// value string
s, err := m.Get("string").String()
if err != nil {
s = "default"
}
fmt.Println(s)
// value bool
b, err := m.Get("bool").Bool()
if err != nil {
b = false
}
fmt.Println(b)
// value int
i, err := m.Get("int").Int64()
if err != nil {
i = 100
}
fmt.Println(i)
// value float
f, err := m.Get("float").Float64()
if err != nil {
f = 100.1
}
fmt.Println(f)
// value slice
if err = m.Get("strings").Slice(&strs); err == nil {
fmt.Println(strs)
}
}
Loading

0 comments on commit 1f5de24

Please sign in to comment.