nano

package module
v0.4.5 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jan 1, 2020 License: MIT Imports: 29 Imported by: 0

README

Nano Build Status GoDoc Go Report Card MIT licensed

Nano is an easy to use, fast, lightweight game server networking library for Go. It provides a core network architecture and a series of tools and libraries that can help developers eliminate boring duplicate work for common underlying logic. The goal of nano is to improve development efficiency by eliminating the need to spend time on repetitious network related programming.

Nano was designed for server-side applications like real-time games, social games, mobile games, etc of all sizes.

How to build a system with Nano

What does a Nano application look like?

The simplest "github.com/jmesyan/nano" application as shown in the following figure, you can make powerful applications by combining different components.

Application

In fact, the nano application is a collection of  Component , and a component is a bundle of  Handler, once you register a component to nano, nano will register all methods that can be converted to Handler to nano service container. Service was accessed by Component.Handler, and the handler will be called while client request. The handler will receive two parameters while handling a message:

  • *session.Session: corresponding a client that apply this request or notify.
  • *protocol.FooBar: the payload of the request.

While you had processed your logic, you can response or push message to the client by session.Response(payload) and session.Push('eventName', payload), or returns error when some unexpected data received.

How to build distributed system with Nano

Nano has no built-in distributed system components, but you can easily implement it with gRPC and smux . Here we take grpc as an example.

  • First of all, you need to define a remote component
type RemoteComponent struct {
	rpcClients []*grpc.ClientConn
}
  • Second, fetch all grpc servers infomation from services like etcd or consul in nano lifetime hooks
type ServerInfo struct {
	Host string `json:"host"`
	Port int    `json:"port"`
}

// lifetime callback
func (r *RemoteComponent) Init() {
	// fetch server list from etcd
	resp, err := http.Get("http://your_etcd_server/backend/server_list/area/10023")
	if err != nil {
		panic(err)
	}
	
	servers := []ServerInfo{}
	if err := json.NewDecoder(resp.Body).Decode(&servers); err != nil {
		panic(err)
	}
	
	for i := range servers {
		server := servers[i]
		client, err := grpc.Dial(fmt.Sprintf("%s:%d", server.Host, server.Post), options)
		if err != nil {
			panic(err)
		}
		r.rpcClients = append(r.rpcClients, client)
	}
}

func (r *RemoteComponent) client(s *session.Session) *grpc.ClientConn {
	// load balance
	return r.rpcClients[s.UID() % len(s.rpcClients)]
}

// Your handler, accessed by:
// nanoClient.Request("RemoteComponent.DemoHandler", &pb.DemoMsg{/*...*/})
func (r *RemoteComponent) DemoHandler(s *session.Session, msg *pb.DemoMsg) error {
	client := r.client(s)
	// do something with client
	// ....
	// ...
	return nil
}

The Nano will remain simple, but you can perform any operations in the component and get the desired goals. You can startup a group of Nano application as agent to dispatch message to backend servers.

How to execute the asynchronous task
func (manager *PlayerManager) Login(s *session.Session, msg *ReqPlayerLogin) error {
    var onDBResult = func(player *Player) {
        manager.players = append(manager.players, player)
        s.Push("PlayerSystem.LoginSuccess", &ResPlayerLogin)
    }
    
    // run slow task in new gorontine
    go func() {
        player, err := db.QueryPlayer(msg.PlayerId) // ignore error in demo
        // handle result in main logical gorontine
        nano.Invoke(func(){ onDBResult(player) })
    }
    return nil
}

Documents

Resources

Community

Successful cases

Go version

> go1.8

Installation

go get github.com/lonnng/nano

# dependencies
go get -u github.com/golang/protobuf
go get -u github.com/gorilla/websocket

Benchmark

# Case:   PingPong
# OS:     Windows 10
# Device: i5-6500 3.2GHz 4 Core/1000-Concurrent   => IOPS 11W(Average)
# Other:  ...

