Coder Social home page Coder Social logo

topfreegames / pitaya Goto Github PK

View Code? Open in Web Editor NEW
2.2K 89.0 445.0 6.42 MB

Scalable game server framework with clustering support and client libraries for iOS, Android, Unity and others through the C SDK.

License: MIT License

Makefile 0.79% Go 98.95% Dockerfile 0.06% JavaScript 0.20%
game-server golang-application game-framework game android ios

pitaya's Introduction

pitaya Build Status Coverage Status GoDoc Docs Go Report Card MIT licensed

WARNING: The version v1.x of pitaya is deprecated, complete guide of the new version v2.x can be found here. The current README is for version v2.x, make sure you look at branch v1 if you'd like to see the documentation for the older version.


Pitaya is an simple, fast and lightweight game server framework with clustering support and client libraries for iOS, Android, Unity and others through the C SDK. It provides a basic development framework for distributed multiplayer games and server-side applications.

Getting Started

Prerequisites

  • Go >= 1.16
  • etcd (optional, used for service discovery)
  • nats (optional, used for sending and receiving rpc)
  • docker (optional, used for running etcd and nats dependencies on containers)

Installing

clone the repo

git clone https://github.com/topfreegames/pitaya.git

setup pitaya dependencies

make setup

Hacking pitaya

Here's one example of running Pitaya:

Start etcd (This command requires docker-compose and will run an etcd container locally. An etcd may be run without docker if preferred.)

cd ./examples/testing && docker-compose up -d etcd

run the connector frontend server from cluster_grpc example

make run-cluster-grpc-example-connector

run the room backend server from the cluster_grpc example

make run-cluster-grpc-example-room

Now there should be 2 pitaya servers running, a frontend connector and a backend room. To send requests, use a REPL client for pitaya pitaya-cli.

$ pitaya-cli
Pitaya REPL Client
>>> connect localhost:3250
connected!
>>> request room.room.entry
>>> sv-> {"code":0,"result":"ok"}

Running the tests

make test

This command will run both unit and e2e tests.

Contributing

#TODO

Authors

  • TFG Co - Initial work

License

MIT License

Acknowledgements

  • nano authors for building the framework pitaya is based on.
  • pomelo authors for the inspiration on the distributed design and protocol

Security

If you have found a security vulnerability, please email [email protected]

Resources

pitaya's People

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

pitaya's Issues

Pitaya should have an admin

With the admin people will be able to manage the servers, see monitoring and servers details, make RPCs and also do some LiveOps

I am a beginner

I am a beginner, is there a complete demo to Introduce some features, like pomelo 'lordofpomelo'

Cannot send messages larger than 2048 bytes

func (h *HandlerService) Handle(conn net.Conn) {

Cannot send messages larger than 2048 bytes.
Sending a message greater than 2048 results in an error, It's pretty certain。

buf := make([]byte, 2048) Unable to read the full message causing an error
This code needs to be modified to read all the message contents at once.

Connector logs "Error reading next available message: invalid header" on player disconnection

Version used: v1.1.0

Connector keeps spamming this "Error reading next available message: invalid header" message:

{"file":"/home/jenkins/jobs/tennis-build-backend/builds/988/pkg/mod/github.com/topfreegames/[email protected]/service/handler.go:186","func":"github.com/topfreegames/pitaya/service.(*HandlerService).Handle","level":"error","msg":"Error reading next available message: invalid header","server":"connector","source":"tennis","time":"2020-04-22T01:06:03Z”}
Is that expected or are we doing something wrong? Apparently it happens when a user disconnects. Doesn’t seem to cause any harm, but if this is not really an unexpected error, we could make it a debug log.

Related code:

logger.Log.Errorf("Error reading next available message: %s", err.Error())

MaxPacketSize excced error.

We used to transfer files when using pitaya, but there was an error that the size exceeded 64k. Can MaxPacketSize be modified to be configured through the configuration file?

Concurrent access to servers list leads to panic

Hi,

A concurrency bug can lead to server crashes in very specific circumstances when acessing and iterating over the map of servers by type returned.

The map returned by GetServersByType, from etcd's service discovery implementation is the same that is updated by the service discovery routine. This leads to possible concurrent read and write if the service discovery routine updates the map at the same time that another function is accessing the map, every request received by a front end server calls GetServersByType, so this is probably the most common user of the method.

Returning the map which is modified by the service can also lead to misuse of this structure and inconsistencies in the service discovery data.

Implement some kind of circuit break for RPCs

If a server dies ungracefully, others will take some time before realising it and will continue sending RPC to the dead server meanwhile, we could setup some kind of circuit break in each servers, could be a black list of servers that are failing too much.

concurrent write to websocket connection

concurrent write to websocket connection

	if c.isWriting {
		panic("concurrent write to websocket connection")
	}
	c.isWriting = true

when use websocket, we find error code. agent use two goroutine for write websocket conn. but websocket ntoes : Connections support one concurrent reader and one concurrent writer

func (a *Agent) Handle() {
	defer func() {
		a.Close()
		logger.Log.Debugf("Session handle goroutine exit, SessionID=%d, UID=%d", a.Session.ID(), a.Session.UID())
	}()

	go a.write()
	go a.heartbeat()
	select {
	case <-a.chDie: // agent closed signal
		return
	}
}

https://godoc.org/github.com/gorilla/websocket#hdr-Concurrency
Concurrency ¶
Connections support one concurrent reader and one concurrent writer.
Applications are responsible for ensuring that no more than one goroutine calls the write methods (NextWriter, SetWriteDeadline, WriteMessage, WriteJSON, EnableWriteCompression, SetCompressionLevel) concurrently and that no more than one goroutine calls the read methods (NextReader, SetReadDeadline, ReadMessage, ReadJSON, SetPongHandler, SetPingHandler) concurrently.
The Close and WriteControl methods can be called concurrently with all other methods.

so we must fix agent.go, use one goroutine to send websocket msg like nano

panic: send on closed channel

Versions

  • Pitaya:1.1.1

Summary

2020-07-10T21:49:30.860+0800	DEBUG	service/handler.go:179	Session read goroutine exit, SessionID=1296, UID=%!d(string=1:0a49046f-affc-496b-add6-23eceab2299e)
2020-07-10T21:49:30.860+0800	DEBUG	agent/agent.go:324	Session handle goroutine exit, SessionID=1296, UID=%!d(string=1:0a49046f-affc-496b-add6-23eceab2299e)
panic: send on closed channel

goroutine 10287 [running]:
github.com/topfreegames/pitaya/agent.(*Agent).heartbeat(0xc000694e40)
	C:/Users/Gosling/go/pkg/mod/github.com/topfreegames/[email protected]/agent/agent.go:368 +0x4b7
created by github.com/topfreegames/pitaya/agent.(*Agent).Handle
	C:/Users/Gosling/go/pkg/mod/github.com/topfreegames/[email protected]/agent/agent.go:328 +0x9e

can not configure server.ID

app default set server as:

app: cluster.NewServer(uuid.New().String(), "game", true, map[string]string{}),

but sometimes we need the server.ID is fixed

I think pitaya.Configure should be able to set sever.ID

RPC and RPCTo: can not get session from context

connector

pitaya.RPC(ctx, "room.room.messageremote", ret, msg)

room MessageRemote func

s := pitaya.GetSessionFromCtx(ctx)

panic

ERRO[1040] pitaya/dispatch: interface conversion: interface {} is nil, not *session.Session  source=pitaya

Document metrics reported by Pitaya

Pitaya reports a few different metrics, but you have to look at the code to discover the reported metrics and their meaning.

It would be nice to have the metrics documented somewhere.

More demos please!

Hello, developers.

Google lead me here, and this project seems promising. I followed every steps in the readme and I can succesfully run the demo. Since I'm new to golang I need more specific instructions than in the readme and the online doc. So please give us more basic and detailed demos.

And another question is do you have any roadmap for this project? I hope it would be a long term active project, and I'd like to see more features coming out.

Thank you guys. Keep up good work!

chat demo running error

Environment:
go 1.13.5
macos 10.15.2

I cloned the pitaya, follow the step to setup the dependancies by using make setup and cd the demo folder to run the following commands

docker-compose -f ../../testing/docker-compose.yml up -d etcd nats
go run main.go

everything is fine.

And I open the webpage http://localhost:3251/web/

I can see the username , textfield to input and button to send. But after I input the text and push the send button nothing happened.

I go back to the terminal of server, realize there is the error message:

Failed to decode message: wrong packet type source=pitaya

here is the log containing the error message

INFO[0000] all modules started!                          source=pitaya
DEBU[0060] UserCount: Time=> 2019-12-29 16:05:48.418552 -0800 PST m=+60.006227350, Count=> 0, Error=> %!q(<nil>)  source=pitaya
DEBU[0120] UserCount: Time=> 2019-12-29 16:06:48.41908 -0800 PST m=+120.006548596, Count=> 0, Error=> %!q(<nil>)  source=pitaya
DEBU[0120] type: chat, servers: map[b35b640f-5a81-4169-94e5-d9fb6414be61:0xc0002ea000]  source=pitaya
DEBU[0179] New session established: Remote=127.0.0.1:62450, LastTime=1577664467  source=pitaya
DEBU[0179] Received data on connection with len 521      source=pitaya
ERRO[0179] Failed to decode message: wrong packet type   source=pitaya
DEBU[0179] Session closed, ID=1, UID=, IP=127.0.0.1:62450  source=pitaya
DEBU[0179] Session read goroutine exit, SessionID=1, UID=%!d(string=)  source=pitaya
DEBU[0179] Session handle goroutine exit, SessionID=1, UID=%!d(string=)  source=pitaya
DEBU[0180] UserCount: Time=> 2019-12-29 16:07:48.422466 -0800 PST m=+180.009728082, Count=> 0, Error=> %!q(<nil>)  source=pitaya

Did I miss anything? I've tried the nano sample which is working.

external port doesn't work on grpc mode

There is only one grpc server starting here. So the only scenario where external port works is when grpc.port == grpc.externalport on config.

Maybe rethink if it's necessary to have internal port and external port. If it's, ensure that we can go gs.grpcSv.Serve(lis) with two different addresses for lis or we need to have two *grpc.Server on GRPCServer struct.

pitaya does not support go.mod

when i'm use v0.7.5 in go.mod

require (
	github.com/topfreegames/pitaya v0.7.5
)

some errors below:

go: finding github.com/topfreegames/pitaya v0.7.5
go: github.com/topfreegames/[email protected]: unknown revision v0.7.5
go: error loading module requirements

when i'm use latest in go.mod

require (
	github.com/topfreegames/pitaya latest
)

that may be use v0.2.1 version.

Because you created 0.7.5 as released tag, not v0.7.5。

SendPushToUsers possibly not returning error if last push was successfull

I think that SendPushToUsers on the main package may have the following problem:

If an array of N users get success on pushing the message for the last user, it will always return nil. This can lead the game to believe that the push was successful while it may have failed for one or more users. If this is intentional, I think maybe we should document it somehow.

This problem may also exist on SendKickToUsers since this one was based on the first and I didnt saw that early, and im going to fix kick asap. But for the push one, i would like know better if this is intentional or not

How to call the local service method?

How to call the local service method?
Can I hold the different services in the same server?
Example

        // hold the components
        // And use them in different service.  like this:  connector.Foo() { login.Bar() }
        connector :=&services.Connector{}
        connectorRemote := &services.ConnectorRemote{}
        login := &services.Login{}
	pitaya.Register(connector,
		component.WithName("connector"),
		component.WithNameFunc(strings.ToLower),
	)
	pitaya.RegisterRemote(connectorRemote,
		component.WithName("connectorremote"),
		component.WithNameFunc(strings.ToLower),
	)

	pitaya.Register(login,
		component.WithName("login"),
		component.WithNameFunc(strings.ToLower),
	)

Originally posted by @tutumagi in #140 (comment)

Hi, can you suport kcp ?

HI, pitaya is very good, I use it in the project. Can you suport kcp or same other Efficient udp protocol?
thank you

cannot use auth.callOpts

env:
GOARCH="amd64"
GOBIN=""
GOCACHE="/Users/admin/Library/Caches/go-build"
GOEXE=""
GOFLAGS=""
GOHOSTARCH="amd64"
GOHOSTOS="darwin"
GOOS="darwin"
GOPATH="/code"
GOPROXY=""
GORACE=""
GOROOT="/usr/local/Cellar/go/1.11.4/libexec"
GOTMPDIR=""
GOTOOLDIR="/usr/local/Cellar/go/1.11.4/libexec/pkg/tool/darwin_amd64"
GCCGO="gccgo"
CC="clang"
CXX="clang++"
CGO_ENABLED="1"
GOMOD=""
CGO_CFLAGS="-g -O2"
CGO_CPPFLAGS=""
CGO_CXXFLAGS="-g -O2"
CGO_FFLAGS="-g -O2"
CGO_LDFLAGS="-g -O2"
PKG_CONFIG="pkg-config"
GOGCCFLAGS="-fPIC -m64 -pthread -fno-caret-diagnostics -Qunused-arguments -fmessage-length=0 -fdebug-prefix-map=/var/folders/rs/g895d51j2qjbkq2l0zxm7bym0000gn/T/go-build134005452=/tmp/go-build -gno-record-gcc-switches -fno-common"

run make run-cluster-grpc-example-connector, show the error down:
make: *** No rule to make target `run-cluster-grpc-example-connector'. Stop.
MacBook-Pro:testing admin$ cd ../
Book-Pro:examples admin$ cd ../
Book-Pro:pitaya admin$ make run-cluster-grpc-example-connector

github.com/nats-io/nkeys

../../../../../nats-io/nkeys/strkey.go:92:17: undefined: ed25519.SeedSize

github.com/coreos/etcd/clientv3

../../../../../coreos/etcd/clientv3/auth.go:116:72: cannot use auth.callOpts (type []"github.com/coreos/etcd/vendor/google.golang.org/grpc".CallOption) as type []"go.etcd.io/etcd/vendor/google.golang.org/grpc".CallOption in argument to auth.remote.AuthEnable
../../../../../coreos/etcd/clientv3/auth.go:121:74: cannot use auth.callOpts (type []"github.com/coreos/etcd/vendor/google.golang.org/grpc".CallOption) as type []"go.etcd.io/etcd/vendor/google.golang.org/grpc".CallOption in argument to auth.remote.AuthDisable
../../../../../coreos/etcd/clientv3/auth.go:126:100: cannot use auth.callOpts (type []"github.com/coreos/etcd/vendor/google.golang.org/grpc".CallOption) as type []"go.etcd.io/etcd/vendor/google.golang.org/grpc".CallOption in argument to auth.remote.UserAdd
../../../../../coreos/etcd/clientv3/auth.go:131:86: cannot use auth.callOpts (type []"github.com/coreos/etcd/vendor/google.golang.org/grpc".CallOption) as type []"go.etcd.io/etcd/vendor/google.golang.org/grpc".CallOption in argument to auth.remote.UserDelete
../../../../../coreos/etcd/clientv3/auth.go:136:122: cannot use auth.callOpts (type []"github.com/coreos/etcd/vendor/google.golang.org/grpc".CallOption) as type []"go.etcd.io/etcd/vendor/google.golang.org/grpc".CallOption in argument to auth.remote.UserChangePassword
../../../../../coreos/etcd/clientv3/auth.go:141:104: cannot use auth.callOpts (type []"github.com/coreos/etcd/vendor/google.golang.org/grpc".CallOption) as type []"go.etcd.io/etcd/vendor/google.golang.org/grpc".CallOption in argument to auth.remote.UserGrantRole
../../../../../coreos/etcd/clientv3/auth.go:146:80: cannot use auth.callOpts (type []"github.com/coreos/etcd/vendor/google.golang.org/grpc".CallOption) as type []"go.etcd.io/etcd/vendor/google.golang.org/grpc".CallOption in argument to auth.remote.UserGet
../../../../../coreos/etcd/clientv3/auth.go:151:72: cannot use auth.callOpts (type []"github.com/coreos/etcd/vendor/google.golang.org/grpc".CallOption) as type []"go.etcd.io/etcd/vendor/google.golang.org/grpc".CallOption in argument to auth.remote.UserList
../../../../../coreos/etcd/clientv3/auth.go:156:106: cannot use auth.callOpts (type []"github.com/coreos/etcd/vendor/google.golang.org/grpc".CallOption) as type []"go.etcd.io/etcd/vendor/google.golang.org/grpc".CallOption in argument to auth.remote.UserRevokeRole
../../../../../coreos/etcd/clientv3/auth.go:161:80: cannot use auth.callOpts (type []"github.com/coreos/etcd/vendor/google.golang.org/grpc".CallOption) as type []"go.etcd.io/etcd/vendor/google.golang.org/grpc".CallOption in argument to auth.remote.RoleAdd
../../../../../coreos/etcd/clientv3/auth.go:161:80: too many errors

github.com/topfreegames/pitaya/protos

../../../protos/bind.pb.go:59:29: undefined: "github.com/gogo/protobuf/proto".InternalMessageInfo
../../../protos/doc.pb.go:58:25: undefined: "github.com/gogo/protobuf/proto".InternalMessageInfo
../../../protos/docmsg.pb.go:58:28: undefined: "github.com/gogo/protobuf/proto".InternalMessageInfo
../../../protos/error.pb.go:60:27: undefined: "github.com/gogo/protobuf/proto".InternalMessageInfo
../../../protos/error.pb.go:85:2: undefined: "github.com/gogo/protobuf/proto".RegisterMapType
../../../protos/kick.pb.go:58:29: undefined: "github.com/gogo/protobuf/proto".InternalMessageInfo
../../../protos/kick.pb.go:102:32: undefined: "github.com/gogo/protobuf/proto".InternalMessageInfo
../../../protos/msg.pb.go:91:25: undefined: "github.com/gogo/protobuf/proto".InternalMessageInfo
../../../protos/protodescriptor.pb.go:59:37: undefined: "github.com/gogo/protobuf/proto".InternalMessageInfo
../../../protos/protodescriptor.pb.go:103:31: undefined: "github.com/gogo/protobuf/proto".InternalMessageInfo
../../../protos/protodescriptor.pb.go:103:31: too many errors
make: *** [run-cluster-grpc-example-connector] Error 2

Here are some questions about packet loss

func (c *Client) readPackets(buf *bytes.Buffer) ([]*packet.Packet, error) {
// listen for sv messages
data := make([]byte, 1024)
n := len(data)
var err error

for n == len(data) {
	n, err = c.conn.Read(data)
	if err != nil {
		return nil, err
	}
	buf.Write(data[:n])
}
packets, err := c.packetDecoder.Decode(buf.Bytes())
if err != nil {
	logger.Log.Errorf("error decoding packet from server: %s", err.Error())
}
totalProcessed := 0
for _, p := range packets {
	totalProcessed += codec.HeadLength + p.Length
}
buf.Next(totalProcessed)

return packets, nil

}

If the read byte array is a complete packet and an incomplete packet, it will cause the data of the incomplete packet to be lost. What do you think?

Why sometimes receive the message will have garbled and sticky packet problem?

I used the chat example provided by Pitaya for testing, and found that sometimes there were problems of sticky packages and garbled codes in the messages I received.

onMembers
{"members":[]}
request room.join succesed.
2.无限期等待中...
onNewUser
{"content":"New user: 98"}
onMessage
{"name":"guest1552192965717","content":"sss"}_pi�
onMessage
{"name":"guest1552192965717","content":"大家好"}
onMessage
{"name":"曹江华","content":"我们fdsf 震"}
onMessage
{"name":"曹江华","content":"无可奈何花落去"}
onMessage
{"name":"曹江华","content":"工"}
onMessage
{"name":"曹江华","content":"需要 无可奈何1534!@#¥#@"}","content":"��
onMessage
{"name":"曹江华","content":"fsaf11城无可奈何花落去 "}�
onMessage
{"name":"曹江华","content":"dddddddd"}��花��

Above are some examples of the messages I received.

onMessage
{"name":"guest1552192965717","content":"sss"}_pi�
onMessage
{"name":"曹江华","content":"需要 无可奈何1534!@#¥#@"}","content":"��
onMessage
{"name":"曹江华","content":"dddddddd"}��花��

The test code for my Java client to receive messages is:

package dog.tale.pitaya;

import org.bytedeco.javacpp.*;

public class PitayaTest {
    static {
        //System.load("/Users/arden/data/repository/tale/PitayaClientJava/lib/libpitaya-mac.bundle");
        System.loadLibrary("pitaya-mac");
        System.loadLibrary("jniPitaya");
    }

    public static void main(String...args) {
        Object lock = new Object();

        try {


            Pitaya.pc_lib_set_default_log_level(Pitaya.PC_LOG_DEBUG);

            Pitaya.pc_lib_client_info_t clientInfo = new Pitaya.pc_lib_client_info_t();

            Pitaya.pc_lib_init((Pitaya.Pc_log_int_BytePointer) null, null, null, null, clientInfo);

            Pitaya.pc_client_config_t config = new Pitaya.pc_client_config_t();
            config.transport_name(Pitaya.PC_TR_NAME_UV_TCP);
            config.enable_reconn(1);
            config.conn_timeout(120);
            config.reconn_max_retry(Pitaya.PC_ALWAYS_RETRY);
            config.reconn_delay(30);


            Pitaya.pc_client_init_result_t result = Pitaya.pc_client_init(null, config);
            Pitaya.pc_client_t client = result.client();

            Pitaya.pc_client_connect(client, "tujiao.co", 3252, null);

            Pitaya.pc_client_add_ev_handler(client, new Pitaya.pc_event_cb_t() {
                @Override
                public void call(Pitaya.pc_client_t client, int ev_type, Pointer ex_data, BytePointer arg1, BytePointer arg2) {
                    System.out.println("aaa: " + ev_type);
                    if (ev_type == Pitaya.PC_EV_CONNECTED) {
                        Pitaya.pc_string_request_with_timeout(client, "room.join", null, null, 15, new Pitaya.pc_request_success_cb_t() {
                            @Override
                            public void call(Pitaya.pc_request_t req, Pitaya.pc_buf_t resp) {
                                System.out.println("request room.join succesed.");
                            }
                        }, new Pitaya.pc_request_error_cb_t() {
                            @Override
                            public void call(Pitaya.pc_request_t req, Pitaya.pc_error_t error) {

                            }
                        });

                        Pitaya.pc_string_notify_with_timeout(client, "room.message", "{\"name\":\"arden\", \"content\":\"welcome arden(他乐好棒)\"}", null, 15, new Pitaya.pc_notify_error_cb_t() {
                            @Override
                            public void call(Pitaya.pc_notify_t req, Pitaya.pc_error_t error) {
                                System.out.println(error);
                            }
                        });
                    }
                }
            }, null, null);


            Pitaya.pc_string_request_with_timeout(client, "room.join", null, null, 15, new Pitaya.pc_request_success_cb_t() {
                @Override
                public void call(Pitaya.pc_request_t req, Pitaya.pc_buf_t resp) {
                    System.out.println("request room.join succesed.");
                }
            }, new Pitaya.pc_request_error_cb_t() {
                @Override
                public void call(Pitaya.pc_request_t req, Pitaya.pc_error_t error) {

                }
            });

            Pitaya.pc_string_notify_with_timeout(client, "room.message", "{\"name\":\"arden\", \"content\":\"welcome arden(他乐好棒Arden)\"}", null, 15, new Pitaya.pc_notify_error_cb_t() {
                @Override
                public void call(Pitaya.pc_notify_t req, Pitaya.pc_error_t error) {
                    System.out.println(error);
                }
            });

            Pitaya.pc_client_set_push_handler(client, new Pitaya.pc_push_handler_cb_t() {
                @Override
                public void call(Pitaya.pc_client_t client, BytePointer route, Pitaya.pc_buf_t payload) {
                    System.out.println(route.getString());
                    System.out.println(payload.base().getString());
                }
            });

            try {
                Thread.sleep(5000);
            } catch (Exception e) {

            }

            while (true) {
                synchronized (lock) {
                    System.out.println("2.无限期等待中...");
                    lock.wait();

                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

}

When using GRPC, it's possible that we never connect to another server

https://github.com/topfreegames/pitaya/blob/master/cluster/grpc_rpc_client.go#L234-L238

	conn, err := grpc.DialContext(ctxT, address, grpc.WithInsecure())
	if err != nil {
		logger.Log.Errorf("unable to connect to server %s at %s: %v", sv.ID, address, err)
		return
	}

This piece of code may lead us to having a known server that we never connect to, maybe we should remove the return and leave GRPC trying to reconnect and if the server is really messed up, eventually it will be removed and deleted from the local sd storage

question about the packet decoder

packets, err := h.decoder.Decode(buf[:n])

If a client sends a packet of 1500 bytes, but the underlying connection only read 1000 bytes for the first read attempt and for the second attempt it read the remaining 500 bytes, which I think is possible.

The referring code will cause decode error because it doesnot have enough bytes and it will discard the first 1000 bytes. how to resolve this case ?

Is it suitable for an MMO Game?

I am writing an MMO game server with golang for five months already. Then I find the pitaya repo. And It's very good.
But an MMO game often has status synchronization with surrounding players.
I want to use the proto design and RPC design which used in the pitaya repo.
But I'm not sure it's suitable for an MMO Game.
Anyone can give me suggestions?

Pitaya crashes due to multiple closes on channel

Different parts of agent/agent.go call agent.Close(), this can lead to a panic in Pitaya with the proper timing.

A stacktrace of this problem:

goroutine 710136 [running]:
.../vendor/github.com/topfreegames/pitaya/agent.(*Agent).Close(0xc002332480, 0xe803e0, 0xc005d91dd0)
	.../vendor/github.com/topfreegames/pitaya/agent/agent.go:209 +0x22d
.../vendor/github.com/topfreegames/pitaya/session.(*Session).Close(0xc002332540)
	.../vendor/github.com/topfreegames/pitaya/session/session.go:343 +0x2ec
.../vendor/github.com/topfreegames/pitaya/service.(*HandlerService).Handle.func1(0xc002332480)
	.../vendor/github.com/topfreegames/pitaya/service/handler.go:176 +0x32
.../vendor/github.com/topfreegames/pitaya/service.(*HandlerService).Handle(0xc0000c41e0, 0x11610a0, 0xc00109dc00)
	.../vendor/github.com/topfreegames/pitaya/service/handler.go:186 +0x778
created by git.topfreegames.com/topfreegames/sniper3d-backend/vendor/github.com/topfreegames/pitaya.listen.func1
	.../vendor/github.com/topfreegames/pitaya/app.go:460 +0x89

nano authors deserve credit

Hi I see you guys just copy pasted nano and started building on it without giving the original author any credit I think nano authors deserve at least that much.

RPC retry strategy

RPC Clients must have some kind of configurable strategy for retrying RPC's, note that this can be dangerous if the operation being retried make changes to the database and is not idempotent

client does not seem to work

1, start pitaya:

d059578

$ git clone https://github.com/topfreegames/pitaya.git
$ go run pitaya/examples/demo/chat/main.go
......
INFO[0000] all modules started!                          source=pitaya

2.1, pitaya-cli

$ go get -u github.com/topfreegames/pitaya-cli
$ pitaya-cli
>>> connect 127.0.0.1:3250
Using json client
Failed to connect!
Error: tls: first record does not look like a TLS handshake

2.2, pitaya-cli

topfreegames/pitaya-cli@50f16b5

$ git clone https://github.com/topfreegames/pitaya-cli.git

modify

func connect(addr string) error {
	if err := pClient.ConnectTo(addr); err != nil {
		return err
	}

	return nil
}
$ go run pitaya-cli/main.go
>>> connect 127.0.0.1:3250
Using json client
ERRO[0001] error decoding packet from server: wrong packet type
panic: runtime error: index out of range

goroutine 1 [running]:
/pitaya/client.(*Client).handleHandshakeResponse(0xc000225b00, 0x0, 0x0)
/[email protected]/client/client.go:147 +0x5aa
/pitaya/client.(*Client).handleHandshake(0xc000225b00, 0xa, 0xc0001e35c0)
/[email protected]/client/client.go:375 +0x4c
/pitaya/client.(*Client).ConnectTo(0xc000225b00, 0xc0001a2b20, 0xe, 0x0, 0xc000225b00)
/[email protected]/client/client.go:361 +0x11f

Nats-io timeout

Summary

One game are having several issues caused by network instabilities and Nats-IO.

When we have a disruption in the communication between Nats and connector/game/metagame. It can't recover from that error. Even restarting the pods of pitaya doesn't solve the "nats timeout" error. We had to restart nats and pitaya together to solve the issue.

Logs

Here are a few logs from connector

{
      "server": "connector",
      "level": "error",
      "version": "0.1.0",
      "msg": "Failed to process remote: nats: timeout",
      "source": "game",
      "time": "2020-03-16T03:48:37Z"
    }

In our meta-game:

{ 
      "source": "game",
      "time": "2020-03-14T17:58:21Z",
      "method": "playerHandler.Authenticate",
      "version": "0.1.0",
      "msg": "nats: timeout",
      "methodName": "bindSession",
      "server": "metagame",
      "level": "error"
 }
{
      "server": "metagame",
      "level": "error",
      "version": "0.1.0",
      "msg": "error while trying to push session to front: nats: timeout",
      "source": "game",
      "time": "2020-03-14T17:58:23Z"
    }

How to reproduce

Currently we couldn't reproduce the error. But it happened a few times:

When we did a reload on the network plugin. That interrupted some connections with nats and started the errors

When we got a slow consumer in Nats and some games restarted.

Related issues

I found this issue nats-io/stan.js#101

Versions

Nats: 1.1.0
Etcd: v3.3.10

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.