添加了对 proto 的解析支持
This commit is contained in:
@@ -0,0 +1,11 @@
|
||||
package zm_proto
|
||||
|
||||
type Import struct {
|
||||
Name string
|
||||
Path string
|
||||
Messages []Message
|
||||
Imports []string
|
||||
Enum map[string]bool
|
||||
|
||||
Proto *Proto
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package zm_proto
|
||||
|
||||
type Message struct {
|
||||
Name string
|
||||
Fields []Field
|
||||
|
||||
Import *Import
|
||||
}
|
||||
|
||||
func (m *Message) GetImportName() string {
|
||||
return m.Import.Name
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
package zm_proto
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"regexp"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type Port struct {
|
||||
Cmd string // 地址
|
||||
PortDesc string // 描述
|
||||
ClientPB string //
|
||||
ServerPB string
|
||||
ConnectType string
|
||||
IsPush bool
|
||||
Parallel bool
|
||||
|
||||
Proto *Proto
|
||||
}
|
||||
|
||||
func ParsePort(Proto *Proto, path string) ([]Port, error) {
|
||||
bytes, err := os.ReadFile(path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
mustPort := regexp.MustCompile(`/\*/*Cmd=.+\*/`)
|
||||
|
||||
result := mustPort.FindAllStringSubmatch(string(bytes), -1)
|
||||
//fmt.Println("result", result)
|
||||
var ports []Port
|
||||
for _, res := range result {
|
||||
for _, match := range res {
|
||||
match = match[2 : len(match)-2]
|
||||
// fmt.Println("match", match)
|
||||
var p = Port{Proto: Proto}
|
||||
for _, fieldStr := range strings.Split(match, ";") {
|
||||
fieldslice := strings.Split(fieldStr, "=")
|
||||
if len(fieldslice) != 2 {
|
||||
return nil, fmt.Errorf("invalid field: %s, match: %s", fieldStr, match)
|
||||
}
|
||||
switch fieldslice[0] {
|
||||
case "Cmd":
|
||||
p.Cmd = fieldslice[1]
|
||||
case "PortDesc":
|
||||
p.PortDesc = fieldslice[1]
|
||||
case "ClientPB":
|
||||
p.ClientPB = fieldslice[1]
|
||||
case "ServerPB":
|
||||
p.ServerPB = fieldslice[1]
|
||||
case "ConnectType":
|
||||
p.ConnectType = fieldslice[1]
|
||||
case "IsPush":
|
||||
p.IsPush = fieldslice[1] == "true"
|
||||
case "Parallel":
|
||||
p.Parallel = fieldslice[1] == "true"
|
||||
}
|
||||
}
|
||||
ports = append(ports, p)
|
||||
}
|
||||
}
|
||||
return ports, nil
|
||||
}
|
||||
@@ -0,0 +1,213 @@
|
||||
package zm_proto
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/emicklei/proto"
|
||||
"os"
|
||||
"path/filepath"
|
||||
)
|
||||
|
||||
type Field struct {
|
||||
Name string
|
||||
Type string
|
||||
Repeated bool
|
||||
}
|
||||
|
||||
type Proto struct {
|
||||
Imports map[string]Import
|
||||
|
||||
Enum map[string]bool
|
||||
|
||||
Dir []string
|
||||
}
|
||||
|
||||
func NewProto() *Proto {
|
||||
return &Proto{
|
||||
Imports: make(map[string]Import),
|
||||
Enum: make(map[string]bool),
|
||||
}
|
||||
}
|
||||
|
||||
func (p *Proto) AddImport(name string, imp Import) {
|
||||
p.Imports[name] = imp
|
||||
p.AddEnum(imp.Enum)
|
||||
}
|
||||
|
||||
func (p *Proto) AddEnum(name map[string]bool) {
|
||||
for k := range name {
|
||||
p.Enum[k] = true
|
||||
}
|
||||
}
|
||||
|
||||
func (p *Proto) Include(dir ...string) *Proto {
|
||||
p.Dir = append(p.Dir, dir...)
|
||||
return p
|
||||
}
|
||||
|
||||
func (p *Proto) FindPathByDir(protoImport string) string {
|
||||
for _, dir := range p.Dir {
|
||||
path := filepath.Join(dir, protoImport)
|
||||
_, err := os.Stat(path)
|
||||
if err == nil {
|
||||
return path
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (p *Proto) ParseAllImport() error {
|
||||
for _, dir := range p.Dir {
|
||||
readDir, err := os.ReadDir(dir)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to read dir %s: %w", dir, err)
|
||||
}
|
||||
for _, f := range readDir {
|
||||
if f.IsDir() {
|
||||
continue
|
||||
}
|
||||
if filepath.Ext(f.Name()) != ".proto" {
|
||||
continue
|
||||
}
|
||||
if p.Imports[f.Name()].Name != "" {
|
||||
continue
|
||||
}
|
||||
if err = p.parseImport(filepath.Join(dir, f.Name())); err != nil {
|
||||
return fmt.Errorf("failed to parse file %s: %w", f.Name(), err)
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *Proto) ParseImport(protoImport string) error {
|
||||
path := p.FindPathByDir(protoImport)
|
||||
if path == "" {
|
||||
return fmt.Errorf("import %s not found", path)
|
||||
}
|
||||
err := p.parseImport(path)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to parse import %s: %w", path, err)
|
||||
}
|
||||
for _, i := range p.Imports[protoImport].Imports {
|
||||
if err = p.ParseImport(i); err != nil {
|
||||
return fmt.Errorf("failed to parse import %s: %w", i, err)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *Proto) parseImport(path string) error {
|
||||
//ext := filepath.Ext(path)
|
||||
//name := filepath.Base(path)[:len(filepath.Base(path))-len(ext)]
|
||||
|
||||
name := filepath.Base(path)
|
||||
reader, err := os.Open(path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer reader.Close()
|
||||
|
||||
parser := proto.NewParser(reader)
|
||||
definition, err := parser.Parse()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var msgs []*Message
|
||||
var enums = make(map[string]bool)
|
||||
var imports []string
|
||||
|
||||
var imp = Import{
|
||||
Name: name,
|
||||
Path: path,
|
||||
Proto: p,
|
||||
}
|
||||
proto.Walk(definition,
|
||||
proto.WithImport(func(i *proto.Import) {
|
||||
//ext1 := filepath.Ext(i.Filename)
|
||||
//name1 := filepath.Base(i.Filename)[:len(filepath.Base(i.Filename))-len(ext1)]
|
||||
imports = append(imports, i.Filename)
|
||||
}),
|
||||
|
||||
proto.WithEnum(func(enum *proto.Enum) {
|
||||
enums[enum.Name] = true
|
||||
}),
|
||||
proto.WithNormalField(func(field *proto.NormalField) {
|
||||
lastmsg := msgs[len(msgs)-1]
|
||||
lastmsg.Fields = append(lastmsg.Fields, Field{
|
||||
Name: field.Name,
|
||||
Type: field.Type,
|
||||
Repeated: field.Repeated,
|
||||
})
|
||||
|
||||
}),
|
||||
proto.WithMessage(func(message *proto.Message) {
|
||||
msgs = append(msgs, &Message{
|
||||
Name: message.Name,
|
||||
Fields: []Field{},
|
||||
Import: &imp,
|
||||
})
|
||||
}))
|
||||
|
||||
imp.Imports = imports
|
||||
imp.Enum = enums
|
||||
|
||||
for _, msg := range msgs {
|
||||
imp.Messages = append(imp.Messages, *msg)
|
||||
}
|
||||
|
||||
p.AddImport(name, imp)
|
||||
return nil
|
||||
}
|
||||
|
||||
var defaultTypeMap = map[string]any{
|
||||
"int32": 0,
|
||||
"int64": 0,
|
||||
"bool": false,
|
||||
"string": "ok",
|
||||
"byte": "byte",
|
||||
}
|
||||
|
||||
func (p *Proto) MessageToMap(name string) (string, map[string]any) {
|
||||
var msg = make(map[string]any)
|
||||
var erlMod = ""
|
||||
for _, i := range p.Imports {
|
||||
for _, m := range i.Messages {
|
||||
if m.Name == name {
|
||||
ext := filepath.Ext(i.Name)
|
||||
erlMod = filepath.Base(i.Name)[:len(filepath.Base(i.Name))-len(ext)]
|
||||
|
||||
for _, field := range m.Fields {
|
||||
defaultValue := defaultTypeMap[field.Type]
|
||||
if defaultValue == nil {
|
||||
_, defaultValue = p.MessageToMap(field.Type)
|
||||
}
|
||||
if field.Repeated {
|
||||
if defaultValue == nil {
|
||||
defaultValue = []any{}
|
||||
}
|
||||
}
|
||||
msg[field.Name] = defaultValue
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if len(msg) == 0 || erlMod == "" {
|
||||
return "single_str", nil
|
||||
}
|
||||
return erlMod, msg
|
||||
}
|
||||
|
||||
// MessageToErlMod z
|
||||
func (p *Proto) MessageToErlMod(name string) string {
|
||||
for _, i := range p.Imports {
|
||||
for _, m := range i.Messages {
|
||||
if m.Name == name {
|
||||
ext := filepath.Ext(i.Name)
|
||||
erlMod := filepath.Base(i.Name)[:len(filepath.Base(i.Name))-len(ext)]
|
||||
return erlMod
|
||||
}
|
||||
}
|
||||
}
|
||||
return "single_str"
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package zm_proto
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestP1(t *testing.T) {
|
||||
pb := NewProto()
|
||||
err := pb.ParseImport("game\\pro_array.proto")
|
||||
fmt.Println(err)
|
||||
fmt.Println(pb)
|
||||
}
|
||||
Reference in New Issue
Block a user