cd $GOPATH/src/github.com/lonnng/nano/benchmark/io
go test -v -tags "benchmark"

License

MIT License

Documentation

Index

Constants

This section is empty.

Variables

View Source
var (
	// ErrBrokenPipe represents the low-level connection has broken.
	ErrBrokenPipe = errors.New("broken low-level pipe")
	// ErrBufferExceed indicates that the current session buffer is full and
	// can not receive more data.
	ErrBufferExceed = errors.New("session send buffer exceed")
)
View Source
var (
	ResponseSuccess = []byte("SUCCESS")
	ResponseFail    = []byte("FAIL")
)
View Source
var (
	ErrSessionOnNotify      = errors.New("current session working on notify mode")
	ErrCloseClosedConnector = errors.New("close closed connector")
	ErrClosedConnector      = errors.New("connector closed")
	ErrMemberNotFound       = errors.New("member not found in the connector")
	ErrCloseClosedSession   = errors.New("close closed session")
	ErrSessionDuplication   = errors.New("session has existed in the current connector")
)

Errors that could be occurred during message handling.

View Source
var VERSION = "0.0.1"

VERSION returns current nano version

Functions

func EnableDebug

func EnableDebug()

EnableDebug let 'nano' to run under debug mode.

func Invoke

func Invoke(fn func())

Invoke invokes function in main logic goroutine

func Listen

func Listen(addr string, opts ...Option)

Listen listens on the TCP network address addr and then calls Serve with handler to handle requests on incoming connections.

func ListenWS

func ListenWS(addr string, opts ...Option)

ListenWS listens on the TCP network address addr and then upgrades the HTTP server connection to the WebSocket protocol to handle requests on incoming connections.

func Register

func Register(c component.Component, options ...component.Option)

Register register a component with options

func SetCheckOriginFunc

func SetCheckOriginFunc(fn func(*http.Request) bool)

SetCheckOriginFunc set the function that check `Origin` in http headers

func SetDictionary

func SetDictionary(dict map[string]uint16)

SetDictionary set routes map, TODO(warning): set dictionary in runtime would be a dangerous operation!!!!!!

func SetHeartbeatInterval

func SetHeartbeatInterval(d time.Duration)

SetHeartbeatInterval set heartbeat time interval

func SetLogger

func SetLogger(l Logger)

SetLogger rewrites the default logger

func SetSerializer

func SetSerializer(seri serialize.Serializer)

SetSerializer customize application serializer, which automatically Marshal and UnMarshal handler payload

func SetWSPath

func SetWSPath(path string)

func Shutdown

func Shutdown()

Shutdown send a signal to let 'nano' shutdown itself.

Types

type ApiManager added in v0.4.3

type ApiManager struct {
	// contains filtered or unexported fields
}
var (
	ApiManagerHandler *ApiManager
	DefautApiAddrs    = "127.0.0.1:20066"
)

func NewApiManager added in v0.4.3

func NewApiManager(opts ...ApiManagerOpts) *ApiManager

func (*ApiManager) AfterInit added in v0.4.3

func (am *ApiManager) AfterInit()

func (*ApiManager) BeforeShutdown added in v0.4.3

func (am *ApiManager) BeforeShutdown()

func (*ApiManager) Init added in v0.4.3

func (am *ApiManager) Init()

func (*ApiManager) Shutdown added in v0.4.3

func (am *ApiManager) Shutdown()

type ApiManagerOpts added in v0.4.3

type ApiManagerOpts func(am *ApiManager)

func WithApiAddrs added in v0.4.3

func WithApiAddrs(addrs string) ApiManagerOpts

type ApiServer added in v0.4.3

type ApiServer struct {
	ReadEndStr []byte
	// contains filtered or unexported fields
}

func NewApiServer added in v0.4.3

func NewApiServer(conn net.Conn, opts ...ApiServerOpts) *ApiServer

func (*ApiServer) SendObj added in v0.4.3

func (as *ApiServer) SendObj(data map[string]interface{})

type ApiServerOpts added in v0.4.3

type ApiServerOpts func(as *ApiServer)

type GameManager added in v0.4.3

type GameManager struct {
	Serversort   map[string]*game.GameServer
	Alltablesort map[string]*game.GameTable
	// contains filtered or unexported fields
}
var (
	GMHander         *GameManager
	DefautListenGame = "0.0.0.0:20572"
)

func NewGameManager added in v0.4.3

func NewGameManager(opts ...GameManagerOpts) *GameManager

func (*GameManager) AfterInit added in v0.4.3

func (g *GameManager) AfterInit()

func (*GameManager) BeforeShutdown added in v0.4.3

func (g *GameManager) BeforeShutdown()

func (*GameManager) EnterToGame added in v0.4.3

func (g *GameManager) EnterToGame(uid int, serverdata *game.ServerData, cb func(result *game.ControlUserEnterroom), isretry bool) error

func (*GameManager) GetCenterServerByBalance added in v0.4.3

func (g *GameManager) GetCenterServerByBalance(ngid int) *game.GameServer

func (*GameManager) GetCenterServers added in v0.4.3

func (g *GameManager) GetCenterServers(ngid int, ngc func(s *game.GameServer) bool) map[string]*game.GameServer

func (*GameManager) GetGameListState added in v0.4.3

func (g *GameManager) GetGameListState() map[string]interface{}

func (*GameManager) GetServerByGSID added in v0.4.3

func (g *GameManager) GetServerByGSID(gsid string) *game.GameServer

func (*GameManager) GetServerSort added in v0.4.3

func (g *GameManager) GetServerSort() map[string]*game.GameServer

func (*GameManager) GetTable added in v0.4.3

func (g *GameManager) GetTable(gsidtid string) *game.GameTable

func (*GameManager) HandleMsg added in v0.4.4

func (g *GameManager) HandleMsg(msg *nats.Msg)

func (*GameManager) Init added in v0.4.3

func (g *GameManager) Init()

func (*GameManager) InitNats added in v0.4.4

func (g *GameManager) InitNats()

func (*GameManager) ProcessServer added in v0.4.3

func (g *GameManager) ProcessServer(route string, body reflect.Value)

func (*GameManager) ReconnectToGame added in v0.4.3

func (g *GameManager) ReconnectToGame(uid int, connectServerdata *game.ServerData) (*game.ServerData, error)

func (*GameManager) RegisterServer added in v0.4.3

func (g *GameManager) RegisterServer(gsid string, server *game.GameServer)

func (*GameManager) RegisterTable added in v0.4.3

func (g *GameManager) RegisterTable(gsidtid string, table *game.GameTable)

func (*GameManager) RemoveServerByGSID added in v0.4.3

func (g *GameManager) RemoveServerByGSID(gsid string)

func (*GameManager) ServerMaintence added in v0.4.4

func (g *GameManager) ServerMaintence()

func (*GameManager) Shutdown added in v0.4.3

func (g *GameManager) Shutdown()

type GameManagerOpts added in v0.4.3

type GameManagerOpts func(g *GameManager)

func WithGameManagerAddrs added in v0.4.3

func WithGameManagerAddrs(addrs string) GameManagerOpts

type Logger

type Logger interface {
	Println(v ...interface{})
	Fatal(v ...interface{})
	Printf(format string, v ...interface{})
}

Logger represents the log interface

type Message

type Message struct {
	*message.Message
}

type Option

type Option func(*options)

func WithPipeline

func WithPipeline(pipeline Pipeline) Option

type Pipeline

type Pipeline interface {
	Outbound() PipelineChannel
	Inbound() PipelineChannel
}

func NewPipeline

func NewPipeline() Pipeline

type PipelineChannel

type PipelineChannel interface {
	PushFront(h PipelineFunc)
	PushBack(h PipelineFunc)
	Process(s *session.Session, msg Message) error
}

type PipelineFunc

type PipelineFunc func(s *session.Session, msg Message) error

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL