Initial commit

This commit is contained in:
Donny
2019-04-22 20:46:32 +08:00
commit 49ab8aadd1
25441 changed files with 4055000 additions and 0 deletions

View File

@@ -0,0 +1,86 @@
load(
"@io_bazel_rules_go//proto:def.bzl",
"go_proto_library",
)
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_test",
"go_library",
)
proto_library(
name = "liverpc_proto",
srcs = ["liverpc.proto"],
tags = ["automanaged"],
)
go_proto_library(
name = "liverpc_go_proto",
compilers = ["@io_bazel_rules_go//proto:go_proto"],
importpath = "go-common/library/net/rpc/liverpc",
proto = ":liverpc_proto",
tags = ["automanaged"],
)
go_test(
name = "go_default_test",
srcs = ["client_conn_test.go"],
embed = [":go_default_library"],
rundir = ".",
tags = ["automanaged"],
deps = [
"//library/conf/env:go_default_library",
"//library/net/metadata:go_default_library",
"//vendor/github.com/smartystreets/goconvey/convey:go_default_library",
],
)
go_library(
name = "go_default_library",
srcs = [
"client.go",
"client_conn.go",
"option.go",
"protocol.go",
],
embed = [":liverpc_go_proto"],
importpath = "go-common/library/net/rpc/liverpc",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//library/conf/env:go_default_library",
"//library/log:go_default_library",
"//library/naming:go_default_library",
"//library/naming/discovery:go_default_library",
"//library/net/metadata:go_default_library",
"//library/net/trace:go_default_library",
"//library/stat:go_default_library",
"//library/time:go_default_library",
"//vendor/github.com/json-iterator/go:go_default_library",
"//vendor/github.com/pkg/errors:go_default_library",
"@com_github_gogo_protobuf//proto:go_default_library",
"@com_github_golang_protobuf//proto:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [
":package-srcs",
"//library/net/rpc/liverpc/context:all-srcs",
"//library/net/rpc/liverpc/test:all-srcs",
"//library/net/rpc/liverpc/testdata:all-srcs",
],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@@ -0,0 +1,27 @@
### v1.0.8
- 加入CallOption
# v1.0.7
1. 调用liverpc使用color而不是group
# v1.0.6
1. 使用context cancel
2. 打日志
# v1.0.5
1. 默认分组改为default
# v1.0.4
1. 支持group分组转发
# v1.0.3
1. 监控上报code为空时不上报
# v1.0.2
2. 修改Header创建逻辑
# v1.0.1
1. 使用protobuf定义
# v1.0.0
1. 实现了liverpc协议

View File

@@ -0,0 +1,11 @@
# Owner
liugang
liuzhen
# Author
liugang
liuzhen
zhouzhichao
# Reviewer
liuzhen

View File

@@ -0,0 +1,10 @@
# See the OWNERS docs at https://go.k8s.io/owners
approvers:
- liugang
- liuzhen
- zhouzhichao
reviewers:
- liugang
- liuzhen
- zhouzhichao

View File

@@ -0,0 +1,5 @@
#### net/rpc/liverpc
##### 项目简介
打通go和直播原有rpc通信的道路

View File

@@ -0,0 +1,334 @@
package liverpc
import (
"context"
"fmt"
"net/url"
"sync/atomic"
"time"
"go-common/library/conf/env"
"go-common/library/log"
"go-common/library/naming"
"go-common/library/naming/discovery"
"go-common/library/net/metadata"
"go-common/library/net/trace"
"go-common/library/stat"
xtime "go-common/library/time"
"github.com/golang/protobuf/proto"
"github.com/pkg/errors"
)
// Key is ContextKey
type Key int
const (
_ Key = iota
// KeyHeader use this in context to pass rpc header field
// Depreated 请使用HeaderOption来传递Header
KeyHeader
// KeyTimeout deprecated
// Depreated 请使用HTTPOption来传递HTTP
KeyTimeout
)
const (
_scheme = "liverpc"
_dialRetries = 3
)
// Get Implement tracer carrier interface
func (m *Header) Get(key string) string {
if key == trace.KeyTraceID {
return m.TraceId
}
return ""
}
// Set Implement tracer carrier interface
func (m *Header) Set(key string, val string) {
if key == trace.KeyTraceID {
m.TraceId = val
}
}
var (
// ErrNoClient no RPC client.
errNoClient = errors.New("no rpc client")
errGroupInvalid = errors.New("invalid group")
stats = stat.RPCClient
)
// GroupAddrs a map struct storing addrs vary groups
type GroupAddrs map[string][]string
// ClientConfig client config.
type ClientConfig struct {
AppID string
Group string
Timeout xtime.Duration
ConnTimeout xtime.Duration
Addr string // if addr is provided, it will use add, else, use discovery
}
// Client is a RPC client.
type Client struct {
conf *ClientConfig
dis naming.Resolver
addrs atomic.Value // GroupAddrs
addrsIdx int64
}
// NewClient new a RPC client with discovery.
func NewClient(c *ClientConfig) *Client {
if c.Timeout <= 0 {
c.Timeout = xtime.Duration(time.Second)
}
if c.ConnTimeout <= 0 {
c.ConnTimeout = xtime.Duration(time.Second)
}
cli := &Client{
conf: c,
}
if c.Addr != "" {
groupAddrs := make(GroupAddrs)
groupAddrs[""] = []string{c.Addr}
cli.addrs.Store(groupAddrs)
return cli
}
cli.dis = discovery.Build(c.AppID)
// discovery watch & fetch nodes
event := cli.dis.Watch()
select {
case _, ok := <-event:
if !ok {
panic("刚启动就从discovery拉到了关闭的event")
}
cli.disFetch()
fmt.Printf("开始创建:%s 的liverpc client等待从discovery拉取节点%s\n", c.AppID, time.Now().Format("2006-01-02 15:04:05"))
case <-time.After(10 * time.Second):
fmt.Printf("失败创建:%s 的liverpc client竟然从discovery拉取节点超时了%s\n", c.AppID, time.Now().Format("2006-01-02 15:04:05"))
}
go cli.disproc(event)
return cli
}
func (c *Client) disproc(event <-chan struct{}) {
for {
_, ok := <-event
if !ok {
return
}
c.disFetch()
}
}
func (c *Client) disFetch() {
ins, ok := c.dis.Fetch(context.Background())
if !ok {
return
}
insZone, ok := ins[env.Zone]
if !ok {
return
}
addrs := make(GroupAddrs)
for _, svr := range insZone {
group, ok := svr.Metadata["color"]
if !ok {
group = ""
}
for _, addr := range svr.Addrs {
u, err := url.Parse(addr)
if err == nil && u.Scheme == _scheme {
addrs[group] = append(addrs[group], u.Host)
}
}
}
if len(addrs) > 0 {
c.addrs.Store(addrs)
}
}
// pickConn pick conn by addrs
func (c *Client) pickConn(ctx context.Context, addrs []string, dialTimeout time.Duration) (*ClientConn, error) {
var (
lastErr error
)
if len(addrs) == 0 {
lastErr = errors.New("addrs empty")
} else {
for i := 0; i < _dialRetries; i++ {
idx := atomic.AddInt64(&c.addrsIdx, 1)
addr := addrs[int(idx)%len(addrs)]
if dialTimeout == 0 {
dialTimeout = time.Duration(c.conf.ConnTimeout)
}
cc, err := Dial(ctx, "tcp", addr, time.Duration(c.conf.Timeout), dialTimeout)
if err != nil {
lastErr = errors.Wrapf(err, "Dial %s error", addr)
continue
}
return cc, nil
}
}
if lastErr != nil {
return nil, errors.WithMessage(errNoClient, lastErr.Error())
}
return nil, errors.WithStack(errNoClient)
}
// fetchAddrs fetch addrs by different strategies
// source_group first, come from request header if exists, currently only CallRaw supports source_group
// then env group, come from os.env
// since no invalid group found, return error
func (c *Client) fetchAddrs(ctx context.Context, request interface{}) (addrs []string, err error) {
var (
args *Args
groupAddrs GroupAddrs
ok bool
sourceGroup string
groups []string
)
defer func() {
if err != nil {
err = errors.WithMessage(errGroupInvalid, err.Error())
}
}()
// try parse request header and fetch source group
if args, ok = request.(*Args); ok && args.Header != nil {
sourceGroup = args.Header.SourceGroup
if sourceGroup != "" {
groups = append(groups, sourceGroup)
}
}
metaColor := metadata.String(ctx, metadata.Color)
if metaColor != "" && metaColor != sourceGroup {
groups = append(groups, metaColor)
}
if env.Color != "" && env.Color != metaColor {
groups = append(groups, env.Color)
}
groups = append(groups, "")
if groupAddrs, ok = c.addrs.Load().(GroupAddrs); !ok {
err = errors.New("addrs load error")
return
}
if len(groupAddrs) == 0 {
err = errors.New("group addrs empty")
return
}
for _, group := range groups {
if addrs, ok = groupAddrs[group]; ok {
break
}
}
if len(addrs) == 0 {
err = errors.Errorf("addrs empty source(%s), metadata(%s), env(%s), default empty, allAddrs(%+v)",
sourceGroup, metaColor, env.Color, groupAddrs)
return
}
return
}
// Call call the service method, waits for it to complete, and returns its error status.
// client: {service}
// serviceMethod: {version}|{controller.method}
// httpURL: /room/v1/Room/room_init
// httpURL: /{service}/{version}/{controller}/{method}
func (c *Client) Call(ctx context.Context, version int, serviceMethod string, in proto.Message, out proto.Message, opts ...CallOption) (err error) {
var (
cc *ClientConn
addrs []string
)
isPickErr := true
defer func() {
if cc != nil {
cc.Close()
}
if err != nil && isPickErr {
log.Error("liverpc Call pick connection error, version %d, method: %s, error: %+v", version, serviceMethod, err)
}
}() // for now it is non-persistent connection
var cInfo = &callInfo{}
for _, o := range opts {
o.before(cInfo)
}
addrs, err = c.fetchAddrs(ctx, in)
if err != nil {
return
}
cc, err = c.pickConn(ctx, addrs, cInfo.DialTimeout)
if err != nil {
return
}
isPickErr = false
cc.callInfo = cInfo
err = cc.Call(ctx, version, serviceMethod, in, out)
if err != nil {
return
}
for _, o := range opts {
o.after(cc.callInfo)
}
return
}
// CallRaw call the service method, waits for it to complete, and returns reply its error status.
// this is can be use without protobuf
// client: {service}
// serviceMethod: {version}|{controller.method}
// httpURL: /room/v1/Room/room_init
// httpURL: /{service}/{version}/{controller}/{method}
func (c *Client) CallRaw(ctx context.Context, version int, serviceMethod string, in *Args, opts ...CallOption) (out *Reply, err error) {
var (
cc *ClientConn
addrs []string
)
isPickErr := true
defer func() {
if cc != nil {
cc.Close()
}
if err != nil && isPickErr {
log.Error("liverpc CallRaw pick connection error, version %d, method: %s, error: %+v", version, serviceMethod, err)
}
}() // for now it is non-persistent connection
var cInfo = &callInfo{}
for _, o := range opts {
o.before(cInfo)
}
addrs, err = c.fetchAddrs(ctx, in)
if err != nil {
return
}
cc, err = c.pickConn(ctx, addrs, cInfo.DialTimeout)
if err != nil {
return
}
isPickErr = false
cc.callInfo = cInfo
out, err = cc.CallRaw(ctx, version, serviceMethod, in)
if err != nil {
return
}
for _, o := range opts {
o.after(cc.callInfo)
}
return
}
//Close handle client exit
func (c *Client) Close() {
if c.dis != nil {
c.dis.Close()
}
}

