Я пытаюсь демаршалировать конфигурацию посланника из JSON в структуру прототипа Go. В JSON есть поле Any с информацией о типе. Я знаю, что protojson каким-то волшебным образом определяет определения прото в двоичном формате. В приведенном ниже случае я получаю сообщение об ошибке.
Error: Expected nil, but got: &errors.prefixError{s:"(line 23:46): unable to resolve \"type.googleapis.com/envoy.extensions.access_loggers.file.v3.FileAccessLog\": \"not found\""}
package play
import (
"testing"
"github.com/stretchr/testify/require"
"google.golang.org/protobuf/encoding/protojson"
listener "github.com/envoyproxy/go-control-plane/envoy/config/listener/v3"
// _ "github.com/envoyproxy/go-control-plane/envoy/extensions/access_loggers/file/v3"
)
var listnerJSONWithAccessLog = `
{
"name": "lis1",
"address": {
"socket_address": {
"address": "127.0.0.1",
"port_value": 9999
}
},
"filter_chains": [
{
"filters": [
{
"name": "envoy.filters.network.http_connection_manager",
"typed_config": {
"@type": "type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager",
"codec_type": "AUTO",
"stat_prefix": "hcm_prefix",
"access_log": [
{
"name": "envoy.access_loggers.file",
"typed_config": {
"@type": "type.googleapis.com/envoy.extensions.access_loggers.file.v3.FileAccessLog",
"path": "/dev/stdout"
}
}
],
"http_filters": [
{
"name": "envoy.filters.http.router",
"typed_config": {
"@type": "type.googleapis.com/envoy.extensions.filters.http.router.v3.Router"
}
}
],
"route_config": {
"name": "lis1_route_config",
"virtual_hosts": [
{
"name": "lis1_virtual_host",
"domains": [
"*"
],
"routes": [
{
"match": {
"prefix": "/direct"
},
"direct_response": {
"status": 200,
"body": {
"inline_string": "hello"
}
}
}
]
}
]
}
}
}
]
}
]
}
`
func TestJSONToPB(t *testing.T) {
t.Run("json to pb", func(t *testing.T) {
var lis listener.Listener
err := protojson.Unmarshal([]byte(listnerJSONWithAccessLog), &lis)
require.Nil(t, err)
})
}
Раскомментирование строки с //_ github... решает проблему. Как правильно это сделать? Нужно ли мне добавлять такой пустой импорт для каждой возможной структуры, которую я пытаюсь демаршалировать?

Вам нужен protoreflect.MessageDescriptor для именованного сообщения, envoy.extensions.access_loggers.file.v3.FileAccessLog в вашем случае.
Видите ли, вы можете получить это из FileAccessLog.ProtoReflect (или напрямую из устаревшего FileAccessLog.Descriptor ), но для этого вам понадобится FileAccessLog . И это вы можете получить посредством отражения, что, конечно, терпит неудачу, когда структура не существует в двоичном виде.
Значит, вам нужно откуда-то получить информацию. Рефлексия обычно является хорошим и удобным способом сделать это. Вы можете просто импортировать пакет как _, потому что вы не будете использовать его напрямую, но все равно зависите от него.
@rett Обычно вы включаете известных. Протокол Buffers совместим как вперед, так и назад, поэтому вы можете даже читать сообщения, созданные по новой схеме (хотя и с неизвестными полями). Кроме того, вы не можете работать с полями, которые вам неизвестны во время компиляции. Пользовательский преобразователь внесет особую зависимость во всю вашу систему, чего я бы, вероятно, избегал. При необходимости вы можете автоматически обновить все зависимости протоколов в клиентах. Кроме того, если это отвечает на ваш вопрос, вы можете пометить его как принятый ответ;)
Спасибо @eik! Какова наилучшая практика включения этих файлов? Могу включить все известные. Это лучший способ? Или мне следует использовать собственный преобразователь, чтобы добавить его без перекомпиляции двоичного файла. Использование собственного преобразователя переопределяет преобразователь Globaltypes, поэтому я не решаюсь это делать. Я поиграюсь с этим.