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  }