Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added bin/csharp/Google.Protobuf.dll
Binary file not shown.
Binary file added bin/csharp/System.Buffers.dll
Binary file not shown.
Binary file added bin/csharp/System.Memory.dll
Binary file not shown.
Binary file not shown.
2 changes: 1 addition & 1 deletion proto/common.proto
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
syntax = "proto3";

package proto;
package gogs;
option go_package = "/proto";


Expand Down
35 changes: 35 additions & 0 deletions tools/gogs/cmd/csharp.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package cmd

import (
"fmt"
"os"

"github.com/metagogs/gogs/tools/gogs/csharp"
"github.com/pterm/pterm"
"github.com/spf13/cobra"
)

func init() {
RootCmd.AddCommand(csharpCmd)
csharpCmd.Flags().StringVarP(&protoFile, "file", "f", "", "proto file")
csharpCmd.Flags().BoolVarP(&gogsFiles, "gogs", "g", false, "should generate gogs framework code")
}

var csharpCmd = &cobra.Command{
Use: "csharp",
Short: "generate csharp code",
Long: ``,
Run: func(cmd *cobra.Command, args []string) {
if len(protoFile) == 0 {
pterm.Error.Printfln("proto file is empty")
os.Exit(1)
}

fmt.Println(gogsFiles)
gen, err := csharp.NewCSharpGen(protoFile, gogsFiles)
if err != nil {
fmt.Println(err)
}
_ = gen.Generate()
},
}
6 changes: 6 additions & 0 deletions tools/gogs/cmd/flags.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package cmd

var (
protoFile string
gogsFiles bool
)
6 changes: 1 addition & 5 deletions tools/gogs/cmd/proto.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,9 @@ import (
"github.com/spf13/cobra"
)

var (
protoFile string
)

func init() {
RootCmd.AddCommand(protoCmd)
protoCmd.Flags().StringVarP(&protoFile, "file", "f", "", "proto文件")
protoCmd.Flags().StringVarP(&protoFile, "file", "f", "", "proto file")
}

