Skip to content

go-leo/config

Repository files navigation

配置

一个应用程序可能从多个资源源获取配置。例如,应用程序可能从环境变量获取配置,从文件获取配置,从配置服务(例如: consul、nacos等)获取配置等。

Leo的config包就是帮助开发者,从多中资源中加载配置和监听配置。

配置源

Leo当前内置了四种源开箱即用:

  1. 环境变量
  2. 文件
  3. Consul
  4. Nacos

配置的格式

Leo当前支持了四种常用的配置格式:

  1. Env
  2. Json
  3. Toml
  4. Yaml

用法

创建一个proto配置文件:

syntax = "proto3";
package leo.config.example;
option go_package = "github.com/go-leo/config/example/configs;configs";

import "leo/config/annotations.proto";

message Application {
  option (leo.config.enable) = true;
  string LEO_RUN_ENV = 1;
  GRPC grpc = 2;
  Redis redis = 4;
}

message GRPC {
  string addr = 1;
  int32 port = 2;
}

message Redis {
  string network = 1;
  string addr = 2;
  string password = 3;
  int32 db = 4;
}

message上添加option (leo.config.enable) = true;注解,表明该message是配置结构,没有该注解,则不会被解析为配置结构。

代码生成命令:

protoc \
--proto_path=. \
--proto_path=../proto \
--go_out=. \
--go_opt=paths=source_relative \
--config_out=. \
--config_opt=paths=source_relative \
*/*.proto
// Code generated by protoc-gen-config. DO NOT EDIT.

package configs

import (
	context "context"
	config "github.com/go-leo/config"
	resource "github.com/go-leo/config/resource"
	proto "google.golang.org/protobuf/proto"
	sync "sync"
)

var (
	_ApplicationConfig      = &Application{}
	_ApplicationConfigMutex sync.RWMutex
)

func GetApplicationConfig() *Application {
	_ApplicationConfigMutex.RLock()
	cloned := proto.Clone(_ApplicationConfig)
	_ApplicationConfigMutex.RUnlock()
	return cloned.(*Application)
}

func SetApplicationConfig(conf *Application) {
	cloned := proto.Clone(conf).(*Application)
	_ApplicationConfigMutex.Lock()
	_ApplicationConfig = cloned
	_ApplicationConfigMutex.Unlock()
}

func LoadApplicationConfig(ctx context.Context, resources ...resource.Resource) error {
	conf, err := config.Load[*Application](ctx, resources...)
	if err != nil {
		return err
	}
	SetApplicationConfig(conf)
	return nil
}

func WatchApplicationConfig(ctx context.Context, resources ...resource.Resource) (<-chan struct{}, func(context.Context) error, error) {
	notifyC := make(chan *Application)
	errC := make(chan error)
	stop, err := config.Watch(ctx, notifyC, errC, resources...)
	if err != nil {
		return nil, nil, err
	}
	changedC := make(chan struct{}, 1)
	go func() {
		for {
			select {
			case <-ctx.Done():
				return
			case conf := <-notifyC:
				SetApplicationConfig(conf)
				select {
				case <-ctx.Done():
					return
				case changedC <- struct{}{}:
				default:
				}
			}
		}
	}()
	return changedC, stop, nil
}

使用:

package main

import (
	"context"
	"fmt"
	"os"
	"time"

	"github.com/go-leo/config/example/configs"
	"github.com/go-leo/config/resource/env"
	"github.com/go-leo/config/resource/file"
)

func main() {
	// prepare config

	// 模拟环境变量
	os.Setenv("LEO_RUN_ENV", "dev")
	defer os.Unsetenv("LEO_RUN_ENV")

	tmpDir := os.TempDir()

	// 模拟json文件
	jsonFilename := tmpDir + "/config.json"
	if err := os.WriteFile(jsonFilename, genConfigJSON(), 0o644); err != nil {
		panic(err)
	}
	defer os.Remove(jsonFilename)

	// 模拟yaml文件
	yamlFilename := tmpDir + "/config.yaml"
	if err := os.WriteFile(yamlFilename, genConfigYaml(), 0o644); err != nil {
		panic(err)
	}
	defer os.Remove(yamlFilename)

	// 创建环境变量资源
	envRsc, err := env.New("LEO_")
	if err != nil {
		panic(err)
	}
	// 创建json文件资源
	jsonRsc, err := file.New(jsonFilename)
	if err != nil {
		panic(err)
	}
	// 创建yaml文件资源
	yamlRsc, err := file.New(yamlFilename)
	if err != nil {
		panic(err)
	}
	// 加载配置
	if err := configs.LoadApplicationConfig(context.TODO(), envRsc, jsonRsc, yamlRsc); err != nil {
		panic(err)
	}
	// 获取配置
	fmt.Println(configs.GetApplicationConfig())
	// 监听配置
	// sigC 当有配置更新时,会发送通知。
	// stop 用于停止监听。
	sigC, stop, err := configs.WatchApplicationConfig(context.TODO(), envRsc, jsonRsc, yamlRsc)
	if err != nil {
		panic(err)
	}
	go func() {
		time.Sleep(10 * time.Second)
		stop(context.TODO())
	}()

	go func() {
		for range sigC {
			fmt.Println(configs.GetApplicationConfig())
		}
	}()

	go func() {
		for {
			time.Sleep(time.Second)
			if err := os.WriteFile(jsonFilename, genConfigJSON(), 0o644); err != nil {
				panic(err)
			}
			if err := os.WriteFile(yamlFilename, genConfigYaml(), 0o644); err != nil {
				panic(err)
			}
		}
	}()

	time.Sleep(11*time.Second)
}

func genConfigJSON() []byte {
	return []byte(fmt.Sprintf(`{"grpc":{"addr":"127.0.0.1","port":%d}}`, time.Now().Unix()))
}

func genConfigYaml() []byte {
	return []byte(fmt.Sprintf(`
redis:
  addr: 127.0.0.1:6379
  network: tcp
  password: oqnevaqm
  db: %d`, time.Now().Unix()))
}

详细代码见config

About

go config load and watch tool

Topics

Resources

Stars

Watchers

Forks

Packages

No packages published

Languages