diff --git a/README.md b/README.md index 2228a9e7..696a903f 100644 --- a/README.md +++ b/README.md @@ -18,16 +18,77 @@ 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. -## Installation +## How to build a system with `Nano` -```shell -go get github.com/lonnng/nano +#### What does a `Nano` application look like? -# dependencies -go get -u github.com/golang/protobuf -go get -u github.com/gorilla/websocket +A `nano` application can be simply demostrated as below figure. + +![Application](./application.png) + +In fact, the `nano` application is a collection of [Component ](./docs/get_started.md#component) , and a component is a bundle of [Handler](./docs/get_started.md#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. While handling a message, the handler will receive two arguments, session corresponding a client and a message is the payload of this request that unmarshals by nano automatically. + +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 +```go +type RemoteComponent struct { + rpcClients []*grpc.ClientConn +} +``` + +- Second, fetch all grpc servers infomation from services like `etcd` or `consul` in `nano` lifetime callback +```go +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") + 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. + ## Documents - English @@ -37,7 +98,7 @@ go get -u github.com/gorilla/websocket + [Design patterns](./docs/design_patterns.md) + [API Reference(Server)](https://godoc.org/github.com/lonnng/nano) + [How to integrate `Lua` into `Nano` component(incomplete)](.) - + - 简体中文 + [如何构建你的第一个nano应用](./docs/get_started_zh_CN.md) + [路由压缩](./docs/route_compression_zh_CN.md) @@ -61,6 +122,16 @@ go get -u github.com/gorilla/websocket - [Implement a chat room in 100 lines with nano and WebSocket](./examples/demo/chat) - [Tadpole demo](./examples/demo/tadpole) +## Installation + +```shell +go get github.com/lonnng/nano + +# dependencies +go get -u github.com/golang/protobuf +go get -u github.com/gorilla/websocket +``` + ## Benchmark ```shell diff --git a/application.png b/application.png new file mode 100644 index 00000000..b71087e4 Binary files /dev/null and b/application.png differ