var protoCmd = &cobra.Command{
Expand Down
196 changes: 196 additions & 0 deletions tools/gogs/csharp/gen.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,196 @@
package csharp

import (
"fmt"
"os"

"github.com/emicklei/proto"
"github.com/metagogs/gogs/packet"
"github.com/metagogs/gogs/tools/gogs/csharp/gentemplate"
"github.com/metagogs/gogs/tools/gogs/protoparse"
"github.com/metagogs/gogs/utils/execx"
"github.com/metagogs/gogs/utils/templatex"
"github.com/pterm/pterm"
)

type Components struct {
Components []*Component
}

type Component struct {
Name string
Index int
BasePackage string
Fields []*Field
}

type Field struct {
ComponentName string
ComponentIndex int
BasePackage string
Package string
Name string
Index int
ServerMessage bool
Action10 string //action 10进制
Action16 string //action 16进制
}

type CSharpGen struct {
proto protoparse.Proto
protoFile string
componets *Components
messages map[string]protoparse.Message
basePackage string
Home string
logicPath []string
debugNoPb bool
onlyCode bool //just generate code by proto exinclude gogs
}

func NewCSharpGen(proto string, onlyCode bool) (*CSharpGen, error) {
protoPrase, err := protoparse.NewProtoParser().Parse(proto)
if err != nil {
return nil, err
}
return &CSharpGen{
protoFile: proto,
proto: protoPrase,
messages: make(map[string]protoparse.Message),
onlyCode: onlyCode,
}, nil
}

func (g *CSharpGen) Generate() error {
g.init()

if g.onlyCode {
if err := g.gogs(); err != nil {
return err
}
}

if err := g.register(); err != nil {
return err
}

return nil
}

func (g *CSharpGen) init() {
g.componets = new(Components)
for _, m := range g.proto.Message {
g.messages[m.Name] = m
}
//find components
for _, m := range g.proto.Message {
if m.Comment == nil {
continue
}
if protoparse.CommentsContains(m.Comment.Lines, "@gogs:Components") {
for _, e := range m.Elements {
if v, ok := e.(*proto.NormalField); ok {
com := g.parseComponent(v)
g.componets.Components = append(g.componets.Components, com)
}
}
}
}

for _, c := range g.componets.Components {
pterm.Success.Printf("Component: %s [%d]\n", c.Name, c.Index)
for _, f := range c.Fields {
pterm.Success.Printf(" Field: %s [%d][%v]\n", f.Name, f.Index, f.ServerMessage)
}
}
}

func (g *CSharpGen) parseComponent(component *proto.NormalField) *Component {
newCompoent := &Component{}
newCompoent.Name = component.Name
newCompoent.Index = component.Sequence
newCompoent.BasePackage = g.basePackage

for _, e := range g.messages[component.Name].Elements {
if v, ok := e.(*proto.NormalField); ok {
data := &Field{}
data.ComponentName = component.Name
data.ComponentIndex = component.Sequence
data.Name = v.Name
data.Index = v.Sequence
data.Package = g.proto.PbPackage
data.BasePackage = g.basePackage
//create action
actionValue := packet.CreateAction(packet.ServicePacket, uint8(data.ComponentIndex), uint16(data.Index))
data.Action10 = fmt.Sprint(actionValue)
data.Action16 = fmt.Sprintf("0x%x", actionValue)
if g.messages[v.Name].Comment != nil {
if protoparse.CommentsContains(g.messages[v.Name].Comment.Lines, "@gogs:ServerMessage") {
data.ServerMessage = true
}
}

newCompoent.Fields = append(newCompoent.Fields, data)
}
}

return newCompoent

}

func (g *CSharpGen) gogs() error {
if err := templatex.With("gogs").Parse(gentemplate.CodecTpl).SaveTo(nil, g.Home+"Gogs/Codec.cs", true); err != nil {
pterm.Error.Printfln("generate file error Gogs/Codec.cs:" + err.Error())
return err
}
if err := templatex.With("gogs").Parse(gentemplate.CommonTpl).SaveTo(nil, g.Home+"Gogs/Common.cs", true); err != nil {
pterm.Error.Printfln("generate file error Gogs/Common.cs:" + err.Error())
return err
}
if err := templatex.With("gogs").Parse(gentemplate.EventsManagerTpl).SaveTo(nil, g.Home+"Gogs/EventsManager.cs", true); err != nil {
pterm.Error.Printfln("generate file error Gogs/EventsManager.cs:" + err.Error())
return err
}
if err := templatex.With("gogs").Parse(gentemplate.ICodecTpl).SaveTo(nil, g.Home+"Gogs/ICodec.cs", true); err != nil {
pterm.Error.Printfln("generate file error Gogs/ICodec.cs:" + err.Error())
return err
}
if err := templatex.With("gogs").Parse(gentemplate.MessagesTpl).SaveTo(nil, g.Home+"Gogs/Messages.cs", true); err != nil {
pterm.Error.Printfln("generate file error Gogs/Messages.cs:" + err.Error())
return err
}
if err := templatex.With("gogs").Parse(gentemplate.PacketTpl).SaveTo(nil, g.Home+"Gogs/Packet.cs", true); err != nil {
pterm.Error.Printfln("generate file error Gogs/Packet.cs:" + err.Error())
return err
}

return nil
}

func (g *CSharpGen) register() error {
out := "Model"
if len(g.Home) > 0 {
out = g.Home + "Model"
}
if !g.debugNoPb {
_ = os.MkdirAll(out, os.ModePerm)
protocCmd := fmt.Sprintf("protoc --csharp_out=%s %s", out, g.protoFile)
if _, err := execx.Exec(protocCmd); err != nil {
fmt.Println(err.Error())
pterm.Error.Println("run protoc error " + err.Error())
return err
}

}

data := map[string]interface{}{}
data["Package"] = g.proto.PbPackage
data["Components"] = g.componets.Components

if err := templatex.With("gogs").Parse(gentemplate.RegisterTpl).SaveTo(data, g.Home+"Model/Register.cs", true); err != nil {
pterm.Error.Printfln("generate file error Model/Register.cs:" + err.Error())
return err
}

return nil
}
54 changes: 54 additions & 0 deletions tools/gogs/csharp/gen_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package csharp

import (
"os"
"testing"

"github.com/metagogs/gogs/utils/filex"
)

func TestNewGen(t *testing.T) {
type args struct {
proto string
onlyCode bool
}
tests := []struct {
name string
args args
wantErr bool
}{
{
name: "new gen",
args: args{
proto: "testdata/data.proto",
onlyCode: false,
},
wantErr: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
g, err := NewCSharpGen(tt.args.proto, tt.args.onlyCode)
g.Home = "test/"
if (err != nil) != tt.wantErr {
t.Errorf("NewGen() error = %v, wantErr %v", err, tt.wantErr)
return
}
_ = g.Generate()
if (err != nil) != tt.wantErr {
t.Errorf("NewGen() error = %v, wantErr %v", err, tt.wantErr)
return
}

var haveErr bool
if ok := filex.IsFileEqual("testdata/Model/Register.cs", "test/Model/Register.cs"); !ok {
t.Errorf("Init.Generate() error = %s is not equal to %s", "test/Model/Register.cs", "testdata/Model/Register.cs")
haveErr = true
}

if !haveErr {
_ = os.RemoveAll("test")
}
})
}
}
36 changes: 36 additions & 0 deletions tools/gogs/csharp/gentemplate/Gogs/Codec.tpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
using System;
using System.Collections.Generic;
using Google.Protobuf;

namespace Gogs
{
class ProtoEncode : IEncode
{
public byte[] Encode(IMessage msg)
{
if (msg is IMessage message)
{
return message.ToByteArray();
}

throw new Exception("object is not the message type");
}
}

class ProtoDecode : IDecode
{
static readonly Dictionary<String, MessageParser> parses = new Dictionary<String, MessageParser>();

public T Decode<T>(byte[] data) where T : IMessage<T>, new()
{
if (parses.TryGetValue(typeof(T).Name, out MessageParser parse))
{
return (T)parse.ParseFrom(data);
}

Google.Protobuf.MessageParser<T> newParse = new Google.Protobuf.MessageParser<T>(() => new T());
parses[typeof(T).Name] = newParse;
return newParse.ParseFrom(data);
}
}
}
Loading