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 "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

Expand ▾ Collapse ▴

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 (
	ErrSessionOnNotify    = errors.New("current session working on notify mode")
	ErrCloseClosedGroup   = errors.New("close closed group")
	ErrClosedGroup        = errors.New("group closed")
	ErrMemberNotFound     = errors.New("member not found in the group")
	ErrCloseClosedSession = errors.New("close closed session")
	ErrSessionDuplication = errors.New("session has existed in the current group")
)

    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 SetTimerPrecision

                          func SetTimerPrecision(precision time.Duration)

                            SetTimerPrecision set the ticker precision, and time precision can not less than a Millisecond, and can not change after application running. The default precision is time.Second

                            func SetWSPath

                            func SetWSPath(path string)

                            func Shutdown

                            func Shutdown()

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

                              Types

                              type Group

                              type Group struct {
                              	// contains filtered or unexported fields
                              }

                                Group represents a session group which used to manage a number of sessions, data send to the group will send to all session in it.

                                func NewGroup

                                func NewGroup(n string) *Group

                                  NewGroup returns a new group instance

                                  func (*Group) Add

                                  func (c *Group) Add(session *session.Session) error

                                    Add add session to group

                                    func (*Group) Broadcast

                                    func (c *Group) Broadcast(route string, v interface{}) error

                                      Broadcast push the message(s) to all members

                                      func (*Group) Close

                                      func (c *Group) Close() error

                                        Close destroy group, which will release all resource in the group

                                        func (*Group) Contains

                                        func (c *Group) Contains(uid int64) bool

                                          Contains check whether a UID is contained in current group or not

                                          func (*Group) Count

                                          func (c *Group) Count() int

                                            Count get current member amount in the group

                                            func (*Group) Leave

                                            func (c *Group) Leave(s *session.Session) error

                                              Leave remove specified UID related session from group

                                              func (*Group) LeaveAll

                                              func (c *Group) LeaveAll() error

                                                LeaveAll clear all sessions in the group

                                                func (*Group) Member

                                                func (c *Group) Member(uid int64) (*session.Session, error)

                                                  Member returns specified UID's session

                                                  func (*Group) Members

                                                  func (c *Group) Members() []int64

                                                    Members returns all member's UID in current group

                                                    func (*Group) Multicast

                                                    func (c *Group) Multicast(route string, v interface{}, filter SessionFilter) error

                                                      Multicast push the message to the filtered clients

                                                      type Logger

                                                      type Logger interface {
                                                      	Println(v ...interface{})
                                                      	Fatal(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

                                                        type SessionFilter

                                                        type SessionFilter func(*session.Session) bool

                                                          SessionFilter represents a filter which was used to filter session when Multicast, the session will receive the message while filter returns true.

                                                          type Timer

                                                          type Timer struct {
                                                          	// contains filtered or unexported fields
                                                          }

                                                            Timer represents a cron job

                                                            func NewAfterTimer

                                                            func NewAfterTimer(duration time.Duration, fn TimerFunc) *Timer

                                                              NewAfterTimer returns a new Timer containing a function that will be called after duration that specified by the duration argument. The duration d must be greater than zero; if not, NewAfterTimer will panic. Stop the timer to release associated resources.

                                                              func NewCondTimer

                                                              func NewCondTimer(condition TimerCondition, fn TimerFunc) *Timer

                                                                NewCondTimer returns a new Timer containing a function that will be called when condition satisfied that specified by the condition argument. The duration d must be greater than zero; if not, NewCondTimer will panic. Stop the timer to release associated resources.

                                                                func NewCountTimer

                                                                func NewCountTimer(interval time.Duration, count int, fn TimerFunc) *Timer

                                                                  NewCountTimer returns a new Timer containing a function that will be called with a period specified by the duration argument. After count times, timer will be stopped automatically, It adjusts the intervals for slow receivers. The duration d must be greater than zero; if not, NewCountTimer will panic. Stop the timer to release associated resources.

                                                                  func NewTimer

                                                                  func NewTimer(interval time.Duration, fn TimerFunc) *Timer

                                                                    NewTimer returns a new Timer containing a function that will be called with a period specified by the duration argument. It adjusts the intervals for slow receivers. The duration d must be greater than zero; if not, NewTimer will panic. Stop the timer to release associated resources.

                                                                    func (*Timer) ID

                                                                    func (t *Timer) ID() int64

                                                                      ID returns id of current timer

                                                                      func (*Timer) Stop

                                                                      func (t *Timer) Stop()

                                                                        Stop turns off a timer. After Stop, fn will not be called forever

                                                                        type TimerCondition

                                                                        type TimerCondition interface {
                                                                        	Check(now time.Time) bool
                                                                        }

                                                                          TimerCondition represents a checker that returns true when cron job needs to execute

                                                                          type TimerFunc

                                                                          type TimerFunc func()

                                                                            TimerFunc represents a function which will be called periodically in main logic gorontine.