Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/lesismal/arpc
More effective network communication, two-way calling, notify and broadcast supported.
https://github.com/lesismal/arpc
Last synced: 6 days ago
JSON representation
More effective network communication, two-way calling, notify and broadcast supported.
- Host: GitHub
- URL: https://github.com/lesismal/arpc
- Owner: lesismal
- License: mit
- Created: 2020-05-19T11:30:05.000Z (over 4 years ago)
- Default Branch: master
- Last Pushed: 2024-12-02T17:52:57.000Z (10 days ago)
- Last Synced: 2024-12-02T18:56:31.015Z (10 days ago)
- Language: Go
- Homepage:
- Size: 528 KB
- Stars: 971
- Watchers: 27
- Forks: 75
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
- awesome-go - arpc - More effective network communication, support two-way-calling, notify, broadcast. (Distributed Systems / Search and Analytic Databases)
- awesome-ccamel - lesismal/arpc - More effective network communication, two-way calling, notify and broadcast supported. (Go)
- awesome-go-extra - arpc - way calling, notify and broadcast supported.|586|61|1|2020-05-19T11:30:05Z|2022-08-24T10:55:07Z| (Distributed Systems / Advanced Console UIs)
README
# ARPC - More Effective Network Communication
[![Slack][1]][2]
[![Mentioned in Awesome Go][3]][4] [![MIT licensed][5]][6] [![Build Status][7]][8] [![Go Report Card][9]][10] [![Coverage Statusd][11]][12]
[1]: https://img.shields.io/badge/join-us%20on%20slack-gray.svg?longCache=true&logo=slack&colorB=green
[2]: https://join.slack.com/t/arpcnbio/shared_invite/zt-1esuz619h-SbKacrYHNdbkNmO9SV~X1A
[3]: https://awesome.re/mentioned-badge-flat.svg
[4]: https://github.com/avelino/awesome-go#distributed-systems
[5]: https://img.shields.io/badge/license-MIT-blue.svg
[6]: LICENSE
[7]: https://img.shields.io/github/actions/workflow/status/lesismal/arpc/build_linux.yml?branch=master&style=flat-square&logo=github-actions
[8]: https://github.com/lesismal/arpc/actions?query=workflow%3build-linux
[9]: https://goreportcard.com/badge/github.com/lesismal/arpc
[10]: https://goreportcard.com/report/github.com/lesismal/arpc
[11]: https://codecov.io/gh/lesismal/arpc/branch/master/graph/badge.svg
[12]: https://codecov.io/gh/lesismal/arpc
[13]: https://godoc.org/github.com/lesismal/arpc?status.svg
[14]: https://godoc.org/github.com/lesismal/arpc## Contents
- [ARPC - More Effective Network Communication](#arpc---more-effective-network-communication)
- [Contents](#contents)
- [Features](#features)
- [Performance](#performance)
- [Header Layout](#header-layout)
- [Installation](#installation)
- [Quick Start](#quick-start)
- [API Examples](#api-examples)
- [Register Routers](#register-routers)
- [Router Middleware](#router-middleware)
- [Coder Middleware](#coder-middleware)
- [Client Call, CallAsync, Notify](#client-call-callasync-notify)
- [Server Call, CallAsync, Notify](#server-call-callasync-notify)
- [Broadcast - Notify](#broadcast---notify)
- [Async Response](#async-response)
- [Handle New Connection](#handle-new-connection)
- [Handle Disconnected](#handle-disconnected)
- [Handle Client's send queue overstock](#handle-clients-send-queue-overstock)
- [Custom Net Protocol](#custom-net-protocol)
- [Custom Codec](#custom-codec)
- [Custom Logger](#custom-logger)
- [Custom operations before conn's recv and send](#custom-operations-before-conns-recv-and-send)
- [Custom arpc.Client's Reader by wrapping net.Conn](#custom-arpcclients-reader-by-wrapping-netconn)
- [Custom arpc.Client's send queue capacity](#custom-arpcclients-send-queue-capacity)
- [JS Client](#js-client)
- [Web Chat Examples](#web-chat-examples)
- [Pub/Sub Examples](#pubsub-examples)
- [More Examples](#more-examples)## Features
- [x] Two-Way Calling
- [x] Two-Way Notify
- [x] Sync and Async Calling
- [x] Sync and Async Response
- [x] Batch Write | Writev | net.Buffers
- [x] Broadcast
- [x] Middleware
- [x] Pub/Sub
- [x] [Opentracing](https://github.com/opentracing/opentracing-go)| Pattern | Interactive Directions | Description |
| ------- | ---------------------------- | ------------------------ |
| call | two-way:
c -> s
s -> c | request and response |
| notify | two-way:
c -> s
s -> c | request without response |## Performance
Here are some thirdparty benchmark including arpc, **although these repos have provide the performance report, but I suggest you run the code yourself and get the real result, other than just believe other people's doc**:
- [go-rpc-framework-benchmark](https://github.com/micro-svc/go-rpc-framework-benchmark)
- [rpcx-benchmark](https://github.com/rpcxio/rpcx-benchmark)
- [kitex-benchmark](https://github.com/cloudwego/kitex-benchmark)## Header Layout
- LittleEndian
| bodyLen | reserved | cmd | flag | methodLen | sequence | method | body |
| ------- | -------- | ------ | ------- | --------- | -------- | --------------- | ----------------------- |
| 4 bytes | 1 byte | 1 byte | 1 bytes | 1 bytes | 8 bytes | methodLen bytes | bodyLen-methodLen bytes |## Installation
1. Get and install arpc
```sh
$ go get -u github.com/lesismal/arpc
```2. Import in your code:
```go
import "github.com/lesismal/arpc"
```## Quick Start
- start a [server](https://github.com/lesismal/arpc/blob/master/examples/rpc/server/server.go)```go
package mainimport "github.com/lesismal/arpc"
func main() {
server := arpc.NewServer()// register router
server.Handler.Handle("/echo", func(ctx *arpc.Context) {
str := ""
if err := ctx.Bind(&str); err == nil {
ctx.Write(str)
}
})server.Run("localhost:8888")
}
```- start a [client](https://github.com/lesismal/arpc/blob/master/examples/rpc/client/client.go)
```go
package mainimport (
"log"
"net"
"time""github.com/lesismal/arpc"
)func main() {
client, err := arpc.NewClient(func() (net.Conn, error) {
return net.DialTimeout("tcp", "localhost:8888", time.Second*3)
})
if err != nil {
panic(err)
}
defer client.Stop()req := "hello"
rsp := ""
err = client.Call("/echo", &req, &rsp, time.Second*5)
if err != nil {
log.Fatalf("Call failed: %v", err)
} else {
log.Printf("Call Response: \"%v\"", rsp)
}
}
```## API Examples
### Register Routers
```golang
var handler arpc.Handler// package
handler = arpc.DefaultHandler
// server
handler = server.Handler
// client
handler = client.Handler// message would be default handled one by one in the same conn reader goroutine
handler.Handle("/route", func(ctx *arpc.Context) { ... })
handler.Handle("/route2", func(ctx *arpc.Context) { ... })// this make message handled by a new goroutine
async := true
handler.Handle("/asyncResponse", func(ctx *arpc.Context) { ... }, async)
```### Router Middleware
See [router middleware](https://github.com/lesismal/arpc/tree/master/extension/middleware/router), it's easy to implement middlewares yourself
```golang
import "github.com/lesismal/arpc/extension/middleware/router"var handler arpc.Handler
// package
handler = arpc.DefaultHandler
// server
handler = server.Handler
// client
handler = client.Handlerhandler.Use(router.Recover())
handler.Use(router.Logger())
handler.Use(func(ctx *arpc.Context) { ... })
handler.Handle("/echo", func(ctx *arpc.Context) { ... })
handler.Use(func(ctx *arpc.Context) { ... })
```### Coder Middleware
- Coder Middleware is used for converting a message data to your designed format, e.g encrypt/decrypt and compress/uncompress
```golang
import "github.com/lesismal/arpc/extension/middleware/coder/gzip"var handler arpc.Handler
// package
handler = arpc.DefaultHandler
// server
handler = server.Handler
// client
handler = client.Handlerhandler.UseCoder(gzip.New())
handler.Handle("/echo", func(ctx *arpc.Context) { ... })
```### Client Call, CallAsync, Notify
1. Call (Block, with timeout/context)
```golang
request := &Echo{...}
response := &Echo{}
timeout := time.Second*5
err := client.Call("/call/echo", request, response, timeout)
// ctx, cancel := context.WithTimeout(context.Background(), time.Second)
// defer cancel()
// err := client.CallWith(ctx, "/call/echo", request, response)
```2. CallAsync (Nonblock, with callback and timeout/context)
```golang
request := &Echo{...}timeout := time.Second*5
err := client.CallAsync("/call/echo", request, func(ctx *arpc.Context) {
response := &Echo{}
ctx.Bind(response)
...
}, timeout)
```3. Notify (same as CallAsync with timeout/context, without callback)
```golang
data := &Notify{...}
client.Notify("/notify", data, time.Second)
// ctx, cancel := context.WithTimeout(context.Background(), time.Second)
// defer cancel()
// client.NotifyWith(ctx, "/notify", data)
```### Server Call, CallAsync, Notify
1. Get client and keep it in your application
```golang
var client *arpc.Client
server.Handler.Handle("/route", func(ctx *arpc.Context) {
client = ctx.Client
// release client
client.OnDisconnected(func(c *arpc.Client){
client = nil
})
})go func() {
for {
time.Sleep(time.Second)
if client != nil {
client.Call(...)
client.CallAsync(...)
client.Notify(...)
}
}
}()
```2. Then Call/CallAsync/Notify
- [See Previous](#client-call-callasync-notify)
### Broadcast - Notify
- for more details: [**server**](https://github.com/lesismal/arpc/blob/master/examples/broadcast/server/server.go) [**client**](https://github.com/lesismal/arpc/blob/master/examples/broadcast/client/client.go)
```golang
var mux = sync.RWMutex{}
var clientMap = make(map[*arpc.Client]struct{})func broadcast() {
var svr *arpc.Server = ...
msg := svr.NewMessage(arpc.CmdNotify, "/broadcast", fmt.Sprintf("broadcast msg %d", i))
mux.RLock()
for client := range clientMap {
client.PushMsg(msg, arpc.TimeZero)
}
mux.RUnlock()
}
```### Async Response
```golang
var handler arpc.Handler// package
handler = arpc.DefaultHandler
// server
handler = server.Handler
// client
handler = client.HandlerasyncResponse := true // default is true, or set false
handler.Handle("/echo", func(ctx *arpc.Context) {
req := ...
err := ctx.Bind(req)
if err == nil {
ctx.Write(data)
}
}, asyncResponse)
```### Handle New Connection
```golang
// package
arpc.DefaultHandler.HandleConnected(func(c *arpc.Client) {
...
})// server
svr := arpc.NewServer()
svr.Handler.HandleConnected(func(c *arpc.Client) {
...
})// client
client, err := arpc.NewClient(...)
client.Handler.HandleConnected(func(c *arpc.Client) {
...
})
```### Handle Disconnected
```golang
// package
arpc.DefaultHandler.HandleDisconnected(func(c *arpc.Client) {
...
})// server
svr := arpc.NewServer()
svr.Handler.HandleDisconnected(func(c *arpc.Client) {
...
})// client
client, err := arpc.NewClient(...)
client.Handler.HandleDisconnected(func(c *arpc.Client) {
...
})
```### Handle Client's send queue overstock
```golang
// package
arpc.DefaultHandler.HandleOverstock(func(c *arpc.Client) {
...
})// server
svr := arpc.NewServer()
svr.Handler.HandleOverstock(func(c *arpc.Client) {
...
})// client
client, err := arpc.NewClient(...)
client.Handler.HandleOverstock(func(c *arpc.Client) {
...
})
```### Custom Net Protocol
```golang
// server
var ln net.Listener = ...
svr := arpc.NewServer()
svr.Serve(ln)// client
dialer := func() (net.Conn, error) {
return ...
}
client, err := arpc.NewClient(dialer)
```
### Custom Codec```golang
import "github.com/lesismal/arpc/codec"var codec arpc.Codec = ...
// package
codec.Defaultcodec = codec// server
svr := arpc.NewServer()
svr.Codec = codec// client
client, err := arpc.NewClient(...)
client.Codec = codec
```### Custom Logger
```golang
import "github.com/lesismal/arpc/log"var logger arpc.Logger = ...
log.SetLogger(logger) // log.DefaultLogger = logger
```### Custom operations before conn's recv and send
```golang
arpc.DefaultHandler.BeforeRecv(func(conn net.Conn) error) {
// ...
})arpc.DefaultHandler.BeforeSend(func(conn net.Conn) error) {
// ...
})
```### Custom arpc.Client's Reader by wrapping net.Conn
```golang
arpc.DefaultHandler.SetReaderWrapper(func(conn net.Conn) io.Reader) {
// ...
})
```### Custom arpc.Client's send queue capacity
```golang
arpc.DefaultHandler.SetSendQueueSize(4096)
```## JS Client
- See [arpc.js](https://github.com/lesismal/arpc/blob/master/extension/jsclient/arpc.js)
## Web Chat Examples
- See [webchat](https://github.com/lesismal/arpc/tree/master/examples/webchat)
## Pub/Sub Examples
- start a server
```golang
import "github.com/lesismal/arpc/extension/pubsub"var (
address = "localhost:8888"password = "123qwe"
topicName = "Broadcast"
)func main() {
s := pubsub.NewServer()
s.Password = password// server publish to all clients
go func() {
for i := 0; true; i++ {
time.Sleep(time.Second)
s.Publish(topicName, fmt.Sprintf("message from server %v", i))
}
}()s.Run(address)
}
```- start a subscribe client
```golang
import "github.com/lesismal/arpc/log"
import "github.com/lesismal/arpc/extension/pubsub"var (
address = "localhost:8888"password = "123qwe"
topicName = "Broadcast"
)func onTopic(topic *pubsub.Topic) {
log.Info("[OnTopic] [%v] \"%v\", [%v]",
topic.Name,
string(topic.Data),
time.Unix(topic.Timestamp/1000000000, topic.Timestamp%1000000000).Format("2006-01-02 15:04:05.000"))
}func main() {
client, err := pubsub.NewClient(func() (net.Conn, error) {
return net.DialTimeout("tcp", address, time.Second*3)
})
if err != nil {
panic(err)
}
client.Password = password// authentication
err = client.Authenticate()
if err != nil {
panic(err)
}// subscribe topic
if err := client.Subscribe(topicName, onTopic, time.Second); err != nil {
panic(err)
}<-make(chan int)
}
```- start a publish client
```golang
import "github.com/lesismal/arpc/extension/pubsub"var (
address = "localhost:8888"password = "123qwe"
topicName = "Broadcast"
)func main() {
client, err := pubsub.NewClient(func() (net.Conn, error) {
return net.DialTimeout("tcp", address, time.Second*3)
})
if err != nil {
panic(err)
}
client.Password = password// authentication
err = client.Authenticate()
if err != nil {
panic(err)
}for i := 0; true; i++ {
if i%5 == 0 {
// publish msg to all clients
client.Publish(topicName, fmt.Sprintf("message from client %d", i), time.Second)
} else {
// publish msg to only one client
client.PublishToOne(topicName, fmt.Sprintf("message from client %d", i), time.Second)
}
time.Sleep(time.Second)
}
}
```## More Examples
- See [examples](https://github.com/lesismal/arpc/tree/master/examples)