diff --git a/common/serial/typed_message.go b/common/serial/typed_message.go index 5e7405532..b861c18e1 100644 --- a/common/serial/typed_message.go +++ b/common/serial/typed_message.go @@ -47,5 +47,15 @@ func GetInstanceOf(v *anypb.Any) (proto.Message, error) { } func V2Type(v *anypb.Any) string { + return V2TypeFromURL(v.TypeUrl) +} +func V2TypeFromURL(string2 string) string { + return string2 +} +func V2TypeHumanReadable(v *anypb.Any) string { return v.TypeUrl } + +func V2URLFromV2Type(readableType string) string { + return readableType +} diff --git a/infra/conf/v2jsonpb/any.go b/infra/conf/v2jsonpb/any.go new file mode 100644 index 000000000..bef561a59 --- /dev/null +++ b/infra/conf/v2jsonpb/any.go @@ -0,0 +1,28 @@ +package v2jsonpb + +import ( + "github.com/golang/protobuf/jsonpb" + "github.com/golang/protobuf/proto" + "github.com/v2fly/v2ray-core/v4/common/serial" +) + +type AnyHolder struct { + proto.Message +} + +type resolver struct { + backgroundResolver jsonpb.AnyResolver +} + +func (r resolver) Resolve(typeURL string) (proto.Message, error) { + obj, err := r.backgroundResolver.Resolve(typeURL) + if err != nil { + return nil, err + } + return AnyHolder{obj}, nil + +} + +func NewV2JsonPBResolver() jsonpb.AnyResolver { + return &resolver{backgroundResolver: serial.GetResolver()} +} diff --git a/infra/conf/v2jsonpb/any2.go b/infra/conf/v2jsonpb/any2.go new file mode 100644 index 000000000..a2a6d915b --- /dev/null +++ b/infra/conf/v2jsonpb/any2.go @@ -0,0 +1,290 @@ +package v2jsonpb + +import ( + "github.com/golang/protobuf/jsonpb" + "google.golang.org/protobuf/proto" + "google.golang.org/protobuf/reflect/protoreflect" + "google.golang.org/protobuf/types/dynamicpb" + "google.golang.org/protobuf/types/known/anypb" +) + +type resolver2 struct { + backgroundResolver jsonpb.AnyResolver +} + +func (r resolver2) FindMessageByName(message protoreflect.FullName) (protoreflect.MessageType, error) { + panic("implement me") +} + +func (r resolver2) FindMessageByURL(url string) (protoreflect.MessageType, error) { + msg, err := r.backgroundResolver.Resolve(url) + if err != nil { + return nil, err + } + return msg.(proto.Message).ProtoReflect().Type(), nil +} + +func (r resolver2) FindExtensionByName(field protoreflect.FullName) (protoreflect.ExtensionType, error) { + panic("implement me") +} + +func (r resolver2) FindExtensionByNumber(message protoreflect.FullName, field protoreflect.FieldNumber) (protoreflect.ExtensionType, error) { + panic("implement me") +} + +type V2JsonProtobufAnyTypeDescriptor struct { + protoreflect.MessageDescriptor +} + +func (v V2JsonProtobufAnyTypeDescriptor) FullName() protoreflect.FullName { + return "org.v2fly.SynAny" +} + +func (v V2JsonProtobufAnyTypeDescriptor) Fields() protoreflect.FieldDescriptors { + panic("implement me") +} + +type V2JsonProtobufAnyType struct { + originalType protoreflect.MessageType + syntheticDescriptor V2JsonProtobufAnyTypeDescriptor +} + +func (v V2JsonProtobufAnyType) New() protoreflect.Message { + return dynamicpb.NewMessage(v.syntheticDescriptor) +} + +func (v V2JsonProtobufAnyType) Zero() protoreflect.Message { + return dynamicpb.NewMessage(v.syntheticDescriptor) +} + +func (v V2JsonProtobufAnyType) Descriptor() protoreflect.MessageDescriptor { + return v.syntheticDescriptor +} + +type V2JsonProtobufFollowerFieldDescriptor struct { + protoreflect.FieldDescriptor +} + +type V2JsonProtobufAnyTypeFieldDescriptor struct { + protoreflect.FieldDescriptor +} + +func (v V2JsonProtobufAnyTypeFieldDescriptor) JSONName() string { + return "type" +} +func (v V2JsonProtobufAnyTypeFieldDescriptor) TextName() string { + return "type" +} + +type V2JsonProtobufAnyValueField struct { + protoreflect.FieldDescriptor + name string +} + +func (v *V2JsonProtobufAnyValueField) Kind() protoreflect.Kind { + return protoreflect.MessageKind +} + +func (v *V2JsonProtobufAnyValueField) JSONName() string { + return v.name +} +func (v *V2JsonProtobufAnyValueField) TextName() string { + return v.name +} + +type V2JsonProtobufAnyFollower struct { + protoreflect.Message +} + +func (v *V2JsonProtobufAnyFollower) Range(f func(protoreflect.FieldDescriptor, protoreflect.Value) bool) { + v.Message.Range(func(descriptor protoreflect.FieldDescriptor, value protoreflect.Value) bool { + return followValue(descriptor, value, f) + }) +} + +type V2JsonProtobufFollower struct { + protoreflect.Message +} +type V2JsonProtobufListFollower struct { + protoreflect.List +} + +func (v V2JsonProtobufListFollower) Len() int { + return v.List.Len() +} + +func (v V2JsonProtobufListFollower) Get(i int) protoreflect.Value { + return protoreflect.ValueOfMessage(&V2JsonProtobufFollower{v.List.Get(i).Message()}) +} + +func (v V2JsonProtobufListFollower) Set(i int, value protoreflect.Value) { + panic("implement me") +} + +func (v V2JsonProtobufListFollower) Append(value protoreflect.Value) { + panic("implement me") +} + +func (v V2JsonProtobufListFollower) AppendMutable() protoreflect.Value { + panic("implement me") +} + +func (v V2JsonProtobufListFollower) Truncate(i int) { + panic("implement me") +} + +func (v V2JsonProtobufListFollower) NewElement() protoreflect.Value { + panic("implement me") +} + +func (v V2JsonProtobufListFollower) IsValid() bool { + panic("implement me") +} + +type V2JsonProtobufMapFollower struct { + protoreflect.Map +} + +func (v V2JsonProtobufMapFollower) Len() int { + panic("implement me") +} + +func (v V2JsonProtobufMapFollower) Range(f func(protoreflect.MapKey, protoreflect.Value) bool) { + panic("implement me") +} + +func (v V2JsonProtobufMapFollower) Has(key protoreflect.MapKey) bool { + panic("implement me") +} + +func (v V2JsonProtobufMapFollower) Clear(key protoreflect.MapKey) { + panic("implement me") +} + +func (v V2JsonProtobufMapFollower) Get(key protoreflect.MapKey) protoreflect.Value { + panic("implement me") +} + +func (v V2JsonProtobufMapFollower) Set(key protoreflect.MapKey, value protoreflect.Value) { + panic("implement me") +} + +func (v V2JsonProtobufMapFollower) Mutable(key protoreflect.MapKey) protoreflect.Value { + panic("implement me") +} + +func (v V2JsonProtobufMapFollower) NewValue() protoreflect.Value { + panic("implement me") +} + +func (v V2JsonProtobufMapFollower) IsValid() bool { + panic("implement me") +} + +func (v *V2JsonProtobufFollower) Type() protoreflect.MessageType { + panic("implement me") +} + +func (v *V2JsonProtobufFollower) New() protoreflect.Message { + panic("implement me") +} + +func (v *V2JsonProtobufFollower) Interface() protoreflect.ProtoMessage { + panic("implement me") +} + +func (v *V2JsonProtobufFollower) Range(f func(protoreflect.FieldDescriptor, protoreflect.Value) bool) { + v.Message.Range(func(descriptor protoreflect.FieldDescriptor, value protoreflect.Value) bool { + name := descriptor.FullName() + fullname := v.Message.Descriptor().FullName() + if fullname == "google.protobuf.Any" { + + switch name { + case "google.protobuf.Any.type_url": + fd := V2JsonProtobufAnyTypeFieldDescriptor{descriptor} + return f(fd, value) + case "google.protobuf.Any.value": + url := v.Message.Get(v.Message.Descriptor().Fields().ByName("type_url")).String() + fd := &V2JsonProtobufAnyValueField{descriptor, url} + follow := &V2JsonProtobufAnyFollower{v.Message} + return f(fd, protoreflect.ValueOfMessage(follow)) + default: + panic("unexpected any value") + } + + } + return followValue(descriptor, value, f) + }) +} + +func followValue(descriptor protoreflect.FieldDescriptor, value protoreflect.Value, f func(protoreflect.FieldDescriptor, protoreflect.Value) bool) bool { + fd := V2JsonProtobufFollowerFieldDescriptor{descriptor} + if descriptor.Kind() == protoreflect.MessageKind { + if descriptor.IsList() { + value2 := protoreflect.ValueOfList(V2JsonProtobufListFollower{value.List()}) + return f(fd, value2) + } + if descriptor.IsMap() { + value2 := protoreflect.ValueOfMap(V2JsonProtobufMapFollower{value.Map()}) + return f(fd, value2) + } + value2 := protoreflect.ValueOfMessage(&V2JsonProtobufFollower{value.Message()}) + return f(fd, value2) + } + + return f(fd, value) +} + +func (v *V2JsonProtobufFollower) Has(descriptor protoreflect.FieldDescriptor) bool { + panic("implement me") +} + +func (v *V2JsonProtobufFollower) Clear(descriptor protoreflect.FieldDescriptor) { + panic("implement me") +} + +func (v *V2JsonProtobufFollower) Set(descriptor protoreflect.FieldDescriptor, value protoreflect.Value) { + panic("implement me") +} + +func (v *V2JsonProtobufFollower) Mutable(descriptor protoreflect.FieldDescriptor) protoreflect.Value { + panic("implement me") +} + +func (v *V2JsonProtobufFollower) NewField(descriptor protoreflect.FieldDescriptor) protoreflect.Value { + panic("implement me") +} + +func (v *V2JsonProtobufFollower) WhichOneof(descriptor protoreflect.OneofDescriptor) protoreflect.FieldDescriptor { + panic("implement me") +} + +func (v *V2JsonProtobufFollower) GetUnknown() protoreflect.RawFields { + panic("implement me") +} + +func (v *V2JsonProtobufFollower) SetUnknown(fields protoreflect.RawFields) { + panic("implement me") +} + +func (v *V2JsonProtobufFollower) IsValid() bool { + panic("implement me") +} + +func (v *V2JsonProtobufFollower) ProtoReflect() protoreflect.Message { + return v +} + +func (v *V2JsonProtobufFollower) Descriptor() protoreflect.MessageDescriptor { + fullname := v.Message.Descriptor().FullName() + if fullname == "google.protobuf.Any" { + //desc := &V2JsonProtobufAnyType{v.Message.Type(), V2JsonProtobufAnyTypeDescriptor{(&anypb.Any{}).ProtoReflect().Descriptor()}} + desc := &V2JsonProtobufAnyTypeDescriptor{(&anypb.Any{}).ProtoReflect().Descriptor()} + return desc + } + return v.Message.Descriptor() +} + +func (v *V2JsonProtobufFollower) Get(fd protoreflect.FieldDescriptor) protoreflect.Value { + panic("implement me") +} diff --git a/infra/conf/v2jsonpb/v2jsonpb.go b/infra/conf/v2jsonpb/v2jsonpb.go new file mode 100644 index 000000000..ec81f6834 --- /dev/null +++ b/infra/conf/v2jsonpb/v2jsonpb.go @@ -0,0 +1,69 @@ +package v2jsonpb + +import ( + "github.com/v2fly/v2ray-core/v4/common/serial" + "google.golang.org/protobuf/encoding/protojson" + "google.golang.org/protobuf/proto" + + core "github.com/v2fly/v2ray-core/v4" + "github.com/v2fly/v2ray-core/v4/common" + "github.com/v2fly/v2ray-core/v4/common/buf" + "github.com/v2fly/v2ray-core/v4/common/cmdarg" + "io" +) + +//go:generate go run github.com/v2fly/v2ray-core/v4/common/errors/errorgen + +func loadV2JsonPb(data []byte) (*core.Config, error) { + coreconf := &core.Config{} + jsonpbloader := &protojson.UnmarshalOptions{} + err := jsonpbloader.Unmarshal(data, coreconf) + if err != nil { + return nil, err + } + return coreconf, nil +} + +func dumpV2JsonPb(config proto.Message) ([]byte, error) { + jsonpbdumper := &protojson.MarshalOptions{Resolver: resolver2{serial.GetResolver()}, AllowPartial: true} + bytew, err := jsonpbdumper.Marshal(&V2JsonProtobufFollower{config.ProtoReflect()}) + if err != nil { + return nil, err + } + return bytew, nil +} + +func DumpV2JsonPb(config proto.Message) ([]byte, error) { + return dumpV2JsonPb(config) +} + +const FormatProtobufV2JSONPB = "v2jsonpb" + +func init() { + common.Must(core.RegisterConfigLoader(&core.ConfigFormat{ + Name: []string{FormatProtobufV2JSONPB}, + Extension: []string{".v2pb.json", ".v2pbjson"}, + Loader: func(input interface{}) (*core.Config, error) { + switch v := input.(type) { + case string: + r, err := cmdarg.LoadArg(v) + if err != nil { + return nil, err + } + data, err := buf.ReadAllToBytes(r) + if err != nil { + return nil, err + } + return loadV2JsonPb(data) + case io.Reader: + data, err := buf.ReadAllToBytes(v) + if err != nil { + return nil, err + } + return loadV2JsonPb(data) + default: + return nil, newError("unknow type") + } + }, + })) +} diff --git a/main/commands/all/jsonv4/convert.go b/main/commands/all/jsonv4/convert.go index 39da7704c..0008f7f92 100644 --- a/main/commands/all/jsonv4/convert.go +++ b/main/commands/all/jsonv4/convert.go @@ -4,6 +4,7 @@ import ( "bytes" "encoding/json" "github.com/v2fly/v2ray-core/v4/infra/conf/jsonpb" + "github.com/v2fly/v2ray-core/v4/infra/conf/v2jsonpb" "os" "strings" @@ -144,6 +145,24 @@ func executeConvert(cmd *base.Command, args []string) { base.Fatalf(err.Error()) } out = w.Bytes() + case v2jsonpb.FormatProtobufV2JSONPB: + data, err := json.Marshal(m) + if err != nil { + base.Fatalf("failed to marshal json: %s", err) + } + r := bytes.NewReader(data) + cf, err := serial.DecodeJSONConfig(r) + if err != nil { + base.Fatalf("failed to decode json: %s", err) + } + pbConfig, err := cf.Build() + if err != nil { + base.Fatalf(err.Error()) + } + out, err = v2jsonpb.DumpV2JsonPb(pbConfig) + if err != nil { + base.Fatalf(err.Error()) + } default: base.Errorf("invalid output format: %s", outputFormat) base.Errorf("Run '%s help %s' for details.", base.CommandEnv.Exec, cmd.LongName())