server-go/socket/net/client/connector.go

223 lines
4.6 KiB
Go
Raw Normal View History

2018-04-12 01:23:40 +00:00
package client
2018-04-03 08:55:48 +00:00
import (
"crypto/tls"
"fmt"
"net"
2018-04-04 05:31:10 +00:00
"sync"
2018-04-13 07:11:43 +00:00
"sync/atomic"
2018-04-03 08:55:48 +00:00
"time"
2018-04-04 05:31:10 +00:00
2018-04-04 05:47:10 +00:00
"git.loafle.net/commons/logging-go"
2018-04-12 01:23:40 +00:00
"git.loafle.net/commons/server-go/client"
2018-04-05 15:15:29 +00:00
"git.loafle.net/commons/server-go/socket"
2018-04-03 08:55:48 +00:00
)
2018-04-12 01:23:40 +00:00
type Connectors struct {
2018-04-12 05:55:01 +00:00
client.Connectors
2018-04-05 16:21:13 +00:00
socket.ClientConnHandlers
2018-04-05 15:15:29 +00:00
socket.ReadWriteHandlers
2018-04-04 13:28:35 +00:00
2018-04-14 08:49:33 +00:00
Network string `json:"network,omitempty"`
Address string `json:"address,omitempty"`
2018-04-13 11:48:45 +00:00
LocalAddress net.Addr `json:"-"`
2018-04-04 13:28:35 +00:00
stopChan chan struct{}
stopWg sync.WaitGroup
2018-04-04 05:31:10 +00:00
readChan chan []byte
writeChan chan []byte
2018-04-04 13:28:35 +00:00
disconnectedChan chan struct{}
2018-04-05 15:15:29 +00:00
reconnectedChan chan socket.Conn
2018-04-04 13:28:35 +00:00
2018-04-05 15:15:29 +00:00
crw socket.ClientReadWriter
2018-04-13 07:11:43 +00:00
validated atomic.Value
2018-04-04 05:31:10 +00:00
}
2018-04-12 01:23:40 +00:00
func (c *Connectors) Connect() (readChan <-chan []byte, writeChan chan<- []byte, err error) {
2018-04-04 05:31:10 +00:00
var (
2018-04-05 15:15:29 +00:00
conn socket.Conn
2018-04-04 05:31:10 +00:00
)
2018-04-12 05:55:01 +00:00
if nil != c.stopChan {
2018-04-12 01:23:40 +00:00
return nil, nil, fmt.Errorf("%s already connected", c.logHeader())
2018-04-04 05:31:10 +00:00
}
conn, err = c.connect()
if nil != err {
return nil, nil, err
}
c.readChan = make(chan []byte, 256)
c.writeChan = make(chan []byte, 256)
2018-04-04 13:28:35 +00:00
c.disconnectedChan = make(chan struct{})
2018-04-05 15:15:29 +00:00
c.reconnectedChan = make(chan socket.Conn)
2018-04-04 05:31:10 +00:00
c.stopChan = make(chan struct{})
2018-04-04 13:28:35 +00:00
2018-04-04 13:50:34 +00:00
c.crw.ReadwriteHandler = c
c.crw.ReadChan = c.readChan
c.crw.WriteChan = c.writeChan
c.crw.ClientStopChan = c.stopChan
c.crw.ClientStopWg = &c.stopWg
c.crw.DisconnectedChan = c.disconnectedChan
c.crw.ReconnectedChan = c.reconnectedChan
2018-04-04 13:28:35 +00:00
2018-04-04 14:10:09 +00:00
c.stopWg.Add(2)
go c.handleReconnect()
2018-04-04 13:50:34 +00:00
go c.crw.HandleConnection(conn)
2018-04-04 05:31:10 +00:00
return c.readChan, c.writeChan, nil
}
2018-04-12 01:23:40 +00:00
func (c *Connectors) Disconnect() error {
2018-04-04 05:31:10 +00:00
if c.stopChan == nil {
2018-04-12 01:23:40 +00:00
return fmt.Errorf("%s must be connected before disconnection it", c.logHeader())
2018-04-04 05:31:10 +00:00
}
close(c.stopChan)
c.stopWg.Wait()
c.stopChan = nil
return nil
}
2018-04-12 01:23:40 +00:00
func (c *Connectors) logHeader() string {
return fmt.Sprintf("Connector[%s]: ", c.Name)
2018-04-04 05:31:10 +00:00
}
2018-04-12 01:23:40 +00:00
func (c *Connectors) handleReconnect() {
2018-04-04 14:10:09 +00:00
defer func() {
c.stopWg.Done()
}()
RC_LOOP:
for {
select {
case <-c.disconnectedChan:
case <-c.stopChan:
return
}
2018-04-12 05:55:01 +00:00
if 0 >= c.GetReconnectTryTime() {
2018-04-04 14:10:09 +00:00
c.reconnectedChan <- nil
2018-04-18 12:11:52 +00:00
onDisconnected := c.OnDisconnected
if nil != onDisconnected {
onDisconnected(c)
}
2018-04-04 14:10:09 +00:00
continue RC_LOOP
}
2018-04-12 01:23:40 +00:00
logging.Logger().Debugf("%s connection lost", c.logHeader())
2018-04-04 14:21:40 +00:00
2018-04-12 05:55:01 +00:00
for indexI := 0; indexI < c.GetReconnectTryTime(); indexI++ {
2018-04-12 01:23:40 +00:00
logging.Logger().Debugf("%s trying reconnect[%d]", c.logHeader(), indexI)
2018-04-04 14:21:40 +00:00
2018-04-04 14:10:09 +00:00
conn, err := c.connect()
if nil == err {
2018-04-04 14:21:40 +00:00
logging.Logger().Debugf("reconnected")
2018-04-04 14:10:09 +00:00
c.reconnectedChan <- conn
continue RC_LOOP
}
2018-04-12 05:55:01 +00:00
time.Sleep(c.GetReconnectInterval())
2018-04-04 14:10:09 +00:00
}
2018-04-18 12:11:52 +00:00
2018-04-12 01:23:40 +00:00
logging.Logger().Debugf("%s reconnecting has been failed", c.logHeader())
2018-04-18 12:11:52 +00:00
onDisconnected := c.OnDisconnected
if nil != onDisconnected {
onDisconnected(c)
}
2018-04-04 14:10:09 +00:00
}
}
2018-04-12 01:23:40 +00:00
func (c *Connectors) connect() (socket.Conn, error) {
2018-04-04 17:08:07 +00:00
netConn, err := c.dial()
2018-04-04 05:31:10 +00:00
if nil != err {
return nil, err
}
2018-04-12 05:55:01 +00:00
conn := socket.NewConn(netConn, false, c.GetReadBufferSize(), c.GetWriteBufferSize())
2018-04-04 05:31:10 +00:00
conn.SetCloseHandler(func(code int, text string) error {
2018-04-12 01:23:40 +00:00
logging.Logger().Debugf("%s close", c.logHeader())
2018-04-04 05:31:10 +00:00
return nil
})
return conn, nil
}
2018-04-12 01:23:40 +00:00
func (c *Connectors) dial() (net.Conn, error) {
2018-04-03 08:55:48 +00:00
var deadline time.Time
2018-04-12 05:55:01 +00:00
if 0 != c.GetHandshakeTimeout() {
deadline = time.Now().Add(c.GetHandshakeTimeout())
2018-04-03 08:55:48 +00:00
}
d := &net.Dialer{
2018-04-12 05:55:01 +00:00
KeepAlive: c.GetKeepAlive(),
2018-04-03 08:55:48 +00:00
Deadline: deadline,
LocalAddr: c.LocalAddress,
}
conn, err := d.Dial(c.Network, c.Address)
if nil != err {
return nil, err
}
2018-04-12 05:55:01 +00:00
if nil != c.GetTLSConfig() {
cfg := c.GetTLSConfig().Clone()
2018-04-03 08:55:48 +00:00
tlsConn := tls.Client(conn, cfg)
if err := tlsConn.Handshake(); err != nil {
tlsConn.Close()
return nil, err
}
if !cfg.InsecureSkipVerify {
if err := tlsConn.VerifyHostname(cfg.ServerName); err != nil {
return nil, err
}
}
conn = tlsConn
}
return conn, nil
}
2018-04-12 08:19:39 +00:00
func (c *Connectors) Clone() client.Connector {
2018-04-12 05:55:01 +00:00
return &Connectors{
Connectors: *c.Connectors.Clone(),
ClientConnHandlers: *c.ClientConnHandlers.Clone(),
ReadWriteHandlers: *c.ReadWriteHandlers.Clone(),
Network: c.Network,
Address: c.Address,
LocalAddress: c.LocalAddress,
2018-04-13 07:11:43 +00:00
validated: c.validated,
2018-04-12 05:55:01 +00:00
}
}
2018-04-12 01:23:40 +00:00
func (c *Connectors) Validate() error {
2018-04-13 07:11:43 +00:00
if nil != c.validated.Load() {
return nil
}
c.validated.Store(true)
2018-04-12 05:55:01 +00:00
if err := c.Connectors.Validate(); nil != err {
return err
}
2018-04-04 13:56:14 +00:00
if err := c.ClientConnHandlers.Validate(); nil != err {
2018-04-04 13:28:35 +00:00
return err
}
if err := c.ReadWriteHandlers.Validate(); nil != err {
return err
}
2018-04-03 08:55:48 +00:00
if "" == c.Network {
2018-04-12 01:23:40 +00:00
return fmt.Errorf("%s Network is not valid", c.logHeader())
2018-04-03 08:55:48 +00:00
}
if "" == c.Address {
2018-04-12 01:23:40 +00:00
return fmt.Errorf("%s Address is not valid", c.logHeader())
2018-04-03 08:55:48 +00:00
}
return nil
}