mirror of
https://github.com/ergochat/ergo.git
synced 2025-01-03 16:42:38 +01:00
Merge pull request #171 from slingamn/atime
fix a race condition in client timeouts
This commit is contained in:
commit
b2e5738f08
@ -261,6 +261,8 @@ func (client *Client) run() {
|
|||||||
|
|
||||||
// Active updates when the client was last 'active' (i.e. the user should be sitting in front of their client).
|
// Active updates when the client was last 'active' (i.e. the user should be sitting in front of their client).
|
||||||
func (client *Client) Active() {
|
func (client *Client) Active() {
|
||||||
|
client.stateMutex.Lock()
|
||||||
|
defer client.stateMutex.Unlock()
|
||||||
client.atime = time.Now()
|
client.atime = time.Now()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -298,6 +300,8 @@ func (client *Client) Register() {
|
|||||||
|
|
||||||
// IdleTime returns how long this client's been idle.
|
// IdleTime returns how long this client's been idle.
|
||||||
func (client *Client) IdleTime() time.Duration {
|
func (client *Client) IdleTime() time.Duration {
|
||||||
|
client.stateMutex.RLock()
|
||||||
|
defer client.stateMutex.RUnlock()
|
||||||
return time.Since(client.atime)
|
return time.Since(client.atime)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -38,7 +38,6 @@ type IdleTimer struct {
|
|||||||
|
|
||||||
// mutable
|
// mutable
|
||||||
client *Client
|
client *Client
|
||||||
state TimerState
|
|
||||||
lastSeen time.Time
|
lastSeen time.Time
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -49,7 +48,6 @@ func NewIdleTimer(client *Client) *IdleTimer {
|
|||||||
idleTimeout: IdleTimeout,
|
idleTimeout: IdleTimeout,
|
||||||
quitTimeout: QuitTimeout,
|
quitTimeout: QuitTimeout,
|
||||||
client: client,
|
client: client,
|
||||||
state: TimerUnregistered,
|
|
||||||
}
|
}
|
||||||
return &it
|
return &it
|
||||||
}
|
}
|
||||||
@ -58,17 +56,18 @@ func NewIdleTimer(client *Client) *IdleTimer {
|
|||||||
// it will eventually be stopped.
|
// it will eventually be stopped.
|
||||||
func (it *IdleTimer) Start() {
|
func (it *IdleTimer) Start() {
|
||||||
it.Lock()
|
it.Lock()
|
||||||
it.state = TimerUnregistered
|
|
||||||
it.lastSeen = time.Now()
|
it.lastSeen = time.Now()
|
||||||
it.Unlock()
|
it.Unlock()
|
||||||
go it.mainLoop()
|
go it.mainLoop()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (it *IdleTimer) mainLoop() {
|
func (it *IdleTimer) mainLoop() {
|
||||||
|
state := TimerUnregistered
|
||||||
|
var lastPinged time.Time
|
||||||
|
|
||||||
for {
|
for {
|
||||||
it.Lock()
|
it.Lock()
|
||||||
client := it.client
|
client := it.client
|
||||||
state := it.state
|
|
||||||
lastSeen := it.lastSeen
|
lastSeen := it.lastSeen
|
||||||
it.Unlock()
|
it.Unlock()
|
||||||
|
|
||||||
@ -76,7 +75,8 @@ func (it *IdleTimer) mainLoop() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
idleTime := time.Now().Sub(lastSeen)
|
now := time.Now()
|
||||||
|
idleTime := now.Sub(lastSeen)
|
||||||
var nextSleep time.Duration
|
var nextSleep time.Duration
|
||||||
|
|
||||||
if state == TimerUnregistered {
|
if state == TimerUnregistered {
|
||||||
@ -87,8 +87,8 @@ func (it *IdleTimer) mainLoop() {
|
|||||||
nextSleep = it.registerTimeout - idleTime
|
nextSleep = it.registerTimeout - idleTime
|
||||||
}
|
}
|
||||||
} else if state == TimerIdle {
|
} else if state == TimerIdle {
|
||||||
if idleTime < it.quitTimeout {
|
if lastSeen.After(lastPinged) {
|
||||||
// new ping came in after we transitioned to TimerIdle,
|
// new pong came in after we transitioned to TimerIdle,
|
||||||
// transition back to active and process deadlines below
|
// transition back to active and process deadlines below
|
||||||
state = TimerActive
|
state = TimerActive
|
||||||
} else {
|
} else {
|
||||||
@ -100,6 +100,7 @@ func (it *IdleTimer) mainLoop() {
|
|||||||
nextSleep = it.idleTimeout - idleTime
|
nextSleep = it.idleTimeout - idleTime
|
||||||
if nextSleep <= 0 {
|
if nextSleep <= 0 {
|
||||||
state = TimerIdle
|
state = TimerIdle
|
||||||
|
lastPinged = now
|
||||||
client.Ping()
|
client.Ping()
|
||||||
// grant the client at least quitTimeout to respond
|
// grant the client at least quitTimeout to respond
|
||||||
nextSleep = it.quitTimeout
|
nextSleep = it.quitTimeout
|
||||||
@ -113,10 +114,6 @@ func (it *IdleTimer) mainLoop() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
it.Lock()
|
|
||||||
it.state = state
|
|
||||||
it.Unlock()
|
|
||||||
|
|
||||||
time.Sleep(nextSleep)
|
time.Sleep(nextSleep)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user