Skip to content

Commit

Permalink
Combine all commits into one
Browse files Browse the repository at this point in the history
  • Loading branch information
zhu-mi-shan committed Jun 18, 2024
1 parent 93a584e commit f596224
Show file tree
Hide file tree
Showing 19 changed files with 1,704 additions and 2 deletions.
1 change: 0 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -27,4 +27,3 @@ output/*

# Vscode files
.vscode

188 changes: 187 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1 +1,187 @@
# .github
# .github
example中为使用示例,完整example代码地址:https://github.com/zhu-mi-shan/optionloader_example
使用该组件需要安装etcd。
etcd中存储的配置文件例子如下:
server:
```
json_data='{"ServerBasicInfo": {"ServiceName": "echo_server_service","Method": "method1","Tags": {"tag1": "v1","tag2": "v2"}},"ServiceAddr": [{"Network": "tcd","Address": "127.0.0.1:8889"}],"MuxTransport": true,"MyConfig":{"configOne": "This is configOne","configTwo": ["Welcome","to","configTwo","!"]}}'
etcdctl put "/KitexConfig/echo_server_service" "$(echo -n $json_data)"
```
client:
```
json_data='{"ClientBasicInfo":{"ServiceName": "echo_client_service","Method": "method1","Tags": {"tag1": "v1","tag2": "v2"}},"HostPorts": ["0.0.0.0:8888","0.0.0.0:8889"],"DestService": "echo_server_service","Protocol": "HTTP","Connection":{"Method": "LongConnection","LongConnection":{"MinIdlePerAddress": 1,"MaxIdlePerAddress": 10,"MaxIdleGlobal": 100,"MaxIdleTimeout": "1m"},"MuxConnection":{"ConnNum": 3}},"MyConfig":{"configOne": "This is configOne","configTwo": ["Welcome","to","configTwo","!"]}}'
etcdctl put "/KitexConfig/echo_client_service/echo_server_service" "$(echo -n $json_data)"
```
服务端,客户端均支持自定义新的配置文件结构config,自定义新的数据读取方式decoder, 以及新的解析option方法translator
server端示例:
```
const (
serverServiceName = "echo_server_service"
)
// 用户可以自定义读取数据的类型,要求通过Decode返回一个字节流
type myConfigParser struct {
}
func (p *myConfigParser) Decode(data []byte, config *etcdServer.EtcdConfig) error {
return json.Unmarshal(data, config)
}
// 用户可以自定义新增Config文件结构,并且默认的的Config文件结构仍然存在
type myConfig struct {
ConfigOne *string `mapstructure:"configOne"`
ConfigTwo []string `mapstructure:"configTwo"`
}
func (r *myConfig) String() string {
var output string
if r.ConfigOne != nil {
output += fmt.Sprintf("ConfigOne: %s\n", *r.ConfigOne)
}
if r.ConfigTwo != nil {
output += fmt.Sprintf("ConfigTwo: %v\n", r.ConfigTwo)
}
return output
}
// 用户可自定义Translator,用于将myConfig解析成Options
func myTranslator(config *etcdServer.EtcdConfig) ([]kitexserver.Option, error) {
c := config.MyConfig
var opts []kitexserver.Option
//具体处理逻辑
_ = opts
fmt.Println("myConfigTranslator run! myConfig:" + c.String())
return opts, nil
}
func main() {
readerOptions := etcdServer.ReaderOptions{
ConfigParser: &myConfigParser{},
MyConfig: &myConfig{},
}
utils.Printpath()
reader, err := etcdServer.NewReader(readerOptions)
//reader, err := etcdClient.NewReader(etcdClient.ReaderOptions{})//使用默认值时的
if err != nil {
log.Fatal(err)
return
}
myTranslators := []etcdServer.Translator{myTranslator}
loader, err := etcdServer.NewLoader(serverServiceName, reader, myTranslators...)
if err != nil {
log.Fatal(err)
return
}
err = loader.Load()
if err != nil {
log.Fatal(err)
return
}
fmt.Println("Options: ", loader.GetSuite().Options())
config, _ := reader.GetConfig()
fmt.Print("Config:", config.String())
svr := example.NewServer(new(TestServiceImpl), kitexserver.WithSuite(loader.GetSuite()))
err = svr.Run()
if err != nil {
log.Println(err.Error())
}
}
```
client端示例:
```
const (
serverServiceName = "echo_server_service"
clientServiceName = "echo_client_service"
)
// 用户可以自定义读取数据的类型,要求通过Decode返回一个字节流
type myConfigParser struct {
}
func (p *myConfigParser) Decode(data []byte, config *etcdClient.EtcdConfig) error {
return json.Unmarshal(data, config)
}
// 用户可以自定义新增Config文件结构,并且默认的的Config文件结构仍然存在
type myConfig struct {
ConfigOne *string `mapstructure:"configOne"`
ConfigTwo []string `mapstructure:"configTwo"`
}
func (r *myConfig) String() string {
var output string
if r.ConfigOne != nil {
output += fmt.Sprintf("ConfigOne: %s\n", *r.ConfigOne)
}
if r.ConfigTwo != nil {
output += fmt.Sprintf("ConfigTwo: %v\n", r.ConfigTwo)
}
return output
}
// 用户可自定义Translator,用于将myConfig解析成Options
func myTranslator(config *etcdClient.EtcdConfig) ([]kitexclient.Option, error) {
c := config.MyConfig
if c == nil {
return nil, nil
}
opts := []kitexclient.Option{}
//具体处理逻辑
_ = opts
fmt.Println("myConfigTranslator run! myConfig:" + c.String())
return opts, nil
}
func main() {
readerOptions := etcdClient.ReaderOptions{
ConfigParser: &myConfigParser{},
MyConfig: &myConfig{},
}
utils.Printpath()
reader, err := etcdClient.NewReader(readerOptions)
//reader, err := etcdClient.NewReader(etcdClient.ReaderOptions{})//使用默认值时的
if err != nil {
log.Fatal(err)
return
}
myTranslators := []etcdClient.Translator{myTranslator}
loader, err := etcdClient.NewLoader(clientServiceName, serverServiceName, reader, myTranslators...)
if err != nil {
log.Fatal(err)
return
}
err = loader.Load()
if err != nil {
log.Fatal(err)
return
}
fmt.Println("Options: ", loader.GetSuite().Options())
config, _ := reader.GetConfig()
fmt.Print("Config:", config.String())
c, err := example.NewClient("echo_server_service", kitexclient.WithSuite(loader.GetSuite()))
if err != nil {
log.Fatal(err)
}
req := examplegen.Req{
Id: 123,
}
resp, err := c.Test(context.Background(), &req)
if err != nil {
log.Fatal(err)
return
}
fmt.Println(resp)
}
```
81 changes: 81 additions & 0 deletions etcd/client/client.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
package etcdclient

import (
clientv3 "go.etcd.io/etcd/client/v3"
"text/template"
"time"
)

// Options etcd config options. All the fields have default value.
type ReaderOptions struct {
Node []string
Prefix string
PathFormat string
Timeout time.Duration
ConfigParser ConfigParser
MyConfig Config
}

func NewReader(opts ReaderOptions) (*EtcdReader, error) {
if opts.Node == nil {
opts.Node = []string{EtcdDefaultNode}
}
if opts.ConfigParser == nil {
opts.ConfigParser = &defaultParser{}
}
if opts.Prefix == "" {
opts.Prefix = EtcdDefaultConfigPrefix
}
if opts.Timeout == 0 {
opts.Timeout = EtcdDefaultTimeout
}
if opts.PathFormat == "" {
opts.PathFormat = EtcdClientDefaultPath
}
etcdClient, err := clientv3.New(clientv3.Config{
Endpoints: opts.Node,
DialTimeout: opts.Timeout,
})
if err != nil {
return nil, err
}
clientPathTemplate, err := template.New("clientName").Parse(opts.PathFormat)
if err != nil {
return nil, err
}
r := &EtcdReader{
config: &EtcdConfig{MyConfig: opts.MyConfig}, //配置文件读出结果
parser: opts.ConfigParser, //配置文件解码器
etcdClient: etcdClient,
prefix: opts.Prefix,
clientPathTemplate: clientPathTemplate,
etcdTimeout: opts.Timeout,
}

return r, nil
}

func NewLoader(clientServiceName, serverServiceName string, reader *EtcdReader, myTranslators ...Translator) (*EtcdLoader, error) {

// Register all translators
translators := []Translator{
basicInfoTranslator,
hostPortsTranslator,
destServiceTranslator,
protocolTranslator,
connectionTranslator,
}

if len(myTranslators) != 0 {
translators = append(translators, myTranslators...)
}

loader := &EtcdLoader{
translators: translators,
ClientServiceName: clientServiceName,
ServerServiceName: serverServiceName,
reader: reader,
}

return loader, nil
}
83 changes: 83 additions & 0 deletions etcd/client/decoder.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
package etcdclient

import (
"encoding/json"
"fmt"
"strings"
)

type ConfigParser interface {
Decode(data []byte, config *EtcdConfig) error
}

type defaultParser struct {
}

func (p *defaultParser) Decode(data []byte, config *EtcdConfig) error {
return json.Unmarshal(data, config)
}

type Config interface {
String() string
}

type EtcdConfig struct {
ClientBasicInfo *EndpointBasicInfo `mapstructure:"ClientBasicInfo"`
HostPorts []string `mapstructure:"HostPorts"`
DestService *string `mapstructure:"DestService"`
Protocol *string `mapstructure:"Protocol"`
Connection *Connection `mapstructure:"Connection"`
MyConfig Config `mapstructure:"MyConfig"`
}

func (c *EtcdConfig) String() string {
var builder strings.Builder

if c.ClientBasicInfo != nil {
builder.WriteString(fmt.Sprintf("ClientBasicInfo: %v\n", *c.ClientBasicInfo))
}

if c.HostPorts != nil {
builder.WriteString(fmt.Sprintf("HostPorts: %v\n", c.HostPorts))
}

if c.DestService != nil {
builder.WriteString(fmt.Sprintf("DestService: %v\n", *c.DestService))
}

if c.Protocol != nil {
builder.WriteString(fmt.Sprintf("Protocol: %v\n", *c.Protocol))
}

if c.Connection != nil {
builder.WriteString(fmt.Sprintf("Connection: %v\n", *c.Connection))
}

if c.MyConfig != nil {
builder.WriteString(c.MyConfig.String())
}

return builder.String()
}

type EndpointBasicInfo struct {
ServiceName string `mapstructure:"ServiceName"`
Method string `mapstructure:"Method"`
Tags map[string]string `mapstructure:"Tags"`
}

type IdleConfig struct {
MinIdlePerAddress int `mapstructure:"MinIdlePerAddress"`
MaxIdlePerAddress int `mapstructure:"MaxIdlePerAddress"`
MaxIdleGlobal int `mapstructure:"MaxIdleGlobal"`
MaxIdleTimeout string `mapstructure:"MaxIdleTimeout"`
}
type MuxConnection struct {
ConnNum int `mapstructure:"ConnNum"`
}

type Connection struct {
Method string `mapstructure:"Method"`
LongConnection IdleConfig `mapstructure:"LongConnection"`
MuxConnection MuxConnection `mapstructure:"MuxConnection"`
}
Loading

0 comments on commit f596224

Please sign in to comment.