View File

@@ -0,0 +1,371 @@
package liverpc
import (
"context"
"encoding/binary"
"encoding/json"
"fmt"
"io"
"net"
"strconv"
"strings"
"time"
"go-common/library/conf/env"
"go-common/library/log"
"go-common/library/net/metadata"
"go-common/library/net/trace"
"github.com/gogo/protobuf/proto"
"github.com/json-iterator/go"
"github.com/pkg/errors"
)
// ClientConn connect represent a real client connection to a rpc server
type ClientConn struct {
addr string
network string
rwc io.ReadWriteCloser
Timeout time.Duration
DialTimeout time.Duration
callInfo *callInfo
}
type fullReqMsg struct {
Header *Header `json:"header"`
HTTP *HTTP `json:"http"`
Body interface{} `json:"body"`
}
// Dial dial a rpc server
func Dial(ctx context.Context, network, addr string, timeout time.Duration, connTimeout time.Duration) (*ClientConn, error) {
c := &ClientConn{
addr: addr,
network: network,
Timeout: timeout,
DialTimeout: connTimeout,
}
conn, err := net.DialTimeout(c.network, c.addr, c.DialTimeout)
if err != nil {
return nil, err
}
c.rwc = conn
return c, err
}
// Close close the caller connection.
func (c *ClientConn) Close() error {
if c.rwc != nil {
return c.rwc.Close()
}
return nil
}
func (c *ClientConn) writeRequest(ctx context.Context, req *protoReq) (err error) {
var (
headerBuf = make([]byte, _headerLen)
header = req.Header
body = req.Body
)
binary.BigEndian.PutUint32(headerBuf[0:4], header.magic)
binary.BigEndian.PutUint32(headerBuf[4:8], header.timestamp)
binary.BigEndian.PutUint32(headerBuf[8:12], header.checkSum)
binary.BigEndian.PutUint32(headerBuf[12:16], header.version)
binary.BigEndian.PutUint32(headerBuf[16:20], header.reserved)
binary.BigEndian.PutUint32(headerBuf[20:24], header.seq)
binary.BigEndian.PutUint32(headerBuf[24:28], uint32(len(body)))
copy(headerBuf[28:60], header.cmd)
if _, err = c.rwc.Write(headerBuf); err != nil {
err = errors.Wrap(err, "write req header error")
return
}
if log.V(2) {
log.Info("liverpc body: %s", string(body))
}
if _, err = c.rwc.Write(body); err != nil {
err = errors.Wrap(err, "write req body error")
return
}
return
}
func (c *ClientConn) readResponse(ctx context.Context, resp *protoResp) (err error) {
var (
headerBuf = make([]byte, _headerLen)
length int
)
if _, err = c.rwc.Read(headerBuf); err != nil {
err = errors.Wrap(err, "read resp header error")
return
}
resp.Header.magic = binary.BigEndian.Uint32(headerBuf[0:4])
resp.Header.timestamp = binary.BigEndian.Uint32(headerBuf[4:8])
resp.Header.checkSum = binary.BigEndian.Uint32(headerBuf[8:12])
resp.Header.version = binary.BigEndian.Uint32(headerBuf[12:16])
resp.Header.reserved = binary.BigEndian.Uint32(headerBuf[16:20])
resp.Header.seq = binary.BigEndian.Uint32(headerBuf[20:24])
resp.Header.length = binary.BigEndian.Uint32(headerBuf[24:28])
resp.Header.cmd = headerBuf[28:60]
resp.Body = make([]byte, resp.Header.length)
if length, err = io.ReadFull(c.rwc, resp.Body); err != nil {
err = errors.Wrap(err, "read resp body error")
return
}
if uint32(length) != resp.Header.length {
err = errors.New("bad resp body data")
return
}
return
}
func (c *ClientConn) composeReqPackHeader(reqPack *protoReq, version int, serviceMethod string) {
reqPack.Header.magic = _magic
reqPack.Header.checkSum = 0
reqPack.Header.seq = 1
reqPack.Header.timestamp = uint32(time.Now().Unix())
reqPack.Header.reserved = 0
reqPack.Header.version = uint32(version)
// command: {message_type}controller.method
reqPack.Header.cmd = make([]byte, 32)
reqPack.Header.cmd[0] = _cmdReqType
// serviceMethod: Room.room_init
copy(reqPack.Header.cmd[1:], []byte(serviceMethod))
}
func (c *ClientConn) setupDeadline(ctx context.Context) error {
var t time.Duration
if c.callInfo.Timeout != 0 {
t = c.callInfo.Timeout
} else {
t, _ = ctx.Value(KeyTimeout).(time.Duration)
}
if t == 0 {
t = c.Timeout
}
conn := c.rwc.(net.Conn)
if conn != nil {
err := conn.SetDeadline(time.Now().Add(t))
if err != nil {
conn.Close()
return err
}
}
return nil
}
// CallRaw call the service method, waits for it to complete, and returns reply its error status.
// this is can be use without protobuf
// client: {service}
// serviceMethod: {version}|{controller.method}
// httpURL: /room/v1/Room/room_init
// httpURL: /{service}/{version}/{controller}/{method}
func (c *ClientConn) CallRaw(ctx context.Context, version int, serviceMethod string, in *Args) (out *Reply, err error) {
var (
reqPack protoReq
respPack protoResp
code = "0"
now = time.Now()
uid int64
)
defer func() {
stats.Timing(serviceMethod, int64(time.Since(now)/time.Millisecond))
if code != "" {
stats.Incr(serviceMethod, code)
}
logging(ctx, version, serviceMethod, c.addr, err, time.Since(now), uid)
}()
if err = c.setupDeadline(ctx); err != nil {
return
}
// it is ok for request http field to be nil
if in.Header == nil {
if c.callInfo.Header != nil {
in.Header = c.callInfo.Header
} else if hdr, _ := ctx.Value(KeyHeader).(*Header); hdr != nil {
in.Header = hdr
} else {
in.Header = createHeader(ctx)
}
}
uid = in.Header.Uid
if in.HTTP == nil {
if c.callInfo.HTTP != nil {
in.HTTP = c.callInfo.HTTP
}
}
if in.Body == nil {
in.Body = map[string]interface{}{}
}
c.composeReqPackHeader(&reqPack, version, serviceMethod)
var reqBytes []byte
if reqBytes, err = json.Marshal(in); err != nil {
err = errors.Wrap(err, "CallRaw json marshal error")
code = "marshalErr"
return
}
reqPack.Body = reqBytes
ch := make(chan error, 1)
go func() {
ch <- c.sendAndRecv(ctx, &reqPack, &respPack)
}()
select {
case <-ctx.Done():
err = errors.WithStack(ctx.Err())
code = "canceled"
return
case err = <-ch:
if err != nil {
code = "ioErr"
return
}
}
out = &Reply{}
if err = json.Unmarshal(respPack.Body, out); err != nil {
err = errors.Wrap(err, "proto unmarshal error: "+string(respPack.Body))
code = "unmarshalErr"
return
}
return
}
func logging(ctx context.Context, version int, serviceMethod string, addr string, err error, ts time.Duration, uid int64) {
var (
path string
errMsg string
)
logFunc := log.Infov
if err != nil {
if errors.Cause(err) == context.Canceled {
logFunc = log.Warnv
} else {
logFunc = log.Errorv
}
errMsg = fmt.Sprintf("%+v", err)
}
path = "/v" + strconv.Itoa(version) + "/" + strings.Replace(serviceMethod, ".", "/", 1)
logFunc(ctx,
log.KV("path", path),
log.KV("error", errMsg),
log.KV("addr", addr),
log.KV("ts", float64(ts.Seconds())),
log.KV("uid", uid),
log.KV("log", "LIVERPC"),
)
}
func (c *ClientConn) sendAndRecv(ctx context.Context, reqPack *protoReq, respPack *protoResp) (err error) {
if err = c.writeRequest(ctx, reqPack); err != nil {
return
}
if err = c.readResponse(ctx, respPack); err != nil {
return
}
return
}
// Call call the service method, waits for it to complete, and returns its error status.
// this is used with protobuf generated msg
// client: {service}
// serviceMethod: {version}|{controller.method}
// httpURL: /room/v1/Room/room_init
// httpURL: /{service}/{version}/{controller}/{method}
func (c *ClientConn) Call(ctx context.Context, version int, serviceMethod string, in, out proto.Message) (err error) {
var (
reqPack protoReq
respPack protoResp
code = "0"
now = time.Now()
uid int64
)
defer func() {
stats.Timing(serviceMethod, int64(time.Since(now)/time.Millisecond))
if code != "" {
stats.Incr(serviceMethod, code)
}
logging(ctx, version, serviceMethod, c.addr, err, time.Since(now), uid)
}()
if err = c.setupDeadline(ctx); err != nil {
return
}
fullMsg := &fullReqMsg{}
if c.callInfo.Header != nil {
fullMsg.Header = c.callInfo.Header
} else if hdr, _ := ctx.Value(KeyHeader).(*Header); hdr != nil {
fullMsg.Header = hdr
} else {
fullMsg.Header = createHeader(ctx)
}
uid = fullMsg.Header.Uid
if c.callInfo.HTTP != nil {
fullMsg.HTTP = c.callInfo.HTTP
}
fullMsg.Body = in
// it is ok for request http field to be nil
c.composeReqPackHeader(&reqPack, version, serviceMethod)
var reqBody []byte
if reqBody, err = json.Marshal(fullMsg); err != nil {
err = errors.Wrap(err, "Call json marshal error")
code = "marshalErr"
return
}
reqPack.Body = reqBody
ch := make(chan error, 1)
go func() {
ch <- c.sendAndRecv(ctx, &reqPack, &respPack)
}()
select {
case <-ctx.Done():
err = errors.WithStack(ctx.Err())
code = "canceled"
return
case err = <-ch:
if err != nil {
code = "ioErr"
return
}
}
if err = jsoniter.Unmarshal(respPack.Body, out); err != nil {
err = errors.Wrap(err, "proto unmarshal error: "+string(respPack.Body))
code = "unmarshalErr"
return
}
return
}
func createHeader(ctx context.Context) *Header {
header := &Header{}
header.UserIp = metadata.String(ctx, metadata.RemoteIP)
header.Caller = strings.Replace(env.AppID, ".", "-", -1)
if header.Caller == "" {
header.Caller = "unknown"
}
tracer, ok := metadata.Value(ctx, metadata.Trace).(trace.Trace)
if ok {
trace.Inject(tracer, nil, header)
}
mid, _ := metadata.Value(ctx, "mid").(int64)
header.Uid = mid
if color := metadata.String(ctx, metadata.Color); color != "" {
header.SourceGroup = color
} else {
header.SourceGroup = env.Color
}
//header.Platform = ctx.Request.FormValue("platform")
return header
}

View File

@@ -0,0 +1,93 @@
package liverpc
import (
"context"
"math/rand"
"testing"
"time"
"go-common/library/conf/env"
"go-common/library/net/metadata"
. "github.com/smartystreets/goconvey/convey"
)
type testConn struct {
}
func (t *testConn) Read(p []byte) (n int, err error) {
return
}
func (t *testConn) Write(p []byte) (n int, err error) {
return
}
func (t *testConn) Close() (err error) {
return
}
func TestClientConn(t *testing.T) {
var (
req protoReq
resp protoResp
)
req.Header.magic = _magic
req.Header.checkSum = 0
req.Header.seq = rand.Uint32()
req.Header.timestamp = uint32(time.Now().Unix())
req.Header.reserved = 1
req.Header.version = 1
// command: {message_type}controller.method
req.Header.cmd = make([]byte, 32)
req.Header.cmd[0] = _cmdReqType
// serviceMethod: Room.room_init
copy(req.Header.cmd[1:], []byte("Room.room_init"))
codec := &ClientConn{rwc: &testConn{}}
if err := codec.writeRequest(context.TODO(), &req); err != nil {
t.Error(err)
t.FailNow()
}
if err := codec.readResponse(context.TODO(), &resp); err != nil {
t.Error(err)
t.FailNow()
}
t.Logf("request header:%+v body:%s", req.Header, req.Body)
t.Logf("response header:%+v body:%s", resp.Header, resp.Body)
}
func TestGroups(t *testing.T) {
Convey("groups", t, func() {
client := Client{}
// env before empty
env.Color = "red"
client.addrs.Store(GroupAddrs{
"red": []string{"r1", "r2"},
"": {"empty1", "empty2"},
"dark": {"d1", "d2"},
"blue": []string{"b1", "b2"},
})
addrs, _ := client.fetchAddrs(context.TODO(), nil)
So(addrs, ShouldResemble, []string{"r1", "r2"})
// can get env
env.Color = ""
addrs, _ = client.fetchAddrs(context.TODO(), nil)
So(addrs, ShouldResemble, []string{"empty1", "empty2"})
// from metadata.color
env.Color = "red"
addrs, _ = client.fetchAddrs(
metadata.NewContext(context.TODO(), metadata.MD{metadata.Color: "blue"}), nil)
So(addrs, ShouldResemble, []string{"b1", "b2"})
// header source_group always first
addrs, _ = client.fetchAddrs(
metadata.NewContext(context.TODO(), metadata.MD{metadata.Color: "blue"}),
&Args{Header: &Header{SourceGroup: "dark"}})
So(addrs, ShouldResemble, []string{"d1", "d2"})
})
}

