上传rpc 双向通信封装
This commit is contained in:
parent
a54dcebfe9
commit
ea84fb817c
@ -74,7 +74,6 @@ type IRPCXServiceSession interface {
|
|||||||
|
|
||||||
type IRPCXService interface {
|
type IRPCXService interface {
|
||||||
IClusterServiceBase
|
IClusterServiceBase
|
||||||
Register(rcvr interface{}) (err error)
|
|
||||||
RegisterFunction(fn interface{}) (err error)
|
RegisterFunction(fn interface{}) (err error)
|
||||||
RegisterFunctionName(name string, fn interface{}) (err error)
|
RegisterFunctionName(name string, fn interface{}) (err error)
|
||||||
RpcCall(ctx context.Context, servicePath string, serviceMethod string, args interface{}, reply interface{}) (err error)
|
RpcCall(ctx context.Context, servicePath string, serviceMethod string, args interface{}, reply interface{}) (err error)
|
||||||
|
@ -121,12 +121,6 @@ func (this *RPCXService) Destroy() (err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
//注册服务对象
|
|
||||||
func (this *RPCXService) Register(rcvr interface{}) (err error) {
|
|
||||||
err = rpcx.Register(rcvr)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
//注册服务方法
|
//注册服务方法
|
||||||
func (this *RPCXService) RegisterFunction(fn interface{}) (err error) {
|
func (this *RPCXService) RegisterFunction(fn interface{}) (err error) {
|
||||||
err = rpcx.RegisterFunction(fn)
|
err = rpcx.RegisterFunction(fn)
|
||||||
|
@ -3,45 +3,105 @@ package rpcx
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"net"
|
||||||
|
"reflect"
|
||||||
|
"runtime"
|
||||||
"strings"
|
"strings"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
"unicode"
|
||||||
|
"unicode/utf8"
|
||||||
|
|
||||||
"github.com/smallnest/rpcx/client"
|
"github.com/smallnest/rpcx/client"
|
||||||
|
"github.com/smallnest/rpcx/protocol"
|
||||||
"github.com/smallnest/rpcx/share"
|
"github.com/smallnest/rpcx/share"
|
||||||
)
|
)
|
||||||
|
|
||||||
func newClient(rpcx *RPCX) (c *Client) {
|
func newClient(options Options) (sys *Client, err error) {
|
||||||
c = &Client{
|
sys = &Client{
|
||||||
rpcx: rpcx,
|
options: options,
|
||||||
clients: make(map[string]client.XClient),
|
metadata: fmt.Sprintf("stype=%s&sid=%s&version=%s&addr=%s", options.ServiceType, options.ServiceId, options.ServiceVersion, "tcp@"+options.ServiceAddr),
|
||||||
// msgChan: make(chan *protocol.Message, 1000),
|
clients: make(map[string]client.XClient),
|
||||||
|
conns: make(map[string]net.Conn),
|
||||||
|
serviceMap: make(map[string]*service),
|
||||||
|
msgChan: make(chan *protocol.Message, 1000),
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
type Client struct {
|
type Client struct {
|
||||||
rpcx *RPCX
|
options Options
|
||||||
clients map[string]client.XClient
|
metadata string
|
||||||
// msgChan chan *protocol.Message // 接收rpcXServer推送消息
|
writeTimeout time.Duration
|
||||||
|
AsyncWrite bool
|
||||||
|
clients map[string]client.XClient
|
||||||
|
connsMapMu sync.RWMutex
|
||||||
|
conns map[string]net.Conn
|
||||||
|
serviceMapMu sync.RWMutex
|
||||||
|
serviceMap map[string]*service
|
||||||
|
msgChan chan *protocol.Message // 接收rpcXServer推送消息
|
||||||
}
|
}
|
||||||
|
|
||||||
// DoMessage 服务端消息处理
|
// DoMessage 服务端消息处理
|
||||||
func (this *Client) DoMessage() {
|
func (this *Client) DoMessage() {
|
||||||
// for msg := range this.msgChan {
|
for msg := range this.msgChan {
|
||||||
|
go func(req *protocol.Message) {
|
||||||
// }
|
this.Debugf("DoMessage ServicePath:%s ServiceMethod:%s", req.ServicePath, req.ServiceMethod)
|
||||||
|
addr, ok := req.Metadata[ServiceAddrKey]
|
||||||
|
if !ok {
|
||||||
|
this.Errorf("Metadata no found ServiceAddrKey!")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
conn, ok := this.conns[addr]
|
||||||
|
if !ok {
|
||||||
|
this.Errorf("no found conn addr:%s", addr)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
res, _ := this.handleRequest(context.Background(), req)
|
||||||
|
this.sendResponse(conn, req, res)
|
||||||
|
}(msg)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//启动RPC 服务 接收消息处理
|
||||||
func (this *Client) Start() (err error) {
|
func (this *Client) Start() (err error) {
|
||||||
|
go this.DoMessage()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//停止RPC 服务
|
||||||
func (this *Client) Stop() (err error) {
|
func (this *Client) Stop() (err error) {
|
||||||
for _, v := range this.clients {
|
for _, v := range this.clients {
|
||||||
v.Close()
|
v.Close()
|
||||||
}
|
}
|
||||||
|
close(this.msgChan) //关闭消息处理
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//注册Rpc 服务
|
||||||
|
func (this *Client) RegisterFunction(fn interface{}) (err error) {
|
||||||
|
_, err = this.registerFunction(this.options.ServiceType, fn, "", false)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
//注册Rpc 服务
|
||||||
|
func (this *Client) RegisterFunctionName(name string, fn interface{}) (err error) {
|
||||||
|
_, err = this.registerFunction(this.options.ServiceType, fn, name, true)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
//注销 暂不处理
|
||||||
|
func (this *Client) UnregisterAll() (err error) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
//同步调用
|
//同步调用
|
||||||
func (this *Client) Call(ctx context.Context, servicePath string, serviceMethod string, args interface{}, reply interface{}) (err error) {
|
func (this *Client) Call(ctx context.Context, servicePath string, serviceMethod string, args interface{}, reply interface{}) (err error) {
|
||||||
if servicePath == "" {
|
if servicePath == "" {
|
||||||
@ -56,17 +116,19 @@ func (this *Client) Call(ctx context.Context, servicePath string, serviceMethod
|
|||||||
)
|
)
|
||||||
spath = strings.Split(servicePath, "/")
|
spath = strings.Split(servicePath, "/")
|
||||||
if c, ok = this.clients[spath[0]]; !ok {
|
if c, ok = this.clients[spath[0]]; !ok {
|
||||||
if d, err = client.NewConsulDiscovery(this.rpcx.options.ServiceTag, spath[0], this.rpcx.options.ConsulServers, nil); err != nil {
|
if d, err = client.NewConsulDiscovery(this.options.ServiceTag, spath[0], this.options.ConsulServers, nil); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
c = client.NewXClient(spath[0], client.Failfast, client.RandomSelect, d, client.DefaultOption)
|
c = client.NewBidirectionalXClient(spath[0], client.Failfast, client.RandomSelect, d, client.DefaultOption, this.msgChan)
|
||||||
|
c.GetPlugins().Add(this)
|
||||||
c.SetSelector(newSelector())
|
c.SetSelector(newSelector())
|
||||||
this.clients[spath[0]] = c
|
this.clients[spath[0]] = c
|
||||||
|
|
||||||
}
|
}
|
||||||
ctx = context.WithValue(ctx, share.ReqMetaDataKey, map[string]string{
|
ctx = context.WithValue(ctx, share.ReqMetaDataKey, map[string]string{
|
||||||
CallRoutRulesKey: servicePath,
|
CallRoutRulesKey: servicePath,
|
||||||
ServiceAddrKey: "tcp@" + this.rpcx.options.ServiceAddr,
|
ServiceAddrKey: "tcp@" + this.options.ServiceAddr,
|
||||||
ServiceMetaKey: this.rpcx.metadata,
|
ServiceMetaKey: this.metadata,
|
||||||
})
|
})
|
||||||
err = c.Call(ctx, serviceMethod, args, reply)
|
err = c.Call(ctx, serviceMethod, args, reply)
|
||||||
return
|
return
|
||||||
@ -87,17 +149,327 @@ func (this *Client) Go(ctx context.Context, servicePath string, serviceMethod st
|
|||||||
)
|
)
|
||||||
spath = strings.Split(servicePath, "/")
|
spath = strings.Split(servicePath, "/")
|
||||||
if c, ok = this.clients[spath[0]]; !ok {
|
if c, ok = this.clients[spath[0]]; !ok {
|
||||||
if d, err = client.NewConsulDiscovery(this.rpcx.options.ServiceTag, spath[0], this.rpcx.options.ConsulServers, nil); err != nil {
|
if d, err = client.NewConsulDiscovery(this.options.ServiceTag, spath[0], this.options.ConsulServers, nil); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
c = client.NewXClient(spath[0], client.Failfast, client.RandomSelect, d, client.DefaultOption)
|
c = client.NewXClient(spath[0], client.Failfast, client.RandomSelect, d, client.DefaultOption)
|
||||||
|
c.GetPlugins().Add(this)
|
||||||
c.SetSelector(newSelector())
|
c.SetSelector(newSelector())
|
||||||
this.clients[spath[0]] = c
|
this.clients[spath[0]] = c
|
||||||
}
|
}
|
||||||
ctx = context.WithValue(ctx, share.ReqMetaDataKey, map[string]string{
|
ctx = context.WithValue(ctx, share.ReqMetaDataKey, map[string]string{
|
||||||
CallRoutRulesKey: servicePath,
|
CallRoutRulesKey: servicePath,
|
||||||
ServiceAddrKey: "tcp@" + this.rpcx.options.ServiceAddr,
|
ServiceAddrKey: "tcp@" + this.options.ServiceAddr,
|
||||||
ServiceMetaKey: this.rpcx.metadata,
|
ServiceMetaKey: this.metadata,
|
||||||
})
|
})
|
||||||
return c.Go(ctx, string(serviceMethod), args, reply, done)
|
return c.Go(ctx, string(serviceMethod), args, reply, done)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//监控连接建立
|
||||||
|
func (this *Client) ClientConnected(conn net.Conn) (net.Conn, error) {
|
||||||
|
addr := "tcp@" + conn.RemoteAddr().String()
|
||||||
|
this.connsMapMu.Lock()
|
||||||
|
this.conns[addr] = conn
|
||||||
|
this.connsMapMu.Unlock()
|
||||||
|
return conn, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
//监听连接关闭
|
||||||
|
func (this *Client) ClientConnectionClose(conn net.Conn) error {
|
||||||
|
addr := "tcp@" + conn.RemoteAddr().String()
|
||||||
|
this.connsMapMu.Lock()
|
||||||
|
delete(this.conns, addr)
|
||||||
|
this.connsMapMu.Unlock()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
///日志***********************************************************************
|
||||||
|
func (this *Client) Debug() bool {
|
||||||
|
return this.options.Debug
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *Client) Debugf(format string, a ...interface{}) {
|
||||||
|
if this.options.Debug {
|
||||||
|
this.options.Log.Debugf("[SYS RPCX] "+format, a...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *Client) Infof(format string, a ...interface{}) {
|
||||||
|
if this.options.Debug {
|
||||||
|
this.options.Log.Infof("[SYS RPCX] "+format, a...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *Client) Warnf(format string, a ...interface{}) {
|
||||||
|
if this.options.Debug {
|
||||||
|
this.options.Log.Warnf("[SYS RPCX] "+format, a...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *Client) Errorf(format string, a ...interface{}) {
|
||||||
|
if this.options.Debug {
|
||||||
|
this.options.Log.Errorf("[SYS RPCX] "+format, a...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *Client) Panicf(format string, a ...interface{}) {
|
||||||
|
if this.options.Debug {
|
||||||
|
this.options.Log.Panicf("[SYS RPCX] "+format, a...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *Client) Fatalf(format string, a ...interface{}) {
|
||||||
|
if this.options.Debug {
|
||||||
|
this.options.Log.Fatalf("[SYS RPCX] "+format, a...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//注册服务方法
|
||||||
|
func (this *Client) registerFunction(servicePath string, fn interface{}, name string, useName bool) (string, error) {
|
||||||
|
this.serviceMapMu.Lock()
|
||||||
|
defer this.serviceMapMu.Unlock()
|
||||||
|
|
||||||
|
ss := this.serviceMap[servicePath]
|
||||||
|
if ss == nil {
|
||||||
|
ss = new(service)
|
||||||
|
ss.name = servicePath
|
||||||
|
ss.function = make(map[string]*functionType)
|
||||||
|
}
|
||||||
|
|
||||||
|
f, ok := fn.(reflect.Value)
|
||||||
|
if !ok {
|
||||||
|
f = reflect.ValueOf(fn)
|
||||||
|
}
|
||||||
|
if f.Kind() != reflect.Func {
|
||||||
|
return "", errors.New("function must be func or bound method")
|
||||||
|
}
|
||||||
|
|
||||||
|
fname := runtime.FuncForPC(reflect.Indirect(f).Pointer()).Name()
|
||||||
|
if fname != "" {
|
||||||
|
i := strings.LastIndex(fname, ".")
|
||||||
|
if i >= 0 {
|
||||||
|
fname = fname[i+1:]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if useName {
|
||||||
|
fname = name
|
||||||
|
}
|
||||||
|
if fname == "" {
|
||||||
|
errorStr := "rpcx.registerFunction: no func name for type " + f.Type().String()
|
||||||
|
this.Errorf(errorStr)
|
||||||
|
return fname, errors.New(errorStr)
|
||||||
|
}
|
||||||
|
|
||||||
|
t := f.Type()
|
||||||
|
if t.NumIn() != 3 {
|
||||||
|
return fname, fmt.Errorf("rpcx.registerFunction: has wrong number of ins: %s", f.Type().String())
|
||||||
|
}
|
||||||
|
if t.NumOut() != 1 {
|
||||||
|
return fname, fmt.Errorf("rpcx.registerFunction: has wrong number of outs: %s", f.Type().String())
|
||||||
|
}
|
||||||
|
|
||||||
|
// First arg must be context.Context
|
||||||
|
ctxType := t.In(0)
|
||||||
|
if !ctxType.Implements(typeOfContext) {
|
||||||
|
return fname, fmt.Errorf("function %s must use context as the first parameter", f.Type().String())
|
||||||
|
}
|
||||||
|
|
||||||
|
argType := t.In(1)
|
||||||
|
if !isExportedOrBuiltinType(argType) {
|
||||||
|
return fname, fmt.Errorf("function %s parameter type not exported: %v", f.Type().String(), argType)
|
||||||
|
}
|
||||||
|
|
||||||
|
replyType := t.In(2)
|
||||||
|
if replyType.Kind() != reflect.Ptr {
|
||||||
|
return fname, fmt.Errorf("function %s reply type not a pointer: %s", f.Type().String(), replyType)
|
||||||
|
}
|
||||||
|
if !isExportedOrBuiltinType(replyType) {
|
||||||
|
return fname, fmt.Errorf("function %s reply type not exported: %v", f.Type().String(), replyType)
|
||||||
|
}
|
||||||
|
|
||||||
|
// The return type of the method must be error.
|
||||||
|
if returnType := t.Out(0); returnType != typeOfError {
|
||||||
|
return fname, fmt.Errorf("function %s returns %s, not error", f.Type().String(), returnType.String())
|
||||||
|
}
|
||||||
|
|
||||||
|
// Install the methods
|
||||||
|
ss.function[fname] = &functionType{fn: f, ArgType: argType, ReplyType: replyType}
|
||||||
|
this.serviceMap[servicePath] = ss
|
||||||
|
|
||||||
|
// init pool for reflect.Type of args and reply
|
||||||
|
reflectTypePools.Init(argType)
|
||||||
|
reflectTypePools.Init(replyType)
|
||||||
|
return fname, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
//处理远程服务请求
|
||||||
|
func (this *Client) handleRequest(ctx context.Context, req *protocol.Message) (res *protocol.Message, err error) {
|
||||||
|
serviceName := req.ServicePath
|
||||||
|
methodName := req.ServiceMethod
|
||||||
|
|
||||||
|
res = req.Clone()
|
||||||
|
res.SetMessageType(protocol.Response)
|
||||||
|
this.serviceMapMu.RLock()
|
||||||
|
service := this.serviceMap[serviceName]
|
||||||
|
this.serviceMapMu.RUnlock()
|
||||||
|
if service == nil {
|
||||||
|
err = errors.New("rpcx: can't find service " + serviceName)
|
||||||
|
return handleError(res, err)
|
||||||
|
}
|
||||||
|
mtype := service.method[methodName]
|
||||||
|
if mtype == nil {
|
||||||
|
if service.function[methodName] != nil { // check raw functions
|
||||||
|
return this.handleRequestForFunction(ctx, req)
|
||||||
|
}
|
||||||
|
err = errors.New("rpcx: can't find method " + methodName)
|
||||||
|
return handleError(res, err)
|
||||||
|
}
|
||||||
|
// get a argv object from object pool
|
||||||
|
argv := reflectTypePools.Get(mtype.ArgType)
|
||||||
|
|
||||||
|
codec := share.Codecs[req.SerializeType()]
|
||||||
|
if codec == nil {
|
||||||
|
err = fmt.Errorf("can not find codec for %d", req.SerializeType())
|
||||||
|
return handleError(res, err)
|
||||||
|
}
|
||||||
|
err = codec.Decode(req.Payload, argv)
|
||||||
|
if err != nil {
|
||||||
|
return handleError(res, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// and get a reply object from object pool
|
||||||
|
replyv := reflectTypePools.Get(mtype.ReplyType)
|
||||||
|
if mtype.ArgType.Kind() != reflect.Ptr {
|
||||||
|
err = service.call(ctx, mtype, reflect.ValueOf(argv).Elem(), reflect.ValueOf(replyv))
|
||||||
|
} else {
|
||||||
|
err = service.call(ctx, mtype, reflect.ValueOf(argv), reflect.ValueOf(replyv))
|
||||||
|
}
|
||||||
|
reflectTypePools.Put(mtype.ArgType, argv)
|
||||||
|
if err != nil {
|
||||||
|
if replyv != nil {
|
||||||
|
data, err := codec.Encode(replyv)
|
||||||
|
// return reply to object pool
|
||||||
|
reflectTypePools.Put(mtype.ReplyType, replyv)
|
||||||
|
if err != nil {
|
||||||
|
return handleError(res, err)
|
||||||
|
}
|
||||||
|
res.Payload = data
|
||||||
|
}
|
||||||
|
return handleError(res, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !req.IsOneway() {
|
||||||
|
data, err := codec.Encode(replyv)
|
||||||
|
// return reply to object pool
|
||||||
|
reflectTypePools.Put(mtype.ReplyType, replyv)
|
||||||
|
if err != nil {
|
||||||
|
return handleError(res, err)
|
||||||
|
}
|
||||||
|
res.Payload = data
|
||||||
|
} else if replyv != nil {
|
||||||
|
reflectTypePools.Put(mtype.ReplyType, replyv)
|
||||||
|
}
|
||||||
|
this.Debugf("server called service %+v for an request %+v", service, req)
|
||||||
|
return res, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
//处理远程服务请求 for 方法
|
||||||
|
func (this *Client) handleRequestForFunction(ctx context.Context, req *protocol.Message) (res *protocol.Message, err error) {
|
||||||
|
res = req.Clone()
|
||||||
|
|
||||||
|
res.SetMessageType(protocol.Response)
|
||||||
|
|
||||||
|
serviceName := req.ServicePath
|
||||||
|
methodName := req.ServiceMethod
|
||||||
|
this.serviceMapMu.RLock()
|
||||||
|
service := this.serviceMap[serviceName]
|
||||||
|
this.serviceMapMu.RUnlock()
|
||||||
|
if service == nil {
|
||||||
|
err = errors.New("rpcx: can't find service for func raw function")
|
||||||
|
return handleError(res, err)
|
||||||
|
}
|
||||||
|
mtype := service.function[methodName]
|
||||||
|
if mtype == nil {
|
||||||
|
err = errors.New("rpcx: can't find method " + methodName)
|
||||||
|
return handleError(res, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
argv := reflectTypePools.Get(mtype.ArgType)
|
||||||
|
|
||||||
|
codec := share.Codecs[req.SerializeType()]
|
||||||
|
if codec == nil {
|
||||||
|
err = fmt.Errorf("can not find codec for %d", req.SerializeType())
|
||||||
|
return handleError(res, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = codec.Decode(req.Payload, argv)
|
||||||
|
if err != nil {
|
||||||
|
return handleError(res, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
replyv := reflectTypePools.Get(mtype.ReplyType)
|
||||||
|
|
||||||
|
if mtype.ArgType.Kind() != reflect.Ptr {
|
||||||
|
err = service.callForFunction(ctx, mtype, reflect.ValueOf(argv).Elem(), reflect.ValueOf(replyv))
|
||||||
|
} else {
|
||||||
|
err = service.callForFunction(ctx, mtype, reflect.ValueOf(argv), reflect.ValueOf(replyv))
|
||||||
|
}
|
||||||
|
|
||||||
|
reflectTypePools.Put(mtype.ArgType, argv)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
reflectTypePools.Put(mtype.ReplyType, replyv)
|
||||||
|
return handleError(res, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !req.IsOneway() {
|
||||||
|
data, err := codec.Encode(replyv)
|
||||||
|
reflectTypePools.Put(mtype.ReplyType, replyv)
|
||||||
|
if err != nil {
|
||||||
|
return handleError(res, err)
|
||||||
|
}
|
||||||
|
res.Payload = data
|
||||||
|
} else if replyv != nil {
|
||||||
|
reflectTypePools.Put(mtype.ReplyType, replyv)
|
||||||
|
}
|
||||||
|
|
||||||
|
return res, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
//发送远程服务调用 回应消息
|
||||||
|
func (this *Client) sendResponse(conn net.Conn, req, res *protocol.Message) {
|
||||||
|
if len(res.Payload) > 1024 && req.CompressType() != protocol.None {
|
||||||
|
res.SetCompressType(req.CompressType())
|
||||||
|
}
|
||||||
|
data := res.EncodeSlicePointer()
|
||||||
|
if this.writeTimeout != 0 {
|
||||||
|
conn.SetWriteDeadline(time.Now().Add(this.writeTimeout))
|
||||||
|
}
|
||||||
|
conn.Write(*data)
|
||||||
|
protocol.PutData(data)
|
||||||
|
}
|
||||||
|
|
||||||
|
//请求错误 封装回应消息
|
||||||
|
func handleError(res *protocol.Message, err error) (*protocol.Message, error) {
|
||||||
|
res.SetMessageStatusType(protocol.Error)
|
||||||
|
if res.Metadata == nil {
|
||||||
|
res.Metadata = make(map[string]string)
|
||||||
|
}
|
||||||
|
res.Metadata[protocol.ServiceError] = err.Error()
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
|
|
||||||
|
//服务注册 类型判断
|
||||||
|
func isExportedOrBuiltinType(t reflect.Type) bool {
|
||||||
|
for t.Kind() == reflect.Ptr {
|
||||||
|
t = t.Elem()
|
||||||
|
}
|
||||||
|
// PkgPath will be non-empty even for an exported type,
|
||||||
|
// so we need to check the type name as well.
|
||||||
|
return isExported(t.Name()) || t.PkgPath() == ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func isExported(name string) bool {
|
||||||
|
rune, _ := utf8.DecodeRuneInString(name)
|
||||||
|
return unicode.IsUpper(rune)
|
||||||
|
}
|
||||||
|
@ -16,21 +16,12 @@ const (
|
|||||||
|
|
||||||
type (
|
type (
|
||||||
ISys interface {
|
ISys interface {
|
||||||
IRPCXServer
|
|
||||||
IRPCXClient
|
|
||||||
}
|
|
||||||
IRPCXServer interface {
|
|
||||||
Start() (err error)
|
Start() (err error)
|
||||||
Stop() (err error)
|
Stop() (err error)
|
||||||
Register(rcvr interface{}) (err error)
|
// Register(rcvr interface{}) (err error)
|
||||||
RegisterFunction(fn interface{}) (err error)
|
RegisterFunction(fn interface{}) (err error)
|
||||||
RegisterFunctionName(name string, fn interface{}) (err error)
|
RegisterFunctionName(name string, fn interface{}) (err error)
|
||||||
UnregisterAll() (err error)
|
UnregisterAll() (err error)
|
||||||
}
|
|
||||||
|
|
||||||
IRPCXClient interface {
|
|
||||||
Start() (err error)
|
|
||||||
Stop() (err error)
|
|
||||||
Call(ctx context.Context, servicePath string, serviceMethod string, args interface{}, reply interface{}) (err error)
|
Call(ctx context.Context, servicePath string, serviceMethod string, args interface{}, reply interface{}) (err error)
|
||||||
Go(ctx context.Context, servicePath string, serviceMethod string, args interface{}, reply interface{}, done chan *client.Call) (call *client.Call, err error)
|
Go(ctx context.Context, servicePath string, serviceMethod string, args interface{}, reply interface{}, done chan *client.Call) (call *client.Call, err error)
|
||||||
}
|
}
|
||||||
@ -66,9 +57,9 @@ func Stop() (err error) {
|
|||||||
return defsys.Stop()
|
return defsys.Stop()
|
||||||
}
|
}
|
||||||
|
|
||||||
func Register(rcvr interface{}) (err error) {
|
// func Register(rcvr interface{}) (err error) {
|
||||||
return defsys.Register(rcvr)
|
// return defsys.Register(rcvr)
|
||||||
}
|
// }
|
||||||
func RegisterFunction(fn interface{}) (err error) {
|
func RegisterFunction(fn interface{}) (err error) {
|
||||||
return defsys.RegisterFunction(fn)
|
return defsys.RegisterFunction(fn)
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,8 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"go_dreamfactory/lego/sys/log"
|
"go_dreamfactory/lego/sys/log"
|
||||||
"go_dreamfactory/lego/utils/mapstructure"
|
"go_dreamfactory/lego/utils/mapstructure"
|
||||||
|
|
||||||
|
"github.com/smallnest/rpcx/protocol"
|
||||||
)
|
)
|
||||||
|
|
||||||
type RpcxStartType int8
|
type RpcxStartType int8
|
||||||
@ -23,7 +25,8 @@ type Options struct {
|
|||||||
ServiceAddr string //服务地址
|
ServiceAddr string //服务地址
|
||||||
ConsulServers []string //Consul集群服务地址
|
ConsulServers []string //Consul集群服务地址
|
||||||
RpcxStartType RpcxStartType //Rpcx启动类型
|
RpcxStartType RpcxStartType //Rpcx启动类型
|
||||||
Debug bool //日志是否开启
|
SerializeType protocol.SerializeType
|
||||||
|
Debug bool //日志是否开启
|
||||||
Log log.ILog
|
Log log.ILog
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -63,6 +66,13 @@ func SetConsulServers(v []string) Option {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//设置启动类型
|
||||||
|
func SetRpcxStartType(v RpcxStartType) Option {
|
||||||
|
return func(o *Options) {
|
||||||
|
o.RpcxStartType = v
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func SetDebug(v bool) Option {
|
func SetDebug(v bool) Option {
|
||||||
return func(o *Options) {
|
return func(o *Options) {
|
||||||
o.Debug = v
|
o.Debug = v
|
||||||
@ -76,8 +86,9 @@ func SetLog(v log.ILog) Option {
|
|||||||
|
|
||||||
func newOptions(config map[string]interface{}, opts ...Option) (Options, error) {
|
func newOptions(config map[string]interface{}, opts ...Option) (Options, error) {
|
||||||
options := Options{
|
options := Options{
|
||||||
Debug: true,
|
SerializeType: protocol.MsgPack,
|
||||||
Log: log.Clone(log.SetLoglayer(2)),
|
Debug: true,
|
||||||
|
Log: log.Clone(log.SetLoglayer(2)),
|
||||||
}
|
}
|
||||||
if config != nil {
|
if config != nil {
|
||||||
mapstructure.Decode(config, &options)
|
mapstructure.Decode(config, &options)
|
||||||
@ -93,8 +104,9 @@ func newOptions(config map[string]interface{}, opts ...Option) (Options, error)
|
|||||||
|
|
||||||
func newOptionsByOption(opts ...Option) (Options, error) {
|
func newOptionsByOption(opts ...Option) (Options, error) {
|
||||||
options := Options{
|
options := Options{
|
||||||
Debug: true,
|
SerializeType: protocol.MsgPack,
|
||||||
Log: log.Clone(log.SetLoglayer(2)),
|
Debug: true,
|
||||||
|
Log: log.Clone(log.SetLoglayer(2)),
|
||||||
}
|
}
|
||||||
for _, o := range opts {
|
for _, o := range opts {
|
||||||
o(&options)
|
o(&options)
|
||||||
|
68
lego/sys/rpcx/pools.go
Normal file
68
lego/sys/rpcx/pools.go
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
package rpcx
|
||||||
|
|
||||||
|
import (
|
||||||
|
"reflect"
|
||||||
|
"sync"
|
||||||
|
)
|
||||||
|
|
||||||
|
var UsePool bool
|
||||||
|
|
||||||
|
type Reset interface {
|
||||||
|
Reset()
|
||||||
|
}
|
||||||
|
|
||||||
|
var reflectTypePools = &typePools{
|
||||||
|
pools: make(map[reflect.Type]*sync.Pool),
|
||||||
|
New: func(t reflect.Type) interface{} {
|
||||||
|
var argv reflect.Value
|
||||||
|
|
||||||
|
if t.Kind() == reflect.Ptr { // reply must be ptr
|
||||||
|
argv = reflect.New(t.Elem())
|
||||||
|
} else {
|
||||||
|
argv = reflect.New(t)
|
||||||
|
}
|
||||||
|
|
||||||
|
return argv.Interface()
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
type typePools struct {
|
||||||
|
mu sync.RWMutex
|
||||||
|
pools map[reflect.Type]*sync.Pool
|
||||||
|
New func(t reflect.Type) interface{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *typePools) Init(t reflect.Type) {
|
||||||
|
tp := &sync.Pool{}
|
||||||
|
tp.New = func() interface{} {
|
||||||
|
return p.New(t)
|
||||||
|
}
|
||||||
|
p.mu.Lock()
|
||||||
|
defer p.mu.Unlock()
|
||||||
|
p.pools[t] = tp
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *typePools) Put(t reflect.Type, x interface{}) {
|
||||||
|
if !UsePool {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if o, ok := x.(Reset); ok {
|
||||||
|
o.Reset()
|
||||||
|
}
|
||||||
|
|
||||||
|
p.mu.RLock()
|
||||||
|
pool := p.pools[t]
|
||||||
|
p.mu.RUnlock()
|
||||||
|
pool.Put(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *typePools) Get(t reflect.Type) interface{} {
|
||||||
|
if !UsePool {
|
||||||
|
return p.New(t)
|
||||||
|
}
|
||||||
|
p.mu.RLock()
|
||||||
|
pool := p.pools[t]
|
||||||
|
p.mu.RUnlock()
|
||||||
|
|
||||||
|
return pool.Get()
|
||||||
|
}
|
@ -2,33 +2,36 @@ package rpcx
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"github.com/smallnest/rpcx/client"
|
"github.com/smallnest/rpcx/client"
|
||||||
)
|
)
|
||||||
|
|
||||||
func newSys(options Options) (sys *RPCX, err error) {
|
func newSys(options Options) (sys ISys, err error) {
|
||||||
sys = &RPCX{
|
if options.RpcxStartType == RpcxStartByService { //创建RPCX 服务端
|
||||||
options: options,
|
sys, err = newService(options)
|
||||||
metadata: fmt.Sprintf("stype=%s&sid=%s&version=%s&addr=%s", options.ServiceType, options.ServiceId, options.ServiceVersion, "tcp@"+options.ServiceAddr),
|
return
|
||||||
}
|
}
|
||||||
sys.service, err = newService(sys)
|
|
||||||
sys.client = newClient(sys)
|
|
||||||
// if options.RpcxStartType == RpcxStartByAll || options.RpcxStartType == RpcxStartByService { //创建RPCX 服务端
|
|
||||||
|
|
||||||
// }
|
if options.RpcxStartType == RpcxStartByClient { //创建RPCX 客户端
|
||||||
|
sys, err = newClient(options)
|
||||||
// if options.RpcxStartType == RpcxStartByAll || options.RpcxStartType == RpcxStartByClient { //创建RPCX 客户端
|
return
|
||||||
|
}
|
||||||
// }
|
var (
|
||||||
|
service ISys
|
||||||
|
client ISys
|
||||||
|
)
|
||||||
|
service, err = newService(options)
|
||||||
|
client, err = newClient(options)
|
||||||
|
sys = &RPCX{
|
||||||
|
service: service,
|
||||||
|
client: client,
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
type RPCX struct {
|
type RPCX struct {
|
||||||
options Options
|
service ISys
|
||||||
metadata string
|
client ISys
|
||||||
service IRPCXServer
|
|
||||||
client IRPCXClient
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (this *RPCX) Start() (err error) {
|
func (this *RPCX) Start() (err error) {
|
||||||
@ -43,11 +46,6 @@ func (this *RPCX) Stop() (err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (this *RPCX) Register(rcvr interface{}) (err error) {
|
|
||||||
this.service.Register(rcvr)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func (this *RPCX) RegisterFunction(fn interface{}) (err error) {
|
func (this *RPCX) RegisterFunction(fn interface{}) (err error) {
|
||||||
this.service.RegisterFunction(fn)
|
this.service.RegisterFunction(fn)
|
||||||
return
|
return
|
||||||
@ -71,45 +69,3 @@ func (this *RPCX) Call(ctx context.Context, servicePath string, serviceMethod st
|
|||||||
func (this *RPCX) Go(ctx context.Context, servicePath string, serviceMethod string, args interface{}, reply interface{}, done chan *client.Call) (call *client.Call, err error) {
|
func (this *RPCX) Go(ctx context.Context, servicePath string, serviceMethod string, args interface{}, reply interface{}, done chan *client.Call) (call *client.Call, err error) {
|
||||||
return this.client.Go(ctx, servicePath, serviceMethod, args, reply, done)
|
return this.client.Go(ctx, servicePath, serviceMethod, args, reply, done)
|
||||||
}
|
}
|
||||||
|
|
||||||
// func (this *RPCX) PostCall(ctx context.Context, serviceName, methodName string, args, reply interface{}) (interface{}, error) {
|
|
||||||
// clientConn := ctx.Value(server.RemoteConnContextKey).(net.Conn)
|
|
||||||
// fmt.Printf("PostCall servicePath:%v serviceMethod:%v RemoteAddr:%v \n", serviceName, methodName, clientConn.RemoteAddr().String())
|
|
||||||
// return args, nil
|
|
||||||
// }
|
|
||||||
|
|
||||||
///日志***********************************************************************
|
|
||||||
func (this *RPCX) Debug() bool {
|
|
||||||
return this.options.Debug
|
|
||||||
}
|
|
||||||
|
|
||||||
func (this *RPCX) Debugf(format string, a ...interface{}) {
|
|
||||||
if this.options.Debug {
|
|
||||||
this.options.Log.Debugf("[SYS RPCX] "+format, a...)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
func (this *RPCX) Infof(format string, a ...interface{}) {
|
|
||||||
if this.options.Debug {
|
|
||||||
this.options.Log.Infof("[SYS RPCX] "+format, a...)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
func (this *RPCX) Warnf(format string, a ...interface{}) {
|
|
||||||
if this.options.Debug {
|
|
||||||
this.options.Log.Warnf("[SYS RPCX] "+format, a...)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
func (this *RPCX) Errorf(format string, a ...interface{}) {
|
|
||||||
if this.options.Debug {
|
|
||||||
this.options.Log.Errorf("[SYS RPCX] "+format, a...)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
func (this *RPCX) Panicf(format string, a ...interface{}) {
|
|
||||||
if this.options.Debug {
|
|
||||||
this.options.Log.Panicf("[SYS RPCX] "+format, a...)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
func (this *RPCX) Fatalf(format string, a ...interface{}) {
|
|
||||||
if this.options.Debug {
|
|
||||||
this.options.Log.Fatalf("[SYS RPCX] "+format, a...)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -3,22 +3,13 @@ package rpcx
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net"
|
|
||||||
"os"
|
"os"
|
||||||
"os/signal"
|
"os/signal"
|
||||||
"regexp"
|
|
||||||
"syscall"
|
"syscall"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"go_dreamfactory/lego/sys/log"
|
"go_dreamfactory/lego/sys/log"
|
||||||
|
|
||||||
"github.com/rcrowley/go-metrics"
|
|
||||||
"github.com/smallnest/rpcx/client"
|
|
||||||
"github.com/smallnest/rpcx/protocol"
|
|
||||||
"github.com/smallnest/rpcx/server"
|
|
||||||
"github.com/smallnest/rpcx/serverplugin"
|
|
||||||
"github.com/smallnest/rpcx/share"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func Test_Sys(t *testing.T) {
|
func Test_Sys(t *testing.T) {
|
||||||
@ -37,7 +28,7 @@ func Test_Sys(t *testing.T) {
|
|||||||
fmt.Printf("err:%v", err)
|
fmt.Printf("err:%v", err)
|
||||||
return
|
return
|
||||||
} else {
|
} else {
|
||||||
if err = sys.Register(new(Arith)); err != nil {
|
if err = sys.RegisterFunction(RpcxTestHandle); err != nil {
|
||||||
fmt.Printf("err:%v", err)
|
fmt.Printf("err:%v", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -62,142 +53,15 @@ func Test_Sys(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var addr = "127.0.0.1:9978"
|
|
||||||
|
|
||||||
// go server.go
|
|
||||||
func Test_RPCX(t *testing.T) {
|
|
||||||
s := server.NewServer()
|
|
||||||
if err := addRegistryPlugin(s); err != nil {
|
|
||||||
fmt.Printf("err:%v", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
go func() {
|
|
||||||
time.Sleep(time.Second)
|
|
||||||
s.RegisterName("worker", new(Arith), "stype=worker&sid=worker_1&version=1.0.0&addr=tcp@127.0.0.1:9978")
|
|
||||||
}()
|
|
||||||
|
|
||||||
go func() {
|
|
||||||
time.Sleep(time.Second * 3)
|
|
||||||
if d, err := client.NewConsulDiscovery("rpcx_test", "worker", []string{"10.0.0.9:8500"}, nil); err != nil {
|
|
||||||
fmt.Printf("NewConsulDiscovery err:%v", err)
|
|
||||||
return
|
|
||||||
} else {
|
|
||||||
xclient := client.NewXClient("worker", client.Failfast, client.RandomSelect, d, client.DefaultOption)
|
|
||||||
xclient.SetSelector(newSelector())
|
|
||||||
ctx := context.WithValue(context.Background(), share.ReqMetaDataKey, map[string]string{"RoutRules": "worker/worker_1"})
|
|
||||||
if err = xclient.Call(ctx, "Mul", &Args{A: 1, B: 2}, &Reply{}); err != nil {
|
|
||||||
fmt.Printf("Call:%v \n", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}()
|
|
||||||
|
|
||||||
s.Serve("tcp", addr)
|
|
||||||
}
|
|
||||||
|
|
||||||
func addRegistryPlugin(s *server.Server) (err error) {
|
|
||||||
r := &serverplugin.ConsulRegisterPlugin{
|
|
||||||
ServiceAddress: "tcp@" + addr,
|
|
||||||
ConsulServers: []string{"10.0.0.9:8500"},
|
|
||||||
BasePath: "rpcx_test",
|
|
||||||
Metrics: metrics.NewRegistry(),
|
|
||||||
UpdateInterval: time.Minute,
|
|
||||||
}
|
|
||||||
err = r.Start()
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
s.Plugins.Add(r)
|
|
||||||
s.Plugins.Add(&call{})
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
type call struct{}
|
|
||||||
|
|
||||||
// func (this *call) PostCall(ctx context.Context, serviceName, methodName string, args, reply interface{}) (interface{}, error) {
|
|
||||||
// clientConn := ctx.Value(server.RemoteConnContextKey).(net.Conn)
|
|
||||||
// RoutRules := ctx.Value("RoutRules")
|
|
||||||
// fmt.Printf("PostCall servicePath:%v serviceMethod:%v RoutRules:%s RemoteAddr:%v \n", serviceName, methodName, RoutRules, clientConn.RemoteAddr().String())
|
|
||||||
// return args, nil
|
|
||||||
// }
|
|
||||||
|
|
||||||
// func (this *call) PreCall(ctx context.Context, serviceName, methodName string, args interface{}) (interface{}, error) {
|
|
||||||
// clientConn := ctx.Value(server.RemoteConnContextKey).(net.Conn)
|
|
||||||
// RoutRules := ctx.Value("RoutRules").(string)
|
|
||||||
// fmt.Printf("PostCall servicePath:%v serviceMethod:%v RoutRules:%s RemoteAddr:%v \n", serviceName, methodName, RoutRules, clientConn.RemoteAddr().String())
|
|
||||||
// return args, nil
|
|
||||||
// }
|
|
||||||
|
|
||||||
// func (this *call) PreReadRequest(ctx context.Context) error {
|
|
||||||
// clientConn := ctx.Value(server.RemoteConnContextKey).(net.Conn)
|
|
||||||
// RoutRules := ctx.Value(share.ReqMetaDataKey).(map[string]string)
|
|
||||||
// fmt.Printf("PreReadRequest RoutRules:%s RemoteAddr:%v \n", RoutRules, clientConn.RemoteAddr().String())
|
|
||||||
// return nil
|
|
||||||
// }
|
|
||||||
|
|
||||||
// func (this *call) PreWriteResponse(ctx context.Context, args *protocol.Message, repy *protocol.Message, errInter error) error {
|
|
||||||
// clientConn := ctx.Value(server.RemoteConnContextKey).(net.Conn)
|
|
||||||
// RoutRules := ctx.Value("RoutRules").(string)
|
|
||||||
// fmt.Printf("PreReadRequest RoutRules:%s RemoteAddr:%v \n", RoutRules, clientConn.RemoteAddr().String())
|
|
||||||
// return nil
|
|
||||||
// }
|
|
||||||
|
|
||||||
func (this *call) PreHandleRequest(ctx context.Context, r *protocol.Message) error {
|
|
||||||
clientConn := ctx.Value(server.RemoteConnContextKey).(net.Conn)
|
|
||||||
RoutRules := ctx.Value(share.ReqMetaDataKey).(map[string]string)
|
|
||||||
fmt.Printf("PreReadRequest RoutRules:%s RemoteAddr:%v \n", RoutRules, clientConn.RemoteAddr().String())
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type Args struct {
|
type Args struct {
|
||||||
A int
|
A int
|
||||||
B int
|
B int
|
||||||
}
|
}
|
||||||
|
|
||||||
type Reply struct {
|
type Reply struct {
|
||||||
C int
|
Error string
|
||||||
}
|
}
|
||||||
|
|
||||||
type Arith int
|
func RpcxTestHandle(ctx context.Context, args *Args, reply *Reply) error {
|
||||||
|
fmt.Printf("A:%d + B:%d = %d", args.A, args.B, args.A+args.B)
|
||||||
func (t *Arith) Mul(ctx context.Context, args *Args, reply *Reply) error {
|
|
||||||
reply.C = args.A * args.B
|
|
||||||
fmt.Printf("call: %d * %d = %d\n", args.A, args.B, reply.C)
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *Arith) Add(ctx context.Context, args *Args, reply *Reply) error {
|
|
||||||
reply.C = args.A + args.B
|
|
||||||
fmt.Printf("call: %d + %d = %d\n", args.A, args.B, reply.C)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *Arith) Say(ctx context.Context, args *string, reply *string) error {
|
|
||||||
*reply = "hello " + *args
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
///正则测试
|
|
||||||
func Test_Regular(t *testing.T) {
|
|
||||||
// str1 := "worker"
|
|
||||||
// str2 := "worker/worker_1"
|
|
||||||
// str3 := "worker/!worker_1"
|
|
||||||
// str4 := "worker/[worker_1,worker_2]"
|
|
||||||
// str5 := "worker/![worker_1,worker_2]"
|
|
||||||
|
|
||||||
// reg1 := regexp.MustCompile(`/`)
|
|
||||||
//根据规则提取关键信息
|
|
||||||
// result1 := reg1.FindAllStringSubmatch(str1, -1)
|
|
||||||
// fmt.Println("result1 = ", result1)
|
|
||||||
// strings.Split()
|
|
||||||
|
|
||||||
str := "worker/!worker_1"
|
|
||||||
// rex := regexp.MustCompile(`\!\[([^)]+)\]`)
|
|
||||||
rex := regexp.MustCompile(`\!([^)]+)`)
|
|
||||||
out := rex.FindAllStringSubmatch(str, -1)
|
|
||||||
|
|
||||||
for _, i := range out {
|
|
||||||
fmt.Println(i[1])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -2,136 +2,338 @@ package rpcx
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"go_dreamfactory/lego/sys/log"
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
"net"
|
"net"
|
||||||
|
"strings"
|
||||||
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/rcrowley/go-metrics"
|
"github.com/rcrowley/go-metrics"
|
||||||
"github.com/smallnest/rpcx/client"
|
"github.com/smallnest/rpcx/client"
|
||||||
|
"github.com/smallnest/rpcx/protocol"
|
||||||
"github.com/smallnest/rpcx/server"
|
"github.com/smallnest/rpcx/server"
|
||||||
"github.com/smallnest/rpcx/serverplugin"
|
"github.com/smallnest/rpcx/serverplugin"
|
||||||
|
"github.com/smallnest/rpcx/share"
|
||||||
)
|
)
|
||||||
|
|
||||||
func newService(rpcx *RPCX) (s *Service, err error) {
|
func newService(options Options) (sys *Service, err error) {
|
||||||
s = &Service{
|
sys = &Service{
|
||||||
server: server.NewServer(),
|
options: options,
|
||||||
rpcx: rpcx,
|
metadata: fmt.Sprintf("stype=%s&sid=%s&version=%s&addr=%s", options.ServiceType, options.ServiceId, options.ServiceVersion, "tcp@"+options.ServiceAddr),
|
||||||
// clients: make(map[string]net.Conn),
|
server: server.NewServer(),
|
||||||
// clientmeta: make(map[string]string),
|
selector: newSelector(),
|
||||||
|
clients: make(map[string]net.Conn),
|
||||||
|
clientmeta: make(map[string]string),
|
||||||
|
pending: make(map[uint64]*client.Call),
|
||||||
}
|
}
|
||||||
|
|
||||||
r := &serverplugin.ConsulRegisterPlugin{
|
r := &serverplugin.ConsulRegisterPlugin{
|
||||||
ServiceAddress: "tcp@" + rpcx.options.ServiceAddr,
|
ServiceAddress: "tcp@" + options.ServiceAddr,
|
||||||
ConsulServers: rpcx.options.ConsulServers,
|
ConsulServers: options.ConsulServers,
|
||||||
BasePath: rpcx.options.ServiceTag,
|
BasePath: options.ServiceTag,
|
||||||
Metrics: metrics.NewRegistry(),
|
Metrics: metrics.NewRegistry(),
|
||||||
UpdateInterval: time.Minute,
|
UpdateInterval: time.Minute,
|
||||||
}
|
}
|
||||||
if err = r.Start(); err != nil {
|
if err = r.Start(); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
s.server.Plugins.Add(r)
|
sys.server.Plugins.Add(r)
|
||||||
|
sys.server.Plugins.Add(sys)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
type Service struct {
|
type Service struct {
|
||||||
rpcx *RPCX
|
options Options
|
||||||
server *server.Server
|
metadata string
|
||||||
selector client.Selector
|
server *server.Server
|
||||||
clients map[string]net.Conn
|
selector client.Selector
|
||||||
clientmeta map[string]string
|
clientmutex sync.Mutex
|
||||||
|
clients map[string]net.Conn
|
||||||
|
clientmeta map[string]string
|
||||||
|
mutex sync.Mutex // protects following
|
||||||
|
seq uint64
|
||||||
|
pending map[uint64]*client.Call
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//RPC 服务启动
|
||||||
func (this *Service) Start() (err error) {
|
func (this *Service) Start() (err error) {
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
if err = this.server.Serve("tcp", this.rpcx.options.ServiceAddr); err != nil {
|
if err = this.server.Serve("tcp", this.options.ServiceAddr); err != nil {
|
||||||
log.Errorf("rpcx server exit!")
|
this.Errorf("rpcx server exit!")
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//服务停止
|
||||||
func (this *Service) Stop() (err error) {
|
func (this *Service) Stop() (err error) {
|
||||||
err = this.server.Close()
|
err = this.server.Close()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (this *Service) Register(rcvr interface{}) (err error) {
|
//注册RPC 服务
|
||||||
err = this.server.RegisterName(this.rpcx.options.ServiceType, rcvr, this.rpcx.metadata)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func (this *Service) RegisterFunction(fn interface{}) (err error) {
|
func (this *Service) RegisterFunction(fn interface{}) (err error) {
|
||||||
err = this.server.RegisterFunction(this.rpcx.options.ServiceType, fn, this.rpcx.metadata)
|
err = this.server.RegisterFunction(this.options.ServiceType, fn, this.metadata)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//注册RPC 服务
|
||||||
func (this *Service) RegisterFunctionName(name string, fn interface{}) (err error) {
|
func (this *Service) RegisterFunctionName(name string, fn interface{}) (err error) {
|
||||||
err = this.server.RegisterFunctionName(this.rpcx.options.ServiceType, name, fn, this.rpcx.metadata)
|
err = this.server.RegisterFunctionName(this.options.ServiceType, name, fn, this.metadata)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//注销 暂时不处理
|
||||||
func (this *Service) UnregisterAll() (err error) {
|
func (this *Service) UnregisterAll() (err error) {
|
||||||
err = this.server.UnregisterAll()
|
// err = this.server.UnregisterAll()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
//同步调用
|
//同步调用远程服务
|
||||||
func (this *Service) Call(servicePath string, ctx context.Context, serviceMethod string, args interface{}, reply interface{}) (err error) {
|
func (this *Service) Call(ctx context.Context, servicePath string, serviceMethod string, args interface{}, reply interface{}) (err error) {
|
||||||
// var (
|
var (
|
||||||
// spath string
|
done *client.Call
|
||||||
// clientaddr string
|
conn net.Conn
|
||||||
// conn net.Conn
|
)
|
||||||
// ok bool
|
seq := new(uint64)
|
||||||
// )
|
ctx = context.WithValue(ctx, seqKey{}, seq)
|
||||||
// if servicePath == "" {
|
if conn, done, err = this.call(ctx, servicePath, serviceMethod, args, reply, make(chan *client.Call, 1)); err != nil {
|
||||||
// err = errors.New("servicePath no cant null")
|
return
|
||||||
// return
|
}
|
||||||
// }
|
select {
|
||||||
// spath := strings.Split(servicePath, "/")
|
case <-ctx.Done(): // cancel by context
|
||||||
// ctx = context.WithValue(ctx, share.ReqMetaDataKey, map[string]string{
|
this.mutex.Lock()
|
||||||
// CallRoutRulesKey: servicePath,
|
call := this.pending[*seq]
|
||||||
// ServiceAddrKey: "tcp@" + this.options.ServiceAddr,
|
delete(this.pending, *seq)
|
||||||
// ServiceMetaKey: this.metadata,
|
this.mutex.Unlock()
|
||||||
// })
|
if call != nil {
|
||||||
// if clientaddr = this.selector.Select(ctx, spath[0], serviceMethod, args); clientaddr == "" {
|
call.Error = ctx.Err()
|
||||||
// err = fmt.Errorf("on found routRules:%s", routRules)
|
call.Done <- call
|
||||||
// return
|
}
|
||||||
// }
|
return ctx.Err()
|
||||||
// if conn, ok = this.clients[clientaddr]; !ok {
|
case call := <-done.Done:
|
||||||
// err = fmt.Errorf("on found clientaddr:%s", clientaddr)
|
err = call.Error
|
||||||
// return
|
meta := ctx.Value(share.ResMetaDataKey)
|
||||||
// }
|
if meta != nil && len(call.ResMetadata) > 0 {
|
||||||
// err := this.server.SendMessage(conn, spath[0], serviceMethod, nil, []byte("abcde")){
|
resMeta := meta.(map[string]string)
|
||||||
|
for k, v := range call.ResMetadata {
|
||||||
// }
|
resMeta[k] = v
|
||||||
|
}
|
||||||
|
resMeta[share.ServerAddress] = conn.RemoteAddr().String()
|
||||||
|
}
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
//异步调用
|
//异步调用 远程服务
|
||||||
func (this *Service) Go(routRules string, ctx context.Context, serviceMethod string, args interface{}, reply interface{}) (err error) {
|
func (this *Service) Go(ctx context.Context, servicePath string, serviceMethod string, args interface{}, reply interface{}, done chan *client.Call) (_call *client.Call, err error) {
|
||||||
|
_, _call, err = this.call(ctx, servicePath, serviceMethod, args, reply, done)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
//发现服务
|
//监听客户端链接到服务上 保存客户端的连接对象
|
||||||
func (this *Service) Discovery(addr string, conn net.Conn, meta string) {
|
func (this *Service) PreHandleRequest(ctx context.Context, r *protocol.Message) error {
|
||||||
this.clientmeta[addr] = meta
|
req_metadata := ctx.Value(share.ReqMetaDataKey).(map[string]string)
|
||||||
this.clients[addr] = conn
|
if addr, ok := req_metadata[ServiceAddrKey]; ok {
|
||||||
this.selector.UpdateServer(this.clientmeta)
|
if _, ok = this.clientmeta[addr]; !ok {
|
||||||
|
if smeta, ok := req_metadata[ServiceMetaKey]; ok {
|
||||||
|
servers := make(map[string]string)
|
||||||
|
this.clientmutex.Lock()
|
||||||
|
this.clientmeta[addr] = smeta
|
||||||
|
this.clients[addr] = ctx.Value(server.RemoteConnContextKey).(net.Conn)
|
||||||
|
for k, v := range this.clientmeta {
|
||||||
|
servers[k] = v
|
||||||
|
}
|
||||||
|
this.clientmutex.Unlock()
|
||||||
|
this.selector.UpdateServer(servers)
|
||||||
|
this.Debugf("PreReadRequest addr:%s smeta:%s \n", addr, smeta)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// //监听客户端链接到服务上 保存客户端的连接对象
|
//监控rpc连接收到的请求消息 处理消息回调请求
|
||||||
// func (this *Service) PreHandleRequest(ctx context.Context, r *protocol.Message) error {
|
func (this *Service) PostReadRequest(ctx context.Context, r *protocol.Message, e error) error {
|
||||||
// if smeta, ok := ctx.Value(share.ReqMetaDataKey).(map[string]string)[ServiceAddrKey]; ok {
|
if isCallMessage := (r.MessageType() == protocol.Request); isCallMessage {
|
||||||
// // log.Errorf("smeta:%s err:%v", smeta, ok)
|
return nil
|
||||||
// if node, err := smetaToServiceNode(smeta); err == nil {
|
}
|
||||||
// if _, ok = this.clientmeta[node.ServiceId]; !ok {
|
e = errors.New("is callMessage")
|
||||||
// this.clientmeta[node.ServiceId] = smeta
|
seq := r.Seq()
|
||||||
// }
|
this.mutex.Lock()
|
||||||
// }
|
call := this.pending[seq]
|
||||||
// }
|
delete(this.pending, seq)
|
||||||
|
this.mutex.Unlock()
|
||||||
|
switch {
|
||||||
|
case call == nil:
|
||||||
|
this.Errorf("callmessage no found call:%d", seq)
|
||||||
|
case r.MessageStatusType() == protocol.Error:
|
||||||
|
if len(r.Metadata) > 0 {
|
||||||
|
call.ResMetadata = r.Metadata
|
||||||
|
call.Error = errors.New(r.Metadata[protocol.ServiceError])
|
||||||
|
}
|
||||||
|
if len(r.Payload) > 0 {
|
||||||
|
data := r.Payload
|
||||||
|
codec := share.Codecs[r.SerializeType()]
|
||||||
|
if codec != nil {
|
||||||
|
_ = codec.Decode(data, call.Reply)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
call.Done <- call
|
||||||
|
default:
|
||||||
|
data := r.Payload
|
||||||
|
if len(data) > 0 {
|
||||||
|
codec := share.Codecs[r.SerializeType()]
|
||||||
|
if codec == nil {
|
||||||
|
call.Error = errors.New(client.ErrUnsupportedCodec.Error())
|
||||||
|
} else {
|
||||||
|
err := codec.Decode(data, call.Reply)
|
||||||
|
if err != nil {
|
||||||
|
call.Error = err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(r.Metadata) > 0 {
|
||||||
|
call.ResMetadata = r.Metadata
|
||||||
|
}
|
||||||
|
call.Done <- call
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// // clientConn := ctx.Value(server.RemoteConnContextKey).(net.Conn)
|
///日志***********************************************************************
|
||||||
|
func (this *Service) Debug() bool {
|
||||||
|
return this.options.Debug
|
||||||
|
}
|
||||||
|
|
||||||
// // fmt.Printf("PreReadRequest RoutRules:%s RemoteAddr:%v \n", RoutRules, clientConn.RemoteAddr().String())
|
func (this *Service) Debugf(format string, a ...interface{}) {
|
||||||
// return nil
|
if this.options.Debug {
|
||||||
// }
|
this.options.Log.Debugf("[SYS RPCX] "+format, a...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
func (this *Service) Infof(format string, a ...interface{}) {
|
||||||
|
if this.options.Debug {
|
||||||
|
this.options.Log.Infof("[SYS RPCX] "+format, a...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
func (this *Service) Warnf(format string, a ...interface{}) {
|
||||||
|
if this.options.Debug {
|
||||||
|
this.options.Log.Warnf("[SYS RPCX] "+format, a...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
func (this *Service) Errorf(format string, a ...interface{}) {
|
||||||
|
if this.options.Debug {
|
||||||
|
this.options.Log.Errorf("[SYS RPCX] "+format, a...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
func (this *Service) Panicf(format string, a ...interface{}) {
|
||||||
|
if this.options.Debug {
|
||||||
|
this.options.Log.Panicf("[SYS RPCX] "+format, a...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
func (this *Service) Fatalf(format string, a ...interface{}) {
|
||||||
|
if this.options.Debug {
|
||||||
|
this.options.Log.Fatalf("[SYS RPCX] "+format, a...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//执行远程调用
|
||||||
|
func (this *Service) call(ctx context.Context, servicePath string, serviceMethod string, args interface{}, reply interface{}, done chan *client.Call) (conn net.Conn, _call *client.Call, err error) {
|
||||||
|
var (
|
||||||
|
spath []string
|
||||||
|
clientaddr string
|
||||||
|
metadata map[string]string
|
||||||
|
ok bool
|
||||||
|
)
|
||||||
|
if servicePath == "" {
|
||||||
|
err = errors.New("servicePath no cant null")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
metadata = map[string]string{
|
||||||
|
CallRoutRulesKey: servicePath,
|
||||||
|
ServiceAddrKey: "tcp@" + this.options.ServiceAddr,
|
||||||
|
ServiceMetaKey: this.metadata,
|
||||||
|
}
|
||||||
|
spath = strings.Split(servicePath, "/")
|
||||||
|
ctx = context.WithValue(ctx, share.ReqMetaDataKey, map[string]string{
|
||||||
|
CallRoutRulesKey: servicePath,
|
||||||
|
ServiceAddrKey: "tcp@" + this.options.ServiceAddr,
|
||||||
|
ServiceMetaKey: this.metadata,
|
||||||
|
})
|
||||||
|
if clientaddr = this.selector.Select(ctx, spath[0], serviceMethod, args); clientaddr == "" {
|
||||||
|
err = fmt.Errorf("on found servicePath:%s", servicePath)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if conn, ok = this.clients[clientaddr]; !ok {
|
||||||
|
err = fmt.Errorf("on found clientaddr:%s", clientaddr)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
_call = new(client.Call)
|
||||||
|
_call.ServicePath = servicePath
|
||||||
|
_call.ServiceMethod = serviceMethod
|
||||||
|
_call.Args = args
|
||||||
|
_call.Reply = reply
|
||||||
|
if done == nil {
|
||||||
|
done = make(chan *client.Call, 10) // buffered.
|
||||||
|
} else {
|
||||||
|
if cap(done) == 0 {
|
||||||
|
log.Panic("rpc: done channel is unbuffered")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_call.Done = done
|
||||||
|
this.send(ctx, conn, spath[0], serviceMethod, metadata, _call)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
//发送远程调用请求
|
||||||
|
func (this *Service) send(ctx context.Context, conn net.Conn, servicePath string, serviceMethod string, metadata map[string]string, call *client.Call) {
|
||||||
|
defer func() {
|
||||||
|
if call.Error != nil {
|
||||||
|
call.Done <- call
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
serializeType := this.options.SerializeType
|
||||||
|
codec := share.Codecs[serializeType]
|
||||||
|
if codec == nil {
|
||||||
|
call.Error = client.ErrUnsupportedCodec
|
||||||
|
return
|
||||||
|
}
|
||||||
|
data, err := codec.Encode(call.Args)
|
||||||
|
if err != nil {
|
||||||
|
call.Error = err
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
this.mutex.Lock()
|
||||||
|
seq := this.seq
|
||||||
|
this.seq++
|
||||||
|
this.pending[seq] = call
|
||||||
|
this.mutex.Unlock()
|
||||||
|
if cseq, ok := ctx.Value(seqKey{}).(*uint64); ok {
|
||||||
|
*cseq = seq
|
||||||
|
}
|
||||||
|
req := protocol.GetPooledMsg()
|
||||||
|
req.SetMessageType(protocol.Request)
|
||||||
|
req.SetSeq(seq)
|
||||||
|
req.SetOneway(true)
|
||||||
|
req.SetSerializeType(this.options.SerializeType)
|
||||||
|
req.ServicePath = servicePath
|
||||||
|
req.ServiceMethod = serviceMethod
|
||||||
|
req.Metadata = metadata
|
||||||
|
req.Payload = data
|
||||||
|
|
||||||
|
b := req.EncodeSlicePointer()
|
||||||
|
if _, err = conn.Write(*b); err != nil {
|
||||||
|
call.Error = err
|
||||||
|
this.mutex.Lock()
|
||||||
|
delete(this.pending, seq)
|
||||||
|
this.mutex.Unlock()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
protocol.PutData(b)
|
||||||
|
protocol.FreeMsg(req)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
87
lego/sys/rpcx/utils.go
Normal file
87
lego/sys/rpcx/utils.go
Normal file
@ -0,0 +1,87 @@
|
|||||||
|
package rpcx
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"go_dreamfactory/lego/sys/log"
|
||||||
|
"reflect"
|
||||||
|
"runtime"
|
||||||
|
"sync"
|
||||||
|
)
|
||||||
|
|
||||||
|
var typeOfError = reflect.TypeOf((*error)(nil)).Elem()
|
||||||
|
var typeOfContext = reflect.TypeOf((*context.Context)(nil)).Elem()
|
||||||
|
|
||||||
|
type seqKey struct{}
|
||||||
|
type methodType struct {
|
||||||
|
sync.Mutex // protects counters
|
||||||
|
method reflect.Method
|
||||||
|
ArgType reflect.Type
|
||||||
|
ReplyType reflect.Type
|
||||||
|
// numCalls uint
|
||||||
|
}
|
||||||
|
|
||||||
|
type functionType struct {
|
||||||
|
sync.Mutex // protects counters
|
||||||
|
fn reflect.Value
|
||||||
|
ArgType reflect.Type
|
||||||
|
ReplyType reflect.Type
|
||||||
|
}
|
||||||
|
|
||||||
|
type service struct {
|
||||||
|
name string // name of service
|
||||||
|
rcvr reflect.Value // receiver of methods for the service
|
||||||
|
typ reflect.Type // type of the receiver
|
||||||
|
method map[string]*methodType // registered methods
|
||||||
|
function map[string]*functionType // registered functions
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *service) call(ctx context.Context, mtype *methodType, argv, replyv reflect.Value) (err error) {
|
||||||
|
defer func() {
|
||||||
|
if r := recover(); r != nil {
|
||||||
|
buf := make([]byte, 4096)
|
||||||
|
n := runtime.Stack(buf, false)
|
||||||
|
buf = buf[:n]
|
||||||
|
|
||||||
|
err = fmt.Errorf("[service internal error]: %v, method: %s, argv: %+v, stack: %s",
|
||||||
|
r, mtype.method.Name, argv.Interface(), buf)
|
||||||
|
log.Errorf("err%v", err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
function := mtype.method.Func
|
||||||
|
// Invoke the method, providing a new value for the reply.
|
||||||
|
returnValues := function.Call([]reflect.Value{this.rcvr, reflect.ValueOf(ctx), argv, replyv})
|
||||||
|
// The return value for the method is an error.
|
||||||
|
errInter := returnValues[0].Interface()
|
||||||
|
if errInter != nil {
|
||||||
|
return errInter.(error)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
//执行注册方法
|
||||||
|
func (this *service) callForFunction(ctx context.Context, ft *functionType, argv, replyv reflect.Value) (err error) {
|
||||||
|
defer func() {
|
||||||
|
if r := recover(); r != nil {
|
||||||
|
buf := make([]byte, 4096)
|
||||||
|
n := runtime.Stack(buf, false)
|
||||||
|
buf = buf[:n]
|
||||||
|
|
||||||
|
// log.Errorf("failed to invoke service: %v, stacks: %s", r, string(debug.Stack()))
|
||||||
|
err = fmt.Errorf("[service internal error]: %v, function: %s, argv: %+v, stack: %s",
|
||||||
|
r, runtime.FuncForPC(ft.fn.Pointer()), argv.Interface(), buf)
|
||||||
|
log.Errorf("err:%v", err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
// Invoke the function, providing a new value for the reply.
|
||||||
|
returnValues := ft.fn.Call([]reflect.Value{reflect.ValueOf(ctx), argv, replyv})
|
||||||
|
// The return value for the method is an error.
|
||||||
|
errInter := returnValues[0].Interface()
|
||||||
|
if errInter != nil {
|
||||||
|
return errInter.(error)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
@ -3,7 +3,6 @@ package main
|
|||||||
import (
|
import (
|
||||||
"flag"
|
"flag"
|
||||||
"fmt"
|
"fmt"
|
||||||
"go_dreamfactory/modules/dbservice"
|
|
||||||
"go_dreamfactory/modules/friend"
|
"go_dreamfactory/modules/friend"
|
||||||
"go_dreamfactory/modules/mail"
|
"go_dreamfactory/modules/mail"
|
||||||
"go_dreamfactory/modules/pack"
|
"go_dreamfactory/modules/pack"
|
||||||
@ -41,7 +40,6 @@ func main() {
|
|||||||
pack.NewModule(),
|
pack.NewModule(),
|
||||||
mail.NewModule(),
|
mail.NewModule(),
|
||||||
friend.NewModule(),
|
friend.NewModule(),
|
||||||
dbservice.NewModule(),
|
|
||||||
)
|
)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user