summaryrefslogtreecommitdiff
path: root/lookupPB.go
blob: 9fb73a2e55b24a74515c76a165a06aa90ffcdd0a (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
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
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
}

// don't do this. use prototext.Format(pb)
// duh. I'm dumb. I literally wasted my time + was being lazy so I
// just asked asking Gemini AI to make some function for this
// when, for years, I use prototext.Format() all over the place
func printStrings(pb proto.Message) {
	// 1. Get the protoreflect.Message interface.
	msg := pb.ProtoReflect()

	// It's good practice to check if the message is valid.
	if !msg.IsValid() {
		fmt.Printf("Error: Provided protobuf message is not valid.")
		return
	}

	// 2. Get the message's descriptor.
	descriptor := msg.Descriptor()
	fmt.Printf("--- Listing String Fields in [%s] ---\n", descriptor.FullName())

	// 3. Get the collection of all field descriptors for this message.
	fields := descriptor.Fields()

	// 4. Iterate over all the fields.
	for i := 0; i < fields.Len(); i++ {
		// Get the descriptor for the field at the current index.
		fieldDescriptor := fields.Get(i)

		// 5. Check if the field's kind is a string.
		if fieldDescriptor.Kind() == protoreflect.StringKind {
			// 6. If it is a string, get its name and value.
			fieldName := fieldDescriptor.Name()
			value := msg.Get(fieldDescriptor).String()

			// 7. Print the formatted result.
			// We add a check to see if the field is populated. An empty string
			// is a valid value, but you might only want to see set fields.
			if msg.Has(fieldDescriptor) {
				fmt.Printf("  %s: \"%s\"\n", fieldName, value)
			}
		}
	}
}