github.com/status-im/status-go@v1.1.0/_assets/generate_handlers/generate_handlers.go (about) 1 //go:generate go run generate_handlers.go 2 3 package main 4 5 import ( 6 "fmt" 7 "io/ioutil" 8 "os" 9 "regexp" 10 "strings" 11 "text/template" 12 ) 13 14 // EnumType defines the type of the protobuf enum 15 type EnumType struct { 16 Name string 17 Values []string 18 } 19 20 // MethodInfo holds information about a method 21 type MethodInfo struct { 22 ProtobufName string 23 MethodName string 24 EnumValue string 25 ProcessRaw bool 26 SyncMessage bool 27 FromArchiveArg bool 28 } 29 30 func main() { 31 inputFile := "../../protocol/protobuf/application_metadata_message.proto" 32 outputFile := "../../protocol/messenger_handlers.go" 33 templateFile := "./generate_handlers_template.txt" 34 enumName := "Type" 35 36 // Load the protobuf file 37 content, err := ioutil.ReadFile(inputFile) 38 if err != nil { 39 fmt.Println("Error:", err) 40 os.Exit(1) 41 } 42 43 templateFileContent, err := os.ReadFile(templateFile) 44 if err != nil { 45 fmt.Println("Failed to read template:", err) 46 os.Exit(1) 47 } 48 49 // Extract enum values 50 enum := extractEnum(content, enumName) 51 52 // Prepare method information 53 var methodInfos []MethodInfo 54 for _, value := range enum.Values { 55 protobufName := toCamelCase(value) 56 if protobufName == "Unknown" || strings.HasPrefix(value, "DEPRECATED") { 57 continue 58 } 59 methodName := "handle" + protobufName + "Protobuf" 60 61 info := MethodInfo{MethodName: methodName, ProtobufName: protobufName, EnumValue: value} 62 63 if strings.HasPrefix(value, "SYNC_") { 64 info.SyncMessage = true 65 } 66 67 if protobufName == "PushNotificationRegistration" { 68 info.ProcessRaw = true 69 } 70 71 info.FromArchiveArg = protobufName == "ChatMessage" || protobufName == "PinMessage" 72 73 methodInfos = append(methodInfos, info) 74 } 75 76 // Generate code 77 templateCode := string(templateFileContent) 78 79 tmpl, err := template.New("handlers").Parse(templateCode) 80 if err != nil { 81 fmt.Println("Error:", err) 82 os.Exit(1) 83 } 84 85 output, err := os.Create(outputFile) 86 if err != nil { 87 fmt.Println("Error:", err) 88 os.Exit(1) 89 } 90 defer output.Close() 91 92 err = tmpl.Execute(output, methodInfos) 93 if err != nil { 94 fmt.Println("Error:", err) 95 os.Exit(1) 96 } 97 98 fmt.Printf("Generated handlers in %s for %s enum.\n", outputFile, enumName) 99 } 100 101 func extractEnum(content []byte, enumName string) EnumType { 102 enumPattern := fmt.Sprintf(`enum\s+%s\s*{([^}]+)}`, enumName) 103 re := regexp.MustCompile(enumPattern) 104 match := re.FindStringSubmatch(string(content)) 105 106 if len(match) != 2 { 107 fmt.Println("Enum not found") 108 os.Exit(1) 109 } 110 111 valuesPattern := `(?m)^\s*([A-Z_0-9]+)\s*=\s*\d+;` 112 re = regexp.MustCompile(valuesPattern) 113 valueMatches := re.FindAllStringSubmatch(match[1], -1) 114 115 values := make([]string, len(valueMatches)) 116 for i, match := range valueMatches { 117 values[i] = strings.TrimSpace(match[1]) 118 } 119 120 return EnumType{Name: enumName, Values: values} 121 } 122 123 func toCamelCase(s string) string { 124 words := strings.Split(strings.ToLower(s), "_") 125 for i, word := range words { 126 words[i] = strings.Title(word) 127 } 128 return strings.Join(words, "") 129 }