github.com/Mrs4s/MiraiGo@v0.0.0-20240226124653-54bdd873e3fe/internal/generator/c2c_switcher/c2c_switcher.go (about)

     1  package main
     2  
     3  import (
     4  	"bytes"
     5  	"go/ast"
     6  	"go/format"
     7  	"go/parser"
     8  	"go/token"
     9  	"os"
    10  	"sort"
    11  	"strconv"
    12  	"text/template"
    13  )
    14  
    15  const codeTemplate = `// Code generated by internal/generator/c2c_switcher DO NOT EDIT.
    16  
    17  package client
    18  
    19  import (
    20  {{range .Imports}}	{{.}}
    21  {{end}}
    22  )
    23  
    24  const (
    25  	UnknownDecoder = iota
    26  {{range .Consts}}	{{.}}
    27  {{end}}
    28  )
    29  
    30  func peekC2CDecoder(msgType int32) (decoder func(*QQClient, *msg.Message, network.RequestParams), decoderType uint8) {
    31      switch msgType {
    32  {{range .Decoders}}	case {{.Id}}:
    33  		return {{.Func}}, {{.DecoderType}}
    34  {{end}}	default:
    35          return nil, UnknownDecoder
    36      }
    37  }`
    38  
    39  type decoder struct {
    40  	Id          int64
    41  	Func        string
    42  	DecoderType string
    43  }
    44  type DecoderSort []decoder
    45  
    46  func (d DecoderSort) Len() int           { return len(d) }
    47  func (d DecoderSort) Swap(i, j int)      { d[i], d[j] = d[j], d[i] }
    48  func (d DecoderSort) Less(i, j int) bool { return d[i].Id < d[j].Id }
    49  
    50  func main() {
    51  	type switchFile struct {
    52  		Imports  []string
    53  		Consts   []string
    54  		Decoders DecoderSort
    55  	}
    56  	var sf switchFile
    57  
    58  	fset := token.NewFileSet()
    59  	astF, err := parser.ParseFile(fset, "_c2c_decoders.go", nil, parser.AllErrors|parser.ParseComments)
    60  	if err != nil {
    61  		panic(err)
    62  	}
    63  
    64  	sf.Imports = make([]string, 0, len(astF.Imports))
    65  	for _, imp := range astF.Imports {
    66  		sf.Imports = append(sf.Imports, imp.Path.Value)
    67  	}
    68  
    69  	sf.Consts = make([]string, 0, len(astF.Scope.Objects))
    70  	for _, obj := range astF.Scope.Objects {
    71  		if obj.Kind != ast.Var {
    72  			panic(`unknown non-variable in "_c2c_decoders.go"`)
    73  		}
    74  		value := obj.Decl.(*ast.ValueSpec)
    75  		sf.Consts = append(sf.Consts, obj.Name)
    76  		for _, value := range value.Values {
    77  			if value, ok := value.(*ast.CompositeLit); ok {
    78  				for _, kv := range value.Elts {
    79  					if kv, ok := kv.(*ast.KeyValueExpr); ok {
    80  						k := kv.Key.(*ast.BasicLit)
    81  						v := kv.Value.(*ast.Ident)
    82  						sf.Decoders = append(sf.Decoders, decoder{
    83  							Id:          mustParseInt(k.Value),
    84  							Func:        v.Name,
    85  							DecoderType: obj.Name,
    86  						})
    87  					} else {
    88  						panic(`unknown key value in ` + obj.Name + ` in "_c2c_decoders.go"`)
    89  					}
    90  				}
    91  			} else {
    92  				panic(`unknown non-map value in "_c2c_decoders.go"`)
    93  			}
    94  		}
    95  	}
    96  	sort.Slice(sf.Consts, func(i, j int) bool {
    97  		return sf.Consts[i] < sf.Consts[j]
    98  	})
    99  	sort.Sort(sf.Decoders)
   100  
   101  	f, _ := os.OpenFile("c2c_switch.go", os.O_WRONLY|os.O_CREATE|os.O_SYNC|os.O_TRUNC, 0o644)
   102  	tmpl, err := template.New("template").Parse(codeTemplate)
   103  	if err != nil {
   104  		panic(err)
   105  	}
   106  	buffer := &bytes.Buffer{}
   107  	err = tmpl.Execute(buffer, &sf)
   108  	if err != nil {
   109  		panic(err)
   110  	}
   111  	source, _ := format.Source(buffer.Bytes())
   112  	_, _ = f.Write(source)
   113  	_ = f.Close()
   114  }
   115  
   116  func mustParseInt(s string) int64 {
   117  	i, err := strconv.ParseInt(s, 10, 32)
   118  	if err != nil {
   119  		panic(err)
   120  	}
   121  	return i
   122  }