split out connection info and throttling into ircConn; move conn from state to client
This commit is contained in:
parent
1090fd92a8
commit
ed6e266cba
45
client.go
45
client.go
|
@ -35,6 +35,8 @@ type Client struct {
|
|||
// CTCP is a handler which manages internal and external CTCP handlers.
|
||||
CTCP *CTCP
|
||||
|
||||
// conn is a net.Conn reference to the IRC server.
|
||||
conn *ircConn
|
||||
// tries represents the internal reconnect count to the IRC server.
|
||||
tries int
|
||||
// reconnecting is true if the client is reconnecting, used so multiple
|
||||
|
@ -203,9 +205,7 @@ func (c *Client) Connect() error {
|
|||
return err
|
||||
}
|
||||
|
||||
c.state.mu.Lock()
|
||||
c.state.conn = conn
|
||||
c.state.mu.Unlock()
|
||||
c.conn = conn
|
||||
|
||||
// Send a virtual event allowing hooks for successful socket connection.
|
||||
c.Events <- &Event{Command: INITIALIZED, Trailing: c.Server()}
|
||||
|
@ -226,12 +226,6 @@ func (c *Client) Connect() error {
|
|||
c.tries = 0
|
||||
c.reconnecting = false
|
||||
|
||||
c.state.mu.Lock()
|
||||
ctime := time.Now()
|
||||
c.state.connTime = &ctime
|
||||
c.state.connected = true
|
||||
c.state.mu.Unlock()
|
||||
|
||||
// Start read loop to process messages from the server.
|
||||
var rctx, ectx context.Context
|
||||
rctx, c.closeRead = context.WithCancel(context.Background())
|
||||
|
@ -313,12 +307,10 @@ func (c *Client) Reconnect() error {
|
|||
func (c *Client) cleanup(all bool) {
|
||||
c.cmux.Lock()
|
||||
|
||||
c.state.mu.Lock()
|
||||
// Close any connections they have open.
|
||||
if c.state.conn != nil {
|
||||
c.state.conn.Close()
|
||||
if c.conn != nil {
|
||||
c.conn.Close()
|
||||
}
|
||||
c.state.mu.Unlock()
|
||||
|
||||
if c.closeRead != nil {
|
||||
c.closeRead()
|
||||
|
@ -380,8 +372,8 @@ func (c *Client) readLoop(ctx context.Context) {
|
|||
case <-ctx.Done():
|
||||
return
|
||||
default:
|
||||
c.state.conn.lconn.SetDeadline(time.Now().Add(300 * time.Second))
|
||||
event, err = c.state.conn.Decode()
|
||||
c.conn.setTimeout(300 * time.Second)
|
||||
event, err = c.conn.Decode()
|
||||
if err != nil {
|
||||
// Attempt a reconnect (if applicable). If it fails, send
|
||||
// the error to c.Config.HandleError to be dealt with, if
|
||||
|
@ -483,7 +475,7 @@ func (c *Client) Lifetime() time.Duration {
|
|||
// simply looking to trigger handlers with an event.
|
||||
func (c *Client) Send(event *Event) error {
|
||||
if !c.Config.AllowFlood {
|
||||
<-time.After(c.state.rate(event.Len()))
|
||||
<-time.After(c.conn.rate(event.Len()))
|
||||
}
|
||||
|
||||
return c.write(event)
|
||||
|
@ -491,14 +483,14 @@ func (c *Client) Send(event *Event) error {
|
|||
|
||||
// write is the lower level function to write an event.
|
||||
func (c *Client) write(event *Event) error {
|
||||
c.state.lastWrite = time.Now()
|
||||
c.conn.lastWrite = time.Now()
|
||||
|
||||
// log the event
|
||||
if !event.Sensitive {
|
||||
c.debug.Print("> ", StripRaw(event.String()))
|
||||
}
|
||||
|
||||
return c.state.conn.Encode(event)
|
||||
return c.conn.Encode(event)
|
||||
}
|
||||
|
||||
// Uptime is the time at which the client successfully connected to the
|
||||
|
@ -508,9 +500,7 @@ func (c *Client) Uptime() (up *time.Time, err error) {
|
|||
return nil, ErrNotConnected
|
||||
}
|
||||
|
||||
c.state.mu.RLock()
|
||||
up = c.state.connTime
|
||||
c.state.mu.RUnlock()
|
||||
up = c.conn.connTime
|
||||
|
||||
return up, nil
|
||||
}
|
||||
|
@ -522,20 +512,17 @@ func (c *Client) ConnSince() (since *time.Duration, err error) {
|
|||
return nil, ErrNotConnected
|
||||
}
|
||||
|
||||
c.state.mu.RLock()
|
||||
timeSince := time.Since(*c.state.connTime)
|
||||
c.state.mu.RUnlock()
|
||||
timeSince := time.Since(*c.conn.connTime)
|
||||
|
||||
return &timeSince, nil
|
||||
}
|
||||
|
||||
// IsConnected returns true if the client is connected to the server.
|
||||
func (c *Client) IsConnected() (connected bool) {
|
||||
c.state.mu.RLock()
|
||||
connected = c.state.connected
|
||||
c.state.mu.RUnlock()
|
||||
|
||||
return connected
|
||||
if c.conn == nil {
|
||||
return false
|
||||
}
|
||||
return c.conn.connected
|
||||
}
|
||||
|
||||
// GetNick returns the current nickname of the active connection. Returns
|
||||
|
|
40
conn.go
40
conn.go
|
@ -29,10 +29,22 @@ var endline = []byte("\r\n")
|
|||
type ircConn struct {
|
||||
ircEncoder
|
||||
ircDecoder
|
||||
|
||||
lconn net.Conn
|
||||
|
||||
// lastWrite is used ot keep track of when we last wrote to the server.
|
||||
lastWrite time.Time
|
||||
// writeDelay is used to keep track of rate limiting of events sent to
|
||||
// the server.
|
||||
writeDelay time.Duration
|
||||
|
||||
// connected is true if we're actively connected to a server.
|
||||
connected bool
|
||||
// connTime is the time at which the client has connected to a server.
|
||||
connTime *time.Time
|
||||
}
|
||||
|
||||
// newConn sets up and returns a new connection to the server. This includes
|
||||
// setting up things like proxies, ssl/tls, and other misc. things.
|
||||
func newConn(conf Config, addr string) (*ircConn, error) {
|
||||
// Sanity check a few options.
|
||||
if conf.Server == "" {
|
||||
|
@ -103,10 +115,14 @@ func newConn(conf Config, addr string) (*ircConn, error) {
|
|||
conn = tlsConn
|
||||
}
|
||||
|
||||
ctime := time.Now()
|
||||
|
||||
return &ircConn{
|
||||
ircEncoder: ircEncoder{writer: conn},
|
||||
ircDecoder: ircDecoder{reader: bufio.NewReader(conn)},
|
||||
lconn: conn,
|
||||
connTime: &ctime,
|
||||
connected: true,
|
||||
}, nil
|
||||
}
|
||||
|
||||
|
@ -115,6 +131,28 @@ func (c *ircConn) Close() error {
|
|||
return c.lconn.Close()
|
||||
}
|
||||
|
||||
// setTimeout applies a deadline that the connection must respond back with,
|
||||
// within the specified time.
|
||||
func (c *ircConn) setTimeout(timeout time.Duration) {
|
||||
c.lconn.SetDeadline(time.Now().Add(timeout))
|
||||
}
|
||||
|
||||
// rate allows limiting events based on how frequent the event is being sent,
|
||||
// as well as how many characters each event has.
|
||||
func (c *ircConn) rate(chars int) time.Duration {
|
||||
_time := time.Second + ((time.Duration(chars) * time.Second) / 100)
|
||||
elapsed := time.Now().Sub(c.lastWrite)
|
||||
if c.writeDelay += _time - elapsed; c.writeDelay < 0 {
|
||||
c.writeDelay = 0
|
||||
}
|
||||
|
||||
if c.writeDelay > (8 * time.Second) {
|
||||
return _time
|
||||
}
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
// ircDecoder reads Event objects from an input stream.
|
||||
type ircDecoder struct {
|
||||
reader *bufio.Reader
|
||||
|
|
31
state.go
31
state.go
|
@ -17,20 +17,6 @@ type state struct {
|
|||
// m is a RW mutex lock, used to guard the state from goroutines causing
|
||||
// corruption.
|
||||
mu sync.RWMutex
|
||||
|
||||
// conn is a net.Conn reference to the IRC server.
|
||||
conn *ircConn
|
||||
|
||||
// lastWrite is used ot keep track of when we last wrote to the server.
|
||||
lastWrite time.Time
|
||||
// writeDelay is used to keep track of rate limiting of events sent to
|
||||
// the server.
|
||||
writeDelay time.Duration
|
||||
|
||||
// connected is true if we're actively connected to a server.
|
||||
connected bool
|
||||
// connTime is the time at which the client has connected to a server.
|
||||
connTime *time.Time
|
||||
// nick is the tracker for our nickname on the server.
|
||||
nick string
|
||||
// channels represents all channels we're active in.
|
||||
|
@ -180,7 +166,6 @@ func newState() *state {
|
|||
|
||||
s.channels = make(map[string]*Channel)
|
||||
s.serverOptions = make(map[string]string)
|
||||
s.connected = false
|
||||
|
||||
return s
|
||||
}
|
||||
|
@ -338,19 +323,3 @@ func (s *state) lookupUsers(matchType, toMatch string) []*User {
|
|||
|
||||
return users
|
||||
}
|
||||
|
||||
// rate allows limiting events based on how frequent the event is being sent,
|
||||
// as well as how many characters each event has.
|
||||
func (s *state) rate(chars int) time.Duration {
|
||||
_time := time.Second + ((time.Duration(chars) * time.Second) / 100)
|
||||
elapsed := time.Now().Sub(s.lastWrite)
|
||||
if s.writeDelay += _time - elapsed; s.writeDelay < 0 {
|
||||
s.writeDelay = 0
|
||||
}
|
||||
|
||||
if s.writeDelay > (8 * time.Second) {
|
||||
return _time
|
||||
}
|
||||
|
||||
return 0
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue