112 lines
2.1 KiB
Go
112 lines
2.1 KiB
Go
package rpc
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"jiacrontab/pkg/proto"
|
|
"net"
|
|
"net/rpc"
|
|
"time"
|
|
|
|
"github.com/iwannay/log"
|
|
)
|
|
|
|
const (
|
|
diaTimeout = 5 * time.Second
|
|
callTimeout = 1 * time.Minute
|
|
pingDuration = 3 * time.Second
|
|
)
|
|
|
|
var (
|
|
ErrRpc = errors.New("rpc is not available")
|
|
ErrRpcTimeout = errors.New("rpc call timeout")
|
|
ErrRpcCancel = errors.New("rpc call cancel")
|
|
ErrShutdown = rpc.ErrShutdown
|
|
)
|
|
|
|
type ClientOptions struct {
|
|
Network string
|
|
Addr string
|
|
}
|
|
|
|
type Client struct {
|
|
*rpc.Client
|
|
options ClientOptions
|
|
quit chan struct{}
|
|
err error
|
|
}
|
|
|
|
func Dial(options ClientOptions) (c *Client) {
|
|
c = &Client{}
|
|
c.options = options
|
|
c.dial()
|
|
c.quit = make(chan struct{}, 100)
|
|
return c
|
|
}
|
|
|
|
func (c *Client) dial() (err error) {
|
|
conn, err := net.DialTimeout(c.options.Network, c.options.Addr, diaTimeout)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
c.Client = rpc.NewClient(conn)
|
|
return nil
|
|
}
|
|
|
|
func (c *Client) Call(serviceMethod string, ctx context.Context, args interface{}, reply interface{}) error {
|
|
if serviceMethod != PingService && serviceMethod != RegisterService {
|
|
log.Info("rpc call", c.options.Addr, serviceMethod)
|
|
}
|
|
|
|
if c.Client == nil {
|
|
return ErrRpc
|
|
}
|
|
select {
|
|
case <-ctx.Done():
|
|
return ErrRpcCancel
|
|
case call := <-c.Client.Go(serviceMethod, args, reply, make(chan *rpc.Call, 1)).Done:
|
|
return call.Error
|
|
case <-time.After(callTimeout):
|
|
return ErrRpcTimeout
|
|
}
|
|
}
|
|
|
|
func (c *Client) Error() error {
|
|
return c.err
|
|
}
|
|
|
|
func (c *Client) Close() {
|
|
c.quit <- struct{}{}
|
|
}
|
|
|
|
func (c *Client) Ping(serviceMethod string) {
|
|
var (
|
|
err error
|
|
)
|
|
for {
|
|
select {
|
|
case <-c.quit:
|
|
goto closed
|
|
default:
|
|
}
|
|
if c.Client != nil && c.err == nil {
|
|
if err = c.Call(serviceMethod, context.TODO(), &proto.EmptyArgs{}, &proto.EmptyReply{}); err != nil {
|
|
c.err = err
|
|
c.Client.Close()
|
|
log.Infof("client.Call(%s, args, reply) error (%v) \n", serviceMethod, err)
|
|
}
|
|
} else {
|
|
if err = c.dial(); err == nil {
|
|
c.err = nil
|
|
log.Info("client reconnet ", c.options.Addr)
|
|
}
|
|
}
|
|
time.Sleep(pingDuration)
|
|
}
|
|
closed:
|
|
log.Info("rpc quited", c.options.Addr)
|
|
if c.Client != nil {
|
|
c.Client.Close()
|
|
}
|
|
}
|