summaryrefslogtreecommitdiff
path: root/findFilename.go
blob: 5e81974f8ca9ebc14b17f86f8c7bdf3a99c1e6ca (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
package config

import (
	"errors"
	"fmt"

	"google.golang.org/protobuf/proto"
	"google.golang.org/protobuf/reflect/protoreflect"
)

var ErrProtoNoVarName error = errors.New("name not in .proto")
var ErrProtoVarNotString error = errors.New("name exists but is not a string")

// Gemini AI can help author some pretty good protobuf code.
// I never remember the syntax for 'reflect' on these things.

// sets "Filename" if it exists in the protobuf
func SetFilename(pb proto.Message, filename string) (bool, error) {
	msg := pb.ProtoReflect() // This is the entry point to the reflection API.

	descriptor := msg.Descriptor() // Get the message's descriptor, which contains metadata about its fields.

	fieldName := protoreflect.Name("Filename")
	fieldDescriptor := descriptor.Fields().ByName(fieldName)

	if fieldDescriptor == nil {
		fieldName = protoreflect.Name("filename")
		fieldDescriptor = descriptor.Fields().ByName(fieldName)
	}

	if fieldDescriptor == nil {
		return false, fmt.Errorf("fieldDescriptor == nil")
	}

	if fieldDescriptor.Kind() != protoreflect.StringKind {
		// The field exists but is not a string, so we can't return it as one.
		return false, fmt.Errorf("The field exists but is not a string")
	}

	valueToSet := protoreflect.ValueOfString(filename)

	// 6. If the field exists and is a string, get its value.
	// The value is returned as a protoreflect.Value.
	msg.Set(fieldDescriptor, valueToSet)

	// 7. Convert the protoreflect.Value to a native Go string.
	return true, nil
}

// this will try both "filename" and "Filename"
func GetFilename(pb proto.Message) (string, error) {
	// 1. Get the protoreflect.Message interface from the message.
	// This is the entry point to the reflection API.
	msg := pb.ProtoReflect()

	// 2. Get the message's descriptor, which contains metadata about its fields.
	descriptor := msg.Descriptor()

	// 3. Find the specific field descriptor by its protobuf name ("Filename").
	// Note: The field name must match the name in the .proto file.
	fieldName := protoreflect.Name("Filename")
	fieldDescriptor := descriptor.Fields().ByName(fieldName)

	// try upper case
	if fieldDescriptor == nil {
		fieldName = protoreflect.Name("filename")
		fieldDescriptor = descriptor.Fields().ByName(fieldName)
		// if fieldDescriptor == nil {
		// panic(".proto file: try 'Filename', not 'filename'? or maybe nomutex if pb.Marshal() fails")
		// }
	}

	// 4. Check if the field was found. If not, return false.
	if fieldDescriptor == nil {
		return "", ErrProtoNoVarName
	}

	// 5. (Optional but recommended) Verify the field is a string type.
	if fieldDescriptor.Kind() != protoreflect.StringKind {
		// The field exists but is not a string, so we can't return it as one.
		return "", ErrProtoVarNotString
	}

	// 6. If the field exists and is a string, get its value.
	// The value is returned as a protoreflect.Value.
	value := msg.Get(fieldDescriptor)

	// 7. Convert the protoreflect.Value to a native Go string.
	return value.String(), nil
}

// this will try both "filename" and "Filename"
func GetString(pb proto.Message, varname string) (string, error) {
	// 1. Get the protoreflect.Message interface from the message.
	// This is the entry point to the reflection API.
	msg := pb.ProtoReflect()

	// 2. Get the message's descriptor, which contains metadata about its fields.
	descriptor := msg.Descriptor()

	// 3. Find the specific field descriptor by its protobuf name ("Filename").
	// Note: The field name must match the name in the .proto file.
	fieldName := protoreflect.Name(varname)
	fieldDescriptor := descriptor.Fields().ByName(fieldName)

	// 4. Check if the field was found. If not, return false.
	if fieldDescriptor == nil {
		return "", ErrProtoNoVarName
	}

	// 5. (Optional but recommended) Verify the field is a string type.
	if fieldDescriptor.Kind() != protoreflect.StringKind {
		// The field exists but is not a string, so we can't return it as one.
		return "", ErrProtoVarNotString
	}

	// 6. If the field exists and is a string, get its value.
	// The value is returned as a protoreflect.Value.
	value := msg.Get(fieldDescriptor)

	// 7. Convert the protoreflect.Value to a native Go string.
	return value.String(), nil
}