//go:generate go run generate_handlers.go package main import ( "fmt" "io/ioutil" "os" "regexp" "strings" "text/template" ) // EnumType defines the type of the protobuf enum type EnumType struct { Name string Values []string } // MethodInfo holds information about a method type MethodInfo struct { ProtobufName string MethodName string EnumValue string ProcessRaw bool SyncMessage bool FromArchiveArg bool } func main() { inputFile := "../../protocol/protobuf/application_metadata_message.proto" outputFile := "../../protocol/messenger_handlers.go" templateFile := "./generate_handlers_template.txt" enumName := "Type" // Load the protobuf file content, err := ioutil.ReadFile(inputFile) if err != nil { fmt.Println("Error:", err) os.Exit(1) } templateFileContent, err := os.ReadFile(templateFile) if err != nil { fmt.Println("Failed to read template:", err) os.Exit(1) } // Extract enum values enum := extractEnum(content, enumName) // Prepare method information var methodInfos []MethodInfo for _, value := range enum.Values { protobufName := toCamelCase(value) if protobufName == "Unknown" || strings.HasPrefix(value, "DEPRECATED") { continue } methodName := "handle" + protobufName + "Protobuf" info := MethodInfo{MethodName: methodName, ProtobufName: protobufName, EnumValue: value} if strings.HasPrefix(value, "SYNC_") { info.SyncMessage = true } if protobufName == "PushNotificationRegistration" { info.ProcessRaw = true } info.FromArchiveArg = protobufName == "ChatMessage" || protobufName == "PinMessage" methodInfos = append(methodInfos, info) } // Generate code templateCode := string(templateFileContent) tmpl, err := template.New("handlers").Parse(templateCode) if err != nil { fmt.Println("Error:", err) os.Exit(1) } output, err := os.Create(outputFile) if err != nil { fmt.Println("Error:", err) os.Exit(1) } defer output.Close() err = tmpl.Execute(output, methodInfos) if err != nil { fmt.Println("Error:", err) os.Exit(1) } fmt.Printf("Generated handlers in %s for %s enum.\n", outputFile, enumName) } func extractEnum(content []byte, enumName string) EnumType { enumPattern := fmt.Sprintf(`enum\s+%s\s*{([^}]+)}`, enumName) re := regexp.MustCompile(enumPattern) match := re.FindStringSubmatch(string(content)) if len(match) != 2 { fmt.Println("Enum not found") os.Exit(1) } valuesPattern := `(?m)^\s*([A-Z_0-9]+)\s*=\s*\d+;` re = regexp.MustCompile(valuesPattern) valueMatches := re.FindAllStringSubmatch(match[1], -1) values := make([]string, len(valueMatches)) for i, match := range valueMatches { values[i] = strings.TrimSpace(match[1]) } return EnumType{Name: enumName, Values: values} } func toCamelCase(s string) string { words := strings.Split(strings.ToLower(s), "_") for i, word := range words { words[i] = strings.Title(word) } return strings.Join(words, "") }