Skip to content

Commit

Permalink
Merge pull request #225 from topfreegames/bugfix/clientproto
Browse files Browse the repository at this point in the history
[bugfix] Protoclient was crashing if any handler had no outputs
  • Loading branch information
gabrielcorado committed Jul 29, 2021
2 parents 3b3a670 + ce8c93a commit 565ab50
Show file tree
Hide file tree
Showing 7 changed files with 761 additions and 245 deletions.
3 changes: 3 additions & 0 deletions Makefile
Expand Up @@ -50,6 +50,9 @@ run-custom-metrics-example:
run-rate-limiting-example:
@go run examples/demo/rate_limiting/main.go

protos-compile-demo:
@protoc -I examples/demo/protos examples/demo/protos/*.proto --go_out=.

protos-compile:
@cd benchmark/testdata && ./gen_proto.sh
@protoc -I pitaya-protos/ pitaya-protos/*.proto --go_out=plugins=grpc:protos
Expand Down
31 changes: 18 additions & 13 deletions client/protoclient.go
Expand Up @@ -26,6 +26,7 @@ import (
"crypto/tls"
"encoding/json"
"errors"
"fmt"
"io/ioutil"
"strings"
"time"
Expand Down Expand Up @@ -144,6 +145,11 @@ func getOutputInputNames(command map[string]interface{}) (string, string, error)

out := command["output"]
outputDocsArr := out.([]interface{})
// we can have handlers that have no return specified.
if len(outputDocsArr) == 0 {
return inputName, "", nil
}

outputDocs, ok := outputDocsArr[0].(map[string]interface{})
if ok {
for k := range outputDocs {
Expand Down Expand Up @@ -211,7 +217,7 @@ func (pc *ProtoClient) getDescriptors(data string) error {
cmdInfo := v.(map[string]interface{})
in, out, err := getOutputInputNames(cmdInfo)
if err != nil {
return err
return fmt.Errorf("failed to get output and input names for '%s' handler: %w", k, err)
}

var command Command
Expand Down Expand Up @@ -250,33 +256,33 @@ func (pc *ProtoClient) getDescriptors(data string) error {

encodedNames, err := proto.Marshal(protname)
if err != nil {
return err
return fmt.Errorf("failed to encode proto names: %w", err)
}
_, err = pc.SendRequest(pc.descriptorsRoute, encodedNames)
if err != nil {
return err
return fmt.Errorf("failed to send proto descriptors request: %w", err)
}

response := <-pc.Client.IncomingMsgChan
descriptors := &protos.ProtoDescriptors{}
if err := proto.Unmarshal(response.Data, descriptors); err != nil {
return err
return fmt.Errorf("failed to unmarshal proto descriptors response: %w", err)
}

// get all proto types
descriptorArray := make([]*protobuf.FileDescriptorProto, 0)
for i := range descriptors.Desc {
fileDescriptorProto, err := unpackDescriptor(descriptors.Desc[i])
if err != nil {
return err
return fmt.Errorf("failed to unpack descriptor: %w", err)
}

descriptorArray = append(descriptorArray, fileDescriptorProto)
pc.descriptorsNames[names[i]] = true
}

if err = pc.buildProtosFromDescriptor(descriptorArray); err != nil {
return err
return fmt.Errorf("failed to build proto from descriptor: %w", err)
}

return nil
Expand Down Expand Up @@ -341,11 +347,11 @@ func (pc *ProtoClient) LoadServerInfo(addr string) error {

docs := &protos.Doc{}
if err := proto.Unmarshal(response.Data, docs); err != nil {
return err
return fmt.Errorf("failed to unmarshal docs route response: %w", err)
}

if err := pc.getDescriptors(docs.Doc); err != nil {
return err
return fmt.Errorf("failed to read proto descriptors: %w", err)
}

pc.Disconnect()
Expand All @@ -369,7 +375,6 @@ func (pc *ProtoClient) waitForData() {
for {
select {
case response := <-pc.Client.IncomingMsgChan:

inputMsg := dynamic.NewMessage(pc.expectedInputDescriptor)

msg, ok := pc.info.Commands[response.Route]
Expand All @@ -388,27 +393,27 @@ func (pc *ProtoClient) waitForData() {
}
response.Data, err = json.Marshal(errMsg)
if err != nil {
logger.Log.Errorf("Erro encode error to json: %s", string(response.Data))
logger.Log.Errorf("error encode error to json: %s", string(response.Data))
continue
}
pc.IncomingMsgChan <- response
continue
}

if inputMsg == nil {
logger.Log.Errorf("Not expected data: %s", string(response.Data))
logger.Log.Errorf("not expected data: %s", string(response.Data))
continue
}

err := inputMsg.Unmarshal(response.Data)
if err != nil {
logger.Log.Errorf("Erro decode data: %s", string(response.Data))
logger.Log.Errorf("error decode data: %s", string(response.Data))
continue
}

data, err2 := inputMsg.MarshalJSON()
if err2 != nil {
logger.Log.Errorf("Erro encode data to json: %s", string(response.Data))
logger.Log.Errorf("error encode data to json: %s", string(response.Data))
continue
}

Expand Down
5 changes: 3 additions & 2 deletions examples/demo/cluster/main.go
Expand Up @@ -13,7 +13,7 @@ import (
"github.com/topfreegames/pitaya/component"
"github.com/topfreegames/pitaya/examples/demo/cluster/services"
"github.com/topfreegames/pitaya/route"
"github.com/topfreegames/pitaya/serialize/json"
"github.com/topfreegames/pitaya/serialize/protobuf"
)

func configureBackend() {
Expand All @@ -36,6 +36,7 @@ func configureFrontend(port int) {
component.WithName("connector"),
component.WithNameFunc(strings.ToLower),
)

pitaya.RegisterRemote(&services.ConnectorRemote{},
component.WithName("connectorremote"),
component.WithNameFunc(strings.ToLower),
Expand Down Expand Up @@ -82,7 +83,7 @@ func main() {

defer pitaya.Shutdown()

pitaya.SetSerializer(json.NewSerializer())
pitaya.SetSerializer(protobuf.NewSerializer())

if !*isFrontend {
configureBackend()
Expand Down
64 changes: 21 additions & 43 deletions examples/demo/cluster/services/connector.go
Expand Up @@ -8,6 +8,7 @@ import (
"github.com/topfreegames/pitaya"
"github.com/topfreegames/pitaya/component"
"github.com/topfreegames/pitaya/examples/demo/protos"
pitayaprotos "github.com/topfreegames/pitaya/protos"
)

// ConnectorRemote is a remote that will receive rpc's
Expand All @@ -20,53 +21,14 @@ type Connector struct {
component.Base
}

// SessionData struct
type SessionData struct {
Data map[string]interface{}
}

// Response struct
type Response struct {
Code int32
Msg string
}

func reply(code int32, msg string) (*Response, error) {
res := &Response{
func reply(code int32, msg string) (*protos.Response, error) {
res := &protos.Response{
Code: code,
Msg: msg,
}
return res, nil
}

// GetSessionData gets the session data
func (c *Connector) GetSessionData(ctx context.Context) (*SessionData, error) {
s := pitaya.GetSessionFromCtx(ctx)
res := &SessionData{
Data: s.GetData(),
}
return res, nil
}

// SetSessionData sets the session data
func (c *Connector) SetSessionData(ctx context.Context, data *SessionData) (*Response, error) {
s := pitaya.GetSessionFromCtx(ctx)
err := s.SetData(data.Data)
if err != nil {
return nil, pitaya.Error(err, "CN-000", map[string]string{"failed": "set data"})
}
return reply(200, "success")
}

// NotifySessionData sets the session data
func (c *Connector) NotifySessionData(ctx context.Context, data *SessionData) {
s := pitaya.GetSessionFromCtx(ctx)
err := s.SetData(data.Data)
if err != nil {
fmt.Println("got error on notify", err)
}
}

// RemoteFunc is a function that will be called remotely
func (c *ConnectorRemote) RemoteFunc(ctx context.Context, msg *protos.RPCMsg) (*protos.RPCRes, error) {
fmt.Printf("received a remote call with this message: %s\n", msg.GetMsg())
Expand All @@ -76,7 +38,7 @@ func (c *ConnectorRemote) RemoteFunc(ctx context.Context, msg *protos.RPCMsg) (*
}

// Docs returns documentation
func (c *ConnectorRemote) Docs(ctx context.Context, ddd *protos.Doc) (*protos.Doc, error) {
func (c *ConnectorRemote) Docs(ctx context.Context) (*pitayaprotos.Doc, error) {
d, err := pitaya.Documentation(true)
if err != nil {
return nil, err
Expand All @@ -87,5 +49,21 @@ func (c *ConnectorRemote) Docs(ctx context.Context, ddd *protos.Doc) (*protos.Do
return nil, err
}

return &protos.Doc{Doc: string(doc)}, nil
fmt.Println(string(doc))
return &pitayaprotos.Doc{Doc: string(doc)}, nil
}

func (c *ConnectorRemote) Descriptor(ctx context.Context, names *pitayaprotos.ProtoNames) (*pitayaprotos.ProtoDescriptors, error) {
descriptors := make([][]byte, len(names.Name))

for i, protoName := range names.Name {
desc, err := pitaya.Descriptor(protoName)
if err != nil {
return nil, fmt.Errorf("failed to get descriptor for '%s': %w", protoName, err)
}

descriptors[i] = desc
}

return &pitayaprotos.ProtoDescriptors{Desc: descriptors}, nil
}

0 comments on commit 565ab50

Please sign in to comment.