View File

@@ -0,0 +1,29 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
)
go_library(
name = "go_default_library",
srcs = ["context.go"],
importpath = "go-common/library/net/rpc/liverpc/context",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = ["//library/net/rpc/liverpc:go_default_library"],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@@ -0,0 +1,23 @@
package context
import (
"context"
"time"
"go-common/library/net/rpc/liverpc"
)
// WithHeader returns new context with header
// Deprecated: Use HeaderOption instead
func WithHeader(ctx context.Context, header *liverpc.Header) (ret context.Context) {
ret = context.WithValue(ctx, liverpc.KeyHeader, header)
return
}
// WithTimeout set timeout to rpc request
// Notice this is nothing related to to built-in context.WithTimeout
// Deprecated: Use TimeoutOption instead
func WithTimeout(ctx context.Context, time time.Duration) (ret context.Context) {
ret = context.WithValue(ctx, liverpc.KeyTimeout, time)
return
}

View File

@@ -0,0 +1,2 @@
#!/bin/bash
protoc --go_out=paths=source_relative:. liverpc.proto

View File

@@ -0,0 +1,252 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// source: liverpc.proto
package liverpc // import "go-common/library/net/rpc/liverpc"
import proto "github.com/golang/protobuf/proto"
import fmt "fmt"
import math "math"
// Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal
var _ = fmt.Errorf
var _ = math.Inf
// This is a compile-time assertion to ensure that this generated file
// is compatible with the proto package it is being compiled against.
// A compilation error at this line likely means your copy of the
// proto package needs to be updated.
const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package
type Header struct {
// APP_NAME.xxxxx , when separated by dot,
// the first part is always app_name, the rest is undefined
Caller string `protobuf:"bytes,1,opt,name=caller,proto3" json:"caller,omitempty"`
Uid int64 `protobuf:"varint,2,opt,name=uid,proto3" json:"uid,omitempty"`
Platform string `protobuf:"bytes,3,opt,name=platform,proto3" json:"platform,omitempty"`
Src string `protobuf:"bytes,4,opt,name=src,proto3" json:"src,omitempty"`
TraceId string `protobuf:"bytes,5,opt,name=trace_id,json=traceId,proto3" json:"trace_id,omitempty"`
UserIp string `protobuf:"bytes,7,opt,name=user_ip,json=userIp,proto3" json:"user_ip,omitempty"`
SourceGroup string `protobuf:"bytes,8,opt,name=source_group,json=sourceGroup,proto3" json:"source_group,omitempty"`
Buvid string `protobuf:"bytes,9,opt,name=buvid,proto3" json:"buvid,omitempty"`
// session data, format is http query
// such as access_token=abc&SESS_DATA=def
Sessdata2 string `protobuf:"bytes,10,opt,name=sessdata2,proto3" json:"sessdata2,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *Header) Reset() { *m = Header{} }
func (m *Header) String() string { return proto.CompactTextString(m) }
func (*Header) ProtoMessage() {}
func (*Header) Descriptor() ([]byte, []int) {
return fileDescriptor_liverpc_376c41dd15148bd6, []int{0}
}
func (m *Header) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_Header.Unmarshal(m, b)
}
func (m *Header) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_Header.Marshal(b, m, deterministic)
}
func (dst *Header) XXX_Merge(src proto.Message) {
xxx_messageInfo_Header.Merge(dst, src)
}
func (m *Header) XXX_Size() int {
return xxx_messageInfo_Header.Size(m)
}
func (m *Header) XXX_DiscardUnknown() {
xxx_messageInfo_Header.DiscardUnknown(m)
}
var xxx_messageInfo_Header proto.InternalMessageInfo
func (m *Header) GetCaller() string {
if m != nil {
return m.Caller
}
return ""
}
func (m *Header) GetUid() int64 {
if m != nil {
return m.Uid
}
return 0
}
func (m *Header) GetPlatform() string {
if m != nil {
return m.Platform
}
return ""
}
func (m *Header) GetSrc() string {
if m != nil {
return m.Src
}
return ""
}
func (m *Header) GetTraceId() string {
if m != nil {
return m.TraceId
}
return ""
}
func (m *Header) GetUserIp() string {
if m != nil {
return m.UserIp
}
return ""
}
func (m *Header) GetSourceGroup() string {
if m != nil {
return m.SourceGroup
}
return ""
}
func (m *Header) GetBuvid() string {
if m != nil {
return m.Buvid
}
return ""
}
func (m *Header) GetSessdata2() string {
if m != nil {
return m.Sessdata2
}
return ""
}
// http is inside the protocol body
// {"body":..., "header":..., "http":...}
// this is used when a proxy forward a http request to a rpc request
type HTTP struct {
IsHttps int32 `protobuf:"varint,1,opt,name=is_https,json=isHttps,proto3" json:"is_https,omitempty"`
Body string `protobuf:"bytes,2,opt,name=body,proto3" json:"body,omitempty"`
Cookie map[string]string `protobuf:"bytes,3,rep,name=cookie,proto3" json:"cookie,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
Header map[string]string `protobuf:"bytes,4,rep,name=header,proto3" json:"header,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
Uri string `protobuf:"bytes,5,opt,name=uri,proto3" json:"uri,omitempty"`
Method string `protobuf:"bytes,6,opt,name=method,proto3" json:"method,omitempty"`
Protocol string `protobuf:"bytes,7,opt,name=protocol,proto3" json:"protocol,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *HTTP) Reset() { *m = HTTP{} }
func (m *HTTP) String() string { return proto.CompactTextString(m) }
func (*HTTP) ProtoMessage() {}
func (*HTTP) Descriptor() ([]byte, []int) {
return fileDescriptor_liverpc_376c41dd15148bd6, []int{1}
}
func (m *HTTP) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_HTTP.Unmarshal(m, b)
}
func (m *HTTP) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_HTTP.Marshal(b, m, deterministic)
}
func (dst *HTTP) XXX_Merge(src proto.Message) {
xxx_messageInfo_HTTP.Merge(dst, src)
}
func (m *HTTP) XXX_Size() int {
return xxx_messageInfo_HTTP.Size(m)
}
func (m *HTTP) XXX_DiscardUnknown() {
xxx_messageInfo_HTTP.DiscardUnknown(m)
}
var xxx_messageInfo_HTTP proto.InternalMessageInfo
func (m *HTTP) GetIsHttps() int32 {
if m != nil {
return m.IsHttps
}
return 0
}
func (m *HTTP) GetBody() string {
if m != nil {
return m.Body
}
return ""
}
func (m *HTTP) GetCookie() map[string]string {
if m != nil {
return m.Cookie
}
return nil
}
func (m *HTTP) GetHeader() map[string]string {
if m != nil {
return m.Header
}
return nil
}
func (m *HTTP) GetUri() string {
if m != nil {
return m.Uri
}
return ""
}
func (m *HTTP) GetMethod() string {
if m != nil {
return m.Method
}
return ""
}
func (m *HTTP) GetProtocol() string {
if m != nil {
return m.Protocol
}
return ""
}
func init() {
proto.RegisterType((*Header)(nil), "liverpc.Header")
proto.RegisterType((*HTTP)(nil), "liverpc.HTTP")
proto.RegisterMapType((map[string]string)(nil), "liverpc.HTTP.CookieEntry")
proto.RegisterMapType((map[string]string)(nil), "liverpc.HTTP.HeaderEntry")
}
func init() { proto.RegisterFile("liverpc.proto", fileDescriptor_liverpc_376c41dd15148bd6) }
var fileDescriptor_liverpc_376c41dd15148bd6 = []byte{
// 386 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x91, 0xb1, 0xce, 0xd3, 0x30,
0x10, 0xc7, 0x95, 0x26, 0x4d, 0x1a, 0x17, 0x24, 0x64, 0x21, 0xf0, 0xf7, 0x89, 0xa1, 0x2d, 0x4b,
0x17, 0x1a, 0x51, 0x16, 0x60, 0x04, 0x21, 0xda, 0x0d, 0x45, 0x9d, 0x58, 0x22, 0xc7, 0x36, 0xad,
0xd5, 0xa4, 0xb6, 0x6c, 0xa7, 0x52, 0x9e, 0x94, 0x87, 0xe0, 0x25, 0xd0, 0xd9, 0xa6, 0x74, 0x60,
0x61, 0xbb, 0xdf, 0xdd, 0xfd, 0xed, 0xbb, 0xff, 0xa1, 0xa7, 0x9d, 0xbc, 0x0a, 0xa3, 0xd9, 0x46,
0x1b, 0xe5, 0x14, 0x2e, 0x22, 0xae, 0x7e, 0x25, 0x28, 0xdf, 0x09, 0xca, 0x85, 0xc1, 0x2f, 0x50,
0xce, 0x68, 0xd7, 0x09, 0x43, 0x92, 0x45, 0xb2, 0x2e, 0xeb, 0x48, 0xf8, 0x19, 0x4a, 0x07, 0xc9,
0xc9, 0x64, 0x91, 0xac, 0xd3, 0x1a, 0x42, 0xfc, 0x88, 0x66, 0xba, 0xa3, 0xee, 0x87, 0x32, 0x3d,
0x49, 0x7d, 0xef, 0x8d, 0xa1, 0xdb, 0x1a, 0x46, 0x32, 0x9f, 0x86, 0x10, 0x3f, 0xa0, 0x99, 0x33,
0x94, 0x89, 0x46, 0x72, 0x32, 0xf5, 0xe9, 0xc2, 0xf3, 0x9e, 0xe3, 0x97, 0xa8, 0x18, 0xac, 0x30,
0x8d, 0xd4, 0xa4, 0x08, 0x7f, 0x02, 0xee, 0x35, 0x5e, 0xa2, 0x27, 0x56, 0x0d, 0x86, 0x89, 0xe6,
0x68, 0xd4, 0xa0, 0xc9, 0xcc, 0x57, 0xe7, 0x21, 0xf7, 0x15, 0x52, 0xf8, 0x39, 0x9a, 0xb6, 0xc3,
0x55, 0x72, 0x52, 0xfa, 0x5a, 0x00, 0xfc, 0x0a, 0x95, 0x56, 0x58, 0xcb, 0xa9, 0xa3, 0x5b, 0x82,
0x7c, 0xe5, 0x6f, 0x62, 0xf5, 0x73, 0x82, 0xb2, 0xdd, 0xe1, 0xf0, 0x0d, 0x66, 0x92, 0xb6, 0x39,
0x39, 0xa7, 0xad, 0xdf, 0x76, 0x5a, 0x17, 0xd2, 0xee, 0x00, 0x31, 0x46, 0x59, 0xab, 0xf8, 0xe8,
0xf7, 0x2d, 0x6b, 0x1f, 0xe3, 0xb7, 0x28, 0x67, 0x4a, 0x9d, 0xa5, 0x20, 0xe9, 0x22, 0x5d, 0xcf,
0xb7, 0x0f, 0x9b, 0x3f, 0x76, 0xc2, 0x6b, 0x9b, 0xcf, 0xbe, 0xf6, 0xe5, 0xe2, 0xcc, 0x58, 0xc7,
0x46, 0x90, 0x9c, 0xbc, 0xaf, 0x24, 0xfb, 0x97, 0x24, 0x78, 0x1e, 0x25, 0xa1, 0xd1, 0x1b, 0x6d,
0x64, 0xf4, 0x08, 0x42, 0x38, 0x49, 0x2f, 0xdc, 0x49, 0x71, 0x92, 0x07, 0x7b, 0x02, 0xf9, 0x03,
0xc0, 0x1d, 0x99, 0xea, 0xa2, 0x71, 0x37, 0x7e, 0xfc, 0x80, 0xe6, 0x77, 0xf3, 0xc0, 0xa3, 0x67,
0x31, 0xc6, 0x93, 0x42, 0x08, 0xc6, 0x5d, 0x69, 0x37, 0x88, 0xb8, 0x61, 0x80, 0x8f, 0x93, 0xf7,
0x09, 0x48, 0xef, 0xe6, 0xfa, 0x1f, 0xe9, 0xa7, 0xd7, 0xdf, 0x97, 0x47, 0xf5, 0x86, 0xa9, 0xbe,
0x57, 0x97, 0xaa, 0x93, 0xad, 0xa1, 0x66, 0xac, 0x2e, 0xc2, 0x55, 0x46, 0xb3, 0x2a, 0x6e, 0xde,
0xe6, 0x7e, 0xc8, 0x77, 0xbf, 0x03, 0x00, 0x00, 0xff, 0xff, 0xfe, 0x68, 0x55, 0x93, 0x8d, 0x02,
0x00, 0x00,
}

View File

@@ -0,0 +1,35 @@
syntax = "proto3";
package liverpc;
option go_package = "go-common/library/net/rpc/liverpc";
message Header {
// APP_NAME.xxxxx , when separated by dot,
// the first part is always app_name, the rest is undefined
string caller = 1;
int64 uid = 2;
string platform = 3;
string src = 4;
string trace_id = 5;
string user_ip = 7;
string source_group = 8;
string buvid = 9;
// session data, format is http query
// such as access_token=abc&SESS_DATA=def
string sessdata2 = 10;
}
// http is inside the protocol body
// {"body":..., "header":..., "http":...}
// this is used when a proxy forward a http request to a rpc request
message HTTP {
int32 is_https = 1;
string body = 2; // the original body, only used when nessasary, usually null
map<string, string> cookie = 3;
map<string, string> header = 4;
string uri = 5; // user original uri
string method = 6; // http method
string protocol = 7; // not much use here
}

View File

@@ -0,0 +1,56 @@
package liverpc
import (
"time"
)
// CallOption ...
type CallOption interface {
before(*callInfo)
after(*callInfo)
}
type callInfo struct {
Header *Header
HTTP *HTTP
DialTimeout time.Duration
Timeout time.Duration
}
// TimeoutOption is timeout for a specific call
type TimeoutOption struct {
DialTimeout time.Duration
Timeout time.Duration
}
func (t TimeoutOption) before(info *callInfo) {
info.DialTimeout = t.DialTimeout
info.Timeout = t.Timeout
}
func (t TimeoutOption) after(*callInfo) {
}
// HeaderOption contains Header for liverpc
type HeaderOption struct {
Header *Header
}
func (h HeaderOption) before(info *callInfo) {
info.Header = h.Header
}
func (h HeaderOption) after(*callInfo) {
}
// HTTPOption contains HTTP for liverpc
type HTTPOption struct {
HTTP *HTTP
}
func (h HTTPOption) before(info *callInfo) {
info.HTTP = h.HTTP
}
func (h HTTPOption) after(*callInfo) {
}

View File

@@ -0,0 +1,45 @@
package liverpc
import "encoding/json"
const (
_magic = 2233
_headerLen = 60
_cmdReqType = byte('0')
)
type protoHeader struct {
magic uint32
timestamp uint32
checkSum uint32
version uint32
reserved uint32
seq uint32
length uint32
cmd []byte
}
type protoReq struct {
Header protoHeader
Body []byte
}
type protoResp struct {
Header protoHeader
Body []byte
}
// Args .
type Args struct {
Header *Header `json:"header"`
Body interface{} `json:"body"`
HTTP interface{} `json:"http"`
}
// Reply .
type Reply struct {
Code int `json:"code"`
Message string `json:"msg"`
Data json.RawMessage `json:"data"`
}

View File

@@ -0,0 +1,43 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_test",
"go_library",
)
go_test(
name = "go_default_test",
srcs = ["client_test.go"],
rundir = ".",
tags = ["automanaged"],
deps = [
"//library/net/rpc/liverpc:go_default_library",
"//library/net/rpc/liverpc/testdata:go_default_library",
"//library/net/rpc/liverpc/testdata/v1:go_default_library",
"//library/net/rpc/liverpc/testdata/v2:go_default_library",
"//vendor/github.com/pkg/errors:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)
go_library(
name = "go_default_library",
srcs = ["client.go"],
importpath = "go-common/library/net/rpc/liverpc/test",
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@@ -0,0 +1,2 @@
// Package liverpc . used to suppress warning: no non-test Go files
package liverpc

View File

@@ -0,0 +1,181 @@
// to avoid recycle imports,
// the test must be in different package with liverpc...
// otherwise, test import => generated pb
// generated pb => import liverpc (which includes the test)
package liverpc
import (
"context"
"math/rand"
"testing"
"time"
"go-common/library/net/rpc/liverpc"
"go-common/library/net/rpc/liverpc/testdata"
v1 "go-common/library/net/rpc/liverpc/testdata/v1"
v2 "go-common/library/net/rpc/liverpc/testdata/v2"
"github.com/pkg/errors"
)
func TestDialClient(t *testing.T) {
cli := testdata.New(nil)
var req = &v1.RoomGetInfoReq{Id: 1002}
var hd = &liverpc.Header{
Platform: "ios",
Src: "test",
Buvid: "AUTO3315341311353015",
TraceId: "18abb1a2596c43ea:18abb1a2596c43ea:0:0",
Uid: 10,
Caller: "live-api.rpc",
UserIp: "127.0.0.1",
SourceGroup: "default",
}
var ctx = context.TODO()
reply, err := cli.V1Room.GetInfo(ctx, req, &liverpc.HeaderOption{Header: hd})
if err != nil {
t.Error(err)
t.FailNow()
}
t.Logf("reply:%v %v %v", reply.Code, reply.Msg, reply.Data)
_, err = cli.GetRawCli().CallRaw(context.TODO(), 2, "Room.get_by_ids", &liverpc.Args{})
if err != nil {
t.Error(err)
t.FailNow()
}
}
func TestCallRaw(t *testing.T) {
var cli = liverpc.NewClient(&liverpc.ClientConfig{AppID: "live.room"})
var hd = &liverpc.Header{
Platform: "ios",
Src: "test",
Buvid: "AUTO3315341311353015",
TraceId: "18abb1a2596c43ea:18abb1a2596c43ea:0:0",
Uid: 10,
Caller: "live-api.rpc",
UserIp: "127.0.0.1",
SourceGroup: "default",
}
var req = &liverpc.Args{Body: map[string]interface{}{"id": 1002}, Header: hd}
hd = nil
reply, err := cli.CallRaw(context.TODO(), 1, "Room.get_info", req, &liverpc.TimeoutOption{Timeout: 200 * time.Millisecond})
if err != nil {
t.Error(err)
t.FailNow()
}
t.Logf("reply:%v %v %v", reply.Code, reply.Message, string(reply.Data))
_, err = cli.CallRaw(context.TODO(), 1, "Room.get_info", req, &liverpc.TimeoutOption{Timeout: 2 * time.Millisecond})
if err == nil {
t.Error(errors.New("should fail"))
t.FailNow()
}
}
func TestMap(t *testing.T) {
client := liverpc.NewClient(&liverpc.ClientConfig{AppID: "live.room"})
var rpcClient = v2.NewRoomRPCClient(client)
var req = &v2.RoomGetByIdsReq{Ids: []int64{1002}}
var header = &liverpc.Header{
Platform: "ios",
Src: "test",
Buvid: "AUTO3315341311353015",
TraceId: "18abb1a2596c43ea:18abb1a2596c43ea:0:0",
Uid: 10,
Caller: "live-api.rpc",
UserIp: "127.0.0.1",
SourceGroup: "default",
}
var ctx = context.TODO()
reply, err := rpcClient.GetByIds(ctx, req, liverpc.HeaderOption{Header: header})
if err != nil {
t.Error(err)
t.FailNow()
}
t.Logf("reply:%v %v %v", reply.Code, reply.Msg, reply.Data)
}
func TestDiscoveryClient(t *testing.T) {
conf := &liverpc.ClientConfig{
AppID: "live.room",
}
cli := liverpc.NewClient(conf)
arg := &v1.RoomGetInfoReq{Id: 1001}
var rpcClient = v1.NewRoomRPCClient(cli)
reply, err := rpcClient.GetInfo(context.TODO(), arg)
if err != nil {
t.Error(err)
t.FailNow()
}
t.Logf("reply:%+v", reply)
}
func TestCancel(t *testing.T) {
conf := &liverpc.ClientConfig{
AppID: "live.room",
}
cli := liverpc.NewClient(conf)
arg := &v1.RoomGetInfoReq{Id: 1001}
var rpcClient = v1.NewRoomRPCClient(cli)
ctx, cancel := context.WithTimeout(context.TODO(), time.Millisecond)
defer cancel()
var err error
_, err = rpcClient.GetInfo(ctx, arg)
if err == nil || errors.Cause(err) != context.DeadlineExceeded {
t.Error(err)
t.FailNow()
}
}
func TestCallRawCancel(t *testing.T) {
var cli = liverpc.NewClient(&liverpc.ClientConfig{AppID: "live.room"})
var hd = &liverpc.Header{
Platform: "ios",
Src: "test",
Buvid: "AUTO3315341311353015",
TraceId: "18abb1a2596c43ea:18abb1a2596c43ea:0:0",
Uid: 10,
Caller: "live-api.rpc",
UserIp: "127.0.0.1",
SourceGroup: "default",
}
var req = &liverpc.Args{Body: map[string]interface{}{"id": 1002}, Header: hd}
hd = nil
ctx, cancel := context.WithTimeout(context.TODO(), time.Millisecond)
defer cancel()
_, err := cli.CallRaw(ctx, 1, "Room.get_info", req)
if err == nil || errors.Cause(err) != context.DeadlineExceeded {
t.Error(err)
t.FailNow()
}
t.Logf("err is +%v", err)
}
func BenchmarkDialClient(b *testing.B) {
rand.Seed(time.Now().UnixNano())
var header = &liverpc.Header{
Platform: "ios",
Src: "test",
Buvid: "AUTO3315341311353015",
TraceId: "18abb1a2596c43ea:18abb1a2596c43ea:0:0",
Uid: 10,
Caller: "live-api.rpc",
UserIp: "127.0.0.1",
SourceGroup: "default",
}
var ctx = context.TODO()
for i := 0; i < b.N; i++ { //use b.N for looping
id := rand.Intn(10000)
arg := &v1.RoomGetInfoReq{Id: int64(id)}
cli := liverpc.NewClient(&liverpc.ClientConfig{AppID: "live.room"})
var rpcClient = v1.NewRoomRPCClient(cli)
_, err := rpcClient.GetInfo(ctx, arg, liverpc.HeaderOption{Header: header})
if err != nil {
b.Errorf("%s %d", err, i)
b.FailNow()
}
}
}

37
library/net/rpc/liverpc/testdata/BUILD vendored Normal file
View File

@@ -0,0 +1,37 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
)
go_library(
name = "go_default_library",
srcs = ["client.go"],
importpath = "go-common/library/net/rpc/liverpc/testdata",
tags = ["manual"],
visibility = ["//visibility:public"],
deps = [
"//library/net/rpc/liverpc:go_default_library",
"//library/net/rpc/liverpc/testdata/v1:go_default_library",
"//library/net/rpc/liverpc/testdata/v2:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [
":package-srcs",
"//library/net/rpc/liverpc/testdata/v1:all-srcs",
"//library/net/rpc/liverpc/testdata/v2:all-srcs",
],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@@ -0,0 +1,46 @@
// Code generated by liverpcgen, DO NOT EDIT.
// source: *.proto files under this directory
// If you want to change this file, Please see README in go-common/app/tool/liverpc/protoc-gen-liverpc/
package testdata
import (
"go-common/library/net/rpc/liverpc"
"go-common/library/net/rpc/liverpc/testdata/v1"
"go-common/library/net/rpc/liverpc/testdata/v2"
)
// Client that represents a liverpc room service api
type Client struct {
cli *liverpc.Client
// V1Room presents the controller in liverpc
V1Room v1.RoomRPCClient
// V2Room presents the controller in liverpc
V2Room v2.RoomRPCClient
}
// DiscoveryAppId the discovery id is not the tree name
var DiscoveryAppId = "live.room"
// New a Client that represents a liverpc live.room service api
// conf can be empty, and it will use discovery to find service by default
// conf.AppID will be overwrite by a fixed value DiscoveryAppId
// therefore is no need to set
func New(conf *liverpc.ClientConfig) *Client {
if conf == nil {
conf = &liverpc.ClientConfig{}
}
conf.AppID = DiscoveryAppId
var realCli = liverpc.NewClient(conf)
cli := &Client{cli: realCli}
cli.clientInit(realCli)
return cli
}
func (cli *Client) GetRawCli() *liverpc.Client {
return cli.cli
}
func (cli *Client) clientInit(realCli *liverpc.Client) {
cli.V1Room = v1.NewRoomRPCClient(realCli)
cli.V2Room = v2.NewRoomRPCClient(realCli)
}

View File

@@ -0,0 +1,53 @@
load(
"@io_bazel_rules_go//proto:def.bzl",
"go_proto_library",
)
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
)
proto_library(
name = "v1_proto",
srcs = ["Room.proto"],
tags = ["automanaged"],
)
go_proto_library(
name = "v1_go_proto",
compilers = ["@io_bazel_rules_go//proto:go_grpc"],
importpath = "go-common/library/net/rpc/liverpc/testdata/v1",
proto = ":v1_proto",
tags = ["automanaged"],
)
go_library(
name = "go_default_library",
srcs = ["Room.liverpc.go"],
embed = [":v1_go_proto"],
importpath = "go-common/library/net/rpc/liverpc/testdata/v1",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//library/net/rpc/liverpc:go_default_library",
"@com_github_gogo_protobuf//proto:go_default_library",
"@com_github_golang_protobuf//proto:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@@ -0,0 +1,73 @@
// Code generated by protoc-gen-liverpc v0.1, DO NOT EDIT.
// source: v1/Room.proto
/*
Package v1 is a generated liverpc stub package.
This code was generated with go-common/app/tool/liverpc/protoc-gen-liverpc v0.1.
It is generated from these files:
v1/Room.proto
*/
package v1
import context "context"
import proto "github.com/golang/protobuf/proto"
import "go-common/library/net/rpc/liverpc"
var _ proto.Message // generate to suppress unused imports
// Imports only used by utility functions:
// ==============
// Room Interface
// ==============
type RoomRPCClient interface {
// * 根据房间id获取房间信息
GetInfoById(ctx context.Context, req *RoomGetInfoByIdReq, opts ...liverpc.CallOption) (resp *RoomGetInfoByIdResp, err error)
// * 获取房间基本信息接口,前端/移动端房间页使用
GetInfo(ctx context.Context, req *RoomGetInfoReq, opts ...liverpc.CallOption) (resp *RoomGetInfoResp, err error)
}
// ====================
// Room Live Rpc Client
// ====================
type roomRPCClient struct {
client *liverpc.Client
}
// NewRoomRPCClient creates a client that implements the RoomRPCClient interface.
func NewRoomRPCClient(client *liverpc.Client) RoomRPCClient {
return &roomRPCClient{
client: client,
}
}
func (c *roomRPCClient) GetInfoById(ctx context.Context, in *RoomGetInfoByIdReq, opts ...liverpc.CallOption) (*RoomGetInfoByIdResp, error) {
out := new(RoomGetInfoByIdResp)
err := doRPCRequest(ctx, c.client, 1, "Room.get_info_by_id", in, out, opts)
if err != nil {
return nil, err
}
return out, nil
}
func (c *roomRPCClient) GetInfo(ctx context.Context, in *RoomGetInfoReq, opts ...liverpc.CallOption) (*RoomGetInfoResp, error) {
out := new(RoomGetInfoResp)
err := doRPCRequest(ctx, c.client, 1, "Room.get_info", in, out, opts)
if err != nil {
return nil, err
}
return out, nil
}
// =====
// Utils
// =====
func doRPCRequest(ctx context.Context, client *liverpc.Client, version int, method string, in, out proto.Message, opts []liverpc.CallOption) (err error) {
err = client.Call(ctx, version, method, in, out, opts...)
return
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,119 @@
syntax = "proto3";
package room.v1;
option go_package = "v1";
service Room {
/** 根据房间id获取房间信息
*
*/
rpc get_info_by_id (RoomGetInfoByIdReq) returns (RoomGetInfoByIdResp);
/** 获取房间基本信息接口,前端/移动端房间页使用
*
*/
rpc get_info (RoomGetInfoReq) returns (RoomGetInfoResp);
}
message RoomGetInfoByIdReq {
repeated int64 ids = 1; // 房间id, 可以为短号
repeated string fields = 2; // 需要哪些字段, 不传默认所有
}
message RoomGetInfoByIdResp {
int64 code = 1; // code
string msg = 2; // msg
map<string, RoomInfo> data = 3; // 房间信息map
message RoomInfo {
int64 roomid = 1; // 房间id
string uname = 2; // 用户名, 不可靠.
string cover = 3; // 封面
int64 uid = 4; // 用户id
string live_time = 5; // 开播时间
int64 round_status = 6; // 轮播状态
int64 on_flag = 7; // 是否开播
string title = 8; // 直播间标题
string lock_status = 9; // 锁定到时间
string hidden_status = 10; // 隐藏到时间
string user_cover = 11; // 也是封面...
int64 short_id = 12; // 短号
int64 online = 13; // 在线人数
int64 area = 14; // 分区id
int64 area_v2_id = 15; // 分区v2 id
int64 area_v2_parent_id = 16; // 分区v2 父分区id
string area_v2_name = 17; // 分区v2名字 fields加了该字段才会给
string area_v2_parent_name = 18; // 分区v2父分区名字 fields加了该字段才会给
int64 attentions = 19; // 关注人数
}
}
message RoomGetInfoReq {
int64 id = 1; // 房间号或者短号
string from = 2; // 来源 房间页room link中心 link_center
}
message RoomGetInfoResp {
int64 code = 1; // code
string msg = 2; // msg
Data data = 3; //
message PendantWithDesc {
string name = 1; // 名字、标识
int64 position = 2; // 位置0无1左上2右上3右下4左下
string value = 3; // name对应的value可以是挂件的展示名字/对应的图片地址
string desc = 4; // 描述
}
message Pendant {
string name = 1; // 名字、标识
int64 position = 2; // 位置0无1左上2右上3右下4左下
string value = 3; // name对应的value可以是挂件的展示名字/对应的图片地址
}
message Pendants {
PendantWithDesc frame = 1; // web端房间页头像边框
PendantWithDesc badge = 2; // web端房间页头像角标
Pendant mobile_frame = 3; // 移动端房间页头像边框
Pendant mobile_badge = 4; // 移动端房间页头像角标
}
message Data {
int64 uid = 1; //
int64 room_id = 2; // 房间id
int64 short_id = 3; // 短号
string keyframe = 4; // 关键帧
int64 online = 5; // 在线人数
bool is_portrait = 6; // true为竖屏
string room_silent_type = 7; // 禁言类型 member medal level 或者空字符串
int64 room_silent_second = 8; // 剩余禁言时间,秒数
int64 room_silent_level = 9; // 禁言等级
int64 live_status = 10; // 闲置中0 直播中1 轮播中2
int64 area_id = 11; // 分区id
int64 parent_area_id = 12; // 父分区id
string area_name = 13; // 分区名字
string parent_area_name = 14; // 父分区名字
int64 old_area_id = 15; // 老分区id
string background = 16; // 背景url
string title = 17; // 房间标题
bool is_strict_room = 18; // 是否是限制房间 如果是 应该不连接弹幕 不展示礼物等等
string user_cover = 19; // 房间封面
string live_time = 20; // 开播时间
string pendants = 21; // 挂件列表
string area_pendants = 22; // 分区第一标志, 待定.
string description = 23; // 房间简介.
string tags = 24; // 房间标签, 逗号分隔字符串
string verify = 25; // 认证信息 没认证为空字符串
repeated string hot_words = 26; // 弹幕热词
int64 allow_change_area_time = 27; // 允许修改分区时间戳(主播可能被审核禁止修改分区),0表示没有限制 主播才有此字段
int64 allow_upload_cover_time = 28; // 允许上传封面的时间 0表示没有限制 主播才有此字段gs
Pendants new_pendants = 29; // 新挂件
string up_session = 30; // 一次开播标记
int64 pk_status = 31; // 0为该房间不处于pk中 1表示处于pk中(需调用pk基础信息接口获取pk信息)
}
}

View File

@@ -0,0 +1,53 @@
load(
"@io_bazel_rules_go//proto:def.bzl",
"go_proto_library",
)
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
)
proto_library(
name = "v2_proto",
srcs = ["Room.proto"],
tags = ["automanaged"],
)
go_proto_library(
name = "v2_go_proto",
compilers = ["@io_bazel_rules_go//proto:go_grpc"],
importpath = "go-common/library/net/rpc/liverpc/testdata/v2",
proto = ":v2_proto",
tags = ["automanaged"],
)
go_library(
name = "go_default_library",
srcs = ["Room.liverpc.go"],
embed = [":v2_go_proto"],
importpath = "go-common/library/net/rpc/liverpc/testdata/v2",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//library/net/rpc/liverpc:go_default_library",
"@com_github_gogo_protobuf//proto:go_default_library",
"@com_github_golang_protobuf//proto:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@@ -0,0 +1,62 @@
// Code generated by protoc-gen-liverpc v0.1, DO NOT EDIT.
// source: v2/Room.proto
/*
Package v2 is a generated liverpc stub package.
This code was generated with go-common/app/tool/liverpc/protoc-gen-liverpc v0.1.
It is generated from these files:
v2/Room.proto
*/
package v2
import context "context"
import proto "github.com/golang/protobuf/proto"
import "go-common/library/net/rpc/liverpc"
var _ proto.Message // generate to suppress unused imports
// Imports only used by utility functions:
// ==============
// Room Interface
// ==============
type RoomRPCClient interface {
// * 根据房间id获取房间信息v2
// 修正原来的get_info_by_id 在传了fields字段但是不包含roomid的情况下 依然会返回所有字段, 新版修正这个问题, 只会返回指定的字段.
GetByIds(ctx context.Context, req *RoomGetByIdsReq, opts ...liverpc.CallOption) (resp *RoomGetByIdsResp, err error)
}
// ====================
// Room Live Rpc Client
// ====================
type roomRPCClient struct {
client *liverpc.Client
}
// NewRoomRPCClient creates a client that implements the RoomRPCClient interface.
func NewRoomRPCClient(client *liverpc.Client) RoomRPCClient {
return &roomRPCClient{
client: client,
}
}
func (c *roomRPCClient) GetByIds(ctx context.Context, in *RoomGetByIdsReq, opts ...liverpc.CallOption) (*RoomGetByIdsResp, error) {
out := new(RoomGetByIdsResp)
err := doRPCRequest(ctx, c.client, 2, "Room.get_by_ids", in, out, opts)
if err != nil {
return nil, err
}
return out, nil
}
// =====
// Utils
// =====
func doRPCRequest(ctx context.Context, client *liverpc.Client, version int, method string, in, out proto.Message, opts []liverpc.CallOption) (err error) {
err = client.Call(ctx, version, method, in, out, opts...)
return
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,61 @@
syntax = "proto3";
package room.v2;
option go_package = "v2";
service Room {
/** 根据房间id获取房间信息v2
* 修正原来的get_info_by_id 在传了fields字段但是不包含roomid的情况下 依然会返回所有字段, 新版修正这个问题, 只会返回指定的字段.
*/
rpc get_by_ids (RoomGetByIdsReq) returns (RoomGetByIdsResp);
}
message RoomGetByIdsReq {
repeated int64 ids = 1; // 房间id, 尽可能传长号支持短号eg.短号1->长号40000则返回的房间信息map key是40000
int64 need_uinfo = 2; // 是否需要附加uname、face字段need_uinfo=1 尽量别传,传了请和@小卫报备!!
int64 need_broadcast_type = 3; // 是否需要broadcast_type字段need_broadcast_type=1
repeated string fields = 4; // 需要哪些字段, 不传默认给大多数字段
string from = 5; // 调用方来源英文格式约定部门_服务_业务 eg.live_activity_spring
}
message RoomGetByIdsResp {
int64 code = 1; // code
string msg = 2; // msg
map<string, RoomInfo> data = 3; // 房间信息map
message RoomInfo {
int64 roomid = 1; // 房间id
string uname = 2; // 用户名
string face = 3; // 用户头像
string verify = 4; // 加v认证信息
string cover = 5; // 关键帧 注need_uinfo=1时该字段优先表示封面图
int64 uid = 6; // 用户id
string live_time = 7; // 开播时间
int64 round_status = 8; // 轮播投递状态 1开启 0关闭
int64 on_flag = 9; // 轮播开启状态 1开启 0关闭
string title = 10; // 直播间标题
string tags = 11; // 直播间标签
string lock_status = 12; // 锁定到时间
string hidden_status = 13; // 隐藏到时间
string user_cover = 14; // 封面
int64 short_id = 15; // 短号
int64 online = 16; // 在线人数
int64 area = 17; // 分区id
int64 area_v2_id = 18; // 分区v2 id
int64 area_v2_parent_id = 19; // 分区v2 父分区id
int64 area_pk_status = 20; // 分区是否开放pk 0关闭 1开放
string area_v2_name = 21; // 分区v2名字
string area_v2_parent_name = 22; // 分区v2父分区名字
int64 attentions = 23; // 关注人数
string background = 24; // 房间背景图
int64 room_silent = 25; // 是否静默 0否,1注册会员,2全部
int64 room_shield = 26; // 是否使用房主的屏蔽用户作为房间全局屏蔽用户0不使用1使用
string try_time = 27; // 试用直播间到期时间
int64 live_status = 28; // 直播间状态 0关播 1直播中 2轮播中
int64 broadcast_type = 29; // 横竖屏只有传了need_broadcast_type才会返回 0横屏 1竖屏 -1异常情况
}
}