Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[BUG]Wrong parsing of config, when using config.Scan #3439

Open
godcong opened this issue Oct 12, 2024 · 6 comments
Open

[BUG]Wrong parsing of config, when using config.Scan #3439

godcong opened this issue Oct 12, 2024 · 6 comments
Labels
question Further information is requested

Comments

@godcong
Copy link

godcong commented Oct 12, 2024

What happened:

The default output of toml is configured in UpperCase, which is converted to map=>json during transmission.
But proto's json supports the format of snake_case.
Eventually the json=>Config parsing fails.

flagconf, _ = filepath.Abs(flagconf)
	fmt.Println("load config at:", flagconf)

	client, err := api.NewClient(&api.Config{
		Address: "host:8500",
	})
	if err != nil {
		panic(err)
	}
	fs := file.NewSource(flagconf)
	kvs, err := fs.Load()
	if err != nil {
		panic(err)
	}

	for _, kv := range kvs {
		fmt.Println("key:", kv.Key)
		_, err := client.KV().Put(&api.KVPair{Key: "configs/" + kv.Key, Value: kv.Value}, nil)
		if err != nil {
			panic(err)
		}
	}

	//consul.WithPath(testPath)
	source, err := consul.New(client, consul.WithPath("configs/bootstrap.toml"))
	if err != nil {
		panic(err)
	}
	c := config.New(
		//config.WithSource(file.NewSource(flagconf), source),
		config.WithSource(source),
		//config.WithResolveActualTypes(true),
		config.WithDecoder(codec.SourceDecoder),
	)
	defer c.Close()
	if err := c.Load(); err != nil {
		panic(err)
	}

	var bc conf.Bootstrap
	if err := c.Scan(&bc); err != nil {
		panic(err)
	}

bootstrap.toml

ServiceName = "helloworld"
Version = "v1.0.0"
CryptoType = "argon2"
Id = ""

[Server]
[Server.Http]
Network = "0.0.0.0"
Addr = "8000"
UseTls = false
CertFile = ""
KeyFile = ""
[Server.Http.Timeout]
Seconds = 180
Nanos = 0
[Server.Http.ShutdownTimeout]
Seconds = 180
Nanos = 0
[Server.Http.ReadTimeout]
Seconds = 180
Nanos = 0
[Server.Http.WriteTimeout]
Seconds = 180
Nanos = 0
[Server.Http.IdleTimeout]
Seconds = 180
Nanos = 0
[Server.Grpc]
Network = "0.0.0.0"
Addr = "9000"
UseTls = false
CertFile = ""
KeyFile = ""
[Server.Grpc.Timeout]
Seconds = 180
Nanos = 0
[Server.Grpc.ShutdownTimeout]
Seconds = 180
Nanos = 0
[Server.Grpc.ReadTimeout]
Seconds = 180
Nanos = 0
[Server.Grpc.WriteTimeout]
Seconds = 180
Nanos = 0
[Server.Grpc.IdleTimeout]
Seconds = 180
Nanos = 0

proto

syntax = "proto3";
package kratos.api;

option go_package = "internal/mods/helloworld/conf;conf";

import "google/protobuf/duration.proto";
import "validate/validate.proto";

message Bootstrap {
  string service_name = 1 [json_name = "service_name"];
  string version = 2 [json_name = "version"];
  string crypto_type = 3 [json_name = "crypto_type"];
  Server server = 4;
  Data data = 5;
  Settings settings = 6;
  string id = 99 ;
}

What you expected to happen:

Converts profiles properly

How to reproduce it (as minimally and precisely as possible):

Anything else we need to know?:

Environment:

  • Kratos version (use kratos -v): kratos version v2.8.0
  • Go version (use go version): go version go1.23.2 windows/amd64
  • OS (e.g: cat /etc/os-release): Windows
  • Others:
@godcong godcong added the bug Something isn't working label Oct 12, 2024
@shenqidebaozi
Copy link
Member

I don't quite understand what the specific problem is

@godcong
Copy link
Author

godcong commented Oct 22, 2024

@shenqidebaozi Added an example of yml and toml at:
https://github.com/godcong/example

github.com\go-kratos\kratos\[email protected]\config\reader.go:

1729627669602
This is mainly the case when the source is specialized to target v.
这种情况主要发生在将源代码专门化为目标v 时。

This is because the intermediate values are stored in a map. Therefore, they are not subject to the tag specification.
My configuration file is in .toml format, and it converts the data to UpperCase like this.
我的配置文件是 .toml 格式,它将数据转换为 UpperCase 这样的格式。

example with value ServiceName = "helloworld"
ServiceName = "helloworld"为例子

  1. defined in the proto file:
  2. 在proto文件中定义:
  string service_name = 1 [json_name = "service_name"];
  1. generated to go will like this:
  2. 生成后的go会像这样
   ServiceName string `json:"service_name"`

If the source is in a non-json format.
Then it will be parsed according to the default parsing method for that format.
如果源是非 json 格式。
则将根据该格式的默认解析方法进行解析。

If the configuration is UpperCase in the .toml file, the fields are parsed into map["ServiceName"]"helloworld"
Eventually, it will become a json source during the pass.
如果配置的 .toml 文件中的是 UpperCase这样,字段将被解析为 map[“ServiceName”]“helloworld”
最终,它将在传递过程中变成 json 源。

but the content will be
但内容将是这样

{
    "ServiceName": "helloworld"
}

But the tag of the json is service_name.
Finally, it can't be parsed to the go file correctly.
但 json 的 tagservice_name
最后,它就不能被正确地解析到 go 文件中。

So I think it should be more than just unmarshalJSON.
It should be decoded in the format of the source file.
因此,我认为应该不仅仅是 unmarshalJSON
它应该以源文件的格式解码。

Of course, if the configuration with service_name in the file, it can be resolved normally.
But I don't have the ability to change the case.
I just saved the bootstrap configuration as a file.
当然,如果文件中的配置包含 service_name,就可以正常解析。
但我特意去改变这个。
我只是将引导配置保存为一个文件。

@czyt
Copy link
Contributor

czyt commented Oct 24, 2024

you need two step

  1. register toml codec in kratos
    simpe toml codec
import (
	"github.com/BurntSushi/toml"
	"github.com/go-kratos/kratos/v2/encoding"
)

// Name is the name registered for the xml codec.
const Name = "toml"

func init() {
	encoding.RegisterCodec(codec{})
}

// codec is a Codec implementation with xml.
type codec struct{}

func (codec) Marshal(v interface{}) ([]byte, error) {
	return toml.Marshal(v)
}

func (codec) Unmarshal(data []byte, v interface{}) error {
	return toml.Unmarshal(data, v)
}

func (codec) Name() string {
	return Name
}
  1. define your resolver see more https://go-kratos.dev/docs/component/config#6%E9%85%8D%E7%BD%AE%E5%A4%84%E7%90%86resolver
    image

@godcong
Copy link
Author

godcong commented Oct 24, 2024

@czyt 意思是,我实际需要一个自定义的resolver将输入的配置转换成对的map格式对吧?
means, I actually need a custom resolver to convert the input configuration into a map format, right?

@kratos-ci-bot
Copy link
Collaborator

Bot detected the issue body's language is not English, translate it automatically. 👯👭🏻🧑‍🤝‍🧑👫🧑🏿‍🤝‍🧑🏻👩🏾‍🤝‍👨🏿👬🏿


@czyt means, I actually need a custom resolver to convert the input configuration into a map format, right?

@czyt
Copy link
Contributor

czyt commented Oct 24, 2024

@czyt 意思是,我实际需要一个自定义的resolver将输入的配置转换成对的map格式对吧? means, I actually need a custom resolver to convert the input configuration into a map format, right?

yes,you can try

@shenqidebaozi shenqidebaozi added question Further information is requested and removed bug Something isn't working labels Oct 24, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
question Further information is requested
Projects
None yet
Development

No branches or pull requests

4 participants