Pitaya API

Handlers

Handlers are one of the core features of Pitaya, they are the entities responsible for receiving the requests from the clients and handling them, returning the response if the method is a request handler, or nothing, if the method is a notify handler.

Signature

Handlers must be public methods of the struct and have a signature following:

Arguments

  • context.Context: the context of the request, which contains the client’s session.
  • pointer or []byte: the payload of the request (optional).

Notify handlers return nothing, while request handlers must return:

  • pointer or []byte: the response payload
  • error: an error variable

Registering handlers

Handlers must be explicitly registered by the application by calling a pitaya app’s Register with a instance of the handler component. The handler’s name can be defined by calling pitaya/component.WithName("handlerName") and the methods can be renamed by using pitaya/component.WithNameFunc(func(string) string).

The clients can call the handler by calling serverType.handlerName.methodName.

Routing messages

Messages are forwarded by pitaya to the appropriate server type, and custom routers can be added to the application by calling a pitaya app’s AddRoute, it expects two arguments:

  • serverType: the server type of the target requests to be routed
  • routingFunction: the routing function with the signature func(session.Session, *route.Route, []byte, map[string]*cluster.Server) (*cluster.Server, error), it receives the user’s session, the route being requested, the message and the map of valid servers of the given type, the key being the servers’ ids

The server will then use the routing function when routing requests to the given server type.

Lifecycle Methods

Handlers can optionally implement the following lifecycle methods:

  • Init() - Called by Pitaya when initializing the application
  • AfterInit() - Called by Pitaya after initializing the application
  • BeforeShutdown() - Called by Pitaya when shutting down components, but before calling shutdown
  • Shutdown() - Called by Pitaya after the start of shutdown

Handler example

Below is a very barebones example of a handler definition, for a complete working example, check the cluster demo.

import (
  "github.com/topfreegames/pitaya"
  "github.com/topfreegames/pitaya/component"
)

type Handler struct {
  component.Base
}

type UserRequestMessage struct {
  Name    string `json:"name"`
  Content string `json:"content"`
}

type UserResponseMessage {
}

type UserPushMessage{
  Command string `json:"cmd"`
}

// Init runs on service initialization (not required to be defined)
func (h *Handler) Init() {}

// AfterInit runs after initialization (not required to be defined)
func (h *Handler) AfterInit() {}

// TestRequest can be called by the client by calling <servertype>.testhandler.testrequest
func (h *Handler) TestRequest(ctx context.Context, msg *UserRequestMessage) (*UserResponseMessage, error) {
  return &UserResponseMessage{}, nil
}

func (h *Handler) TestPush(ctx context.Context, msg *UserPushMessage) {
}

func main() {
  builder := pitaya.NewDefaultBuilder()
  ...
  app := builder.Build()

  app.Register(
    &Handler{}, // struct to register as handler
    component.WithName("testhandler"), // name of the handler, used by the clients
    component.WithNameFunc(strings.ToLower), // naming conversion scheme to be used by the clients
  )
  ...
  app.Start()
}

Remotes

Remotes are one of the core features of Pitaya, they are the entities responsible for receiving the RPCs from other Pitaya servers.

Signature

Remotes must be public methods of the struct and have a signature following:

Arguments

  • context.Context: the context of the request.
  • proto.Message: the payload of the request (optional).

Remote methods must return:

  • proto.Message: the response payload in protobuf format
  • error: an error variable

Registering remotes

Remotes must be explicitly registered by the application by calling a pitaya app’s RegisterRemote with a instance of the remote component. The remote’s name can be defined by calling pitaya/component.WithName("remoteName") and the methods can be renamed by using pitaya/component.WithNameFunc(func(string) string).

The servers can call the remote by calling serverType.remoteName.methodName.

RPC calls

There are two options when sending RPCs between servers:

  • Specify only server type: In this case Pitaya will select one of the available servers at random
  • Specify server type and ID: In this scenario Pitaya will send the RPC to the specified server

Lifecycle Methods

Remotes can optionally implement the following lifecycle methods:

  • Init() - Called by Pitaya when initializing the application
  • AfterInit() - Called by Pitaya after initializing the application
  • BeforeShutdown() - Called by Pitaya when shutting down components, but before calling shutdown
  • Shutdown() - Called by Pitaya after the start of shutdown

Remote example

For a complete working example, check the cluster demo.