Stop the earlier poll loop on a second /connect (closes #228)
check / check (push) Canceled after 0s
check / check (push) Canceled after 0s
A second /connect started a new poll loop without stopping the first. The first loop then polled with the new client too, so each message could be shown twice. It also read stopPoll without a.mu while cmdConnect wrote it. cmdConnect now closes the earlier loop's channel in the same locked step that replaces the client and the cursor, and hands the new channel to the new loop. The loop checks its channel under a.mu before each poll and again before it moves the cursor, so a stopped loop never polls with the new client or moves the new cursor. Model: opus-5-5
This commit is contained in:
+37
-10
@@ -199,11 +199,21 @@ func (a *App) cmdConnect(serverURL string) {
|
||||
return
|
||||
}
|
||||
|
||||
// The poll loop of an earlier connection is stopped in the same
|
||||
// step that replaces the client, so it never polls with the new
|
||||
// one.
|
||||
a.mu.Lock()
|
||||
a.client = client
|
||||
a.nick = resp.Nick
|
||||
a.connected = true
|
||||
a.lastQID = 0
|
||||
|
||||
if a.stopPoll != nil {
|
||||
close(a.stopPoll)
|
||||
}
|
||||
|
||||
stop := make(chan struct{})
|
||||
a.stopPoll = stop
|
||||
a.mu.Unlock()
|
||||
|
||||
a.ui.AddStatus(fmt.Sprintf(
|
||||
@@ -212,9 +222,7 @@ func (a *App) cmdConnect(serverURL string) {
|
||||
))
|
||||
a.ui.SetStatus(resp.Nick, "", "connected")
|
||||
|
||||
a.stopPoll = make(chan struct{})
|
||||
|
||||
go a.pollLoop()
|
||||
go a.pollLoop(stop)
|
||||
}
|
||||
|
||||
func (a *App) cmdNick(nick string) {
|
||||
@@ -702,16 +710,23 @@ func (a *App) cmdHelp() {
|
||||
}
|
||||
}
|
||||
|
||||
// pollLoop long-polls for messages in the background.
|
||||
func (a *App) pollLoop() {
|
||||
// pollLoop long-polls for messages in the background until stop is
|
||||
// closed. A later /connect closes stop under a.mu as it replaces the
|
||||
// client and the cursor, so the loop checks stop under a.mu too. A
|
||||
// stopped loop then neither polls with the new client nor moves the
|
||||
// new cursor.
|
||||
func (a *App) pollLoop(stop <-chan struct{}) {
|
||||
for {
|
||||
a.mu.Lock()
|
||||
|
||||
select {
|
||||
case <-a.stopPoll:
|
||||
case <-stop:
|
||||
a.mu.Unlock()
|
||||
|
||||
return
|
||||
default:
|
||||
}
|
||||
|
||||
a.mu.Lock()
|
||||
client := a.client
|
||||
lastQID := a.lastQID
|
||||
a.mu.Unlock()
|
||||
@@ -729,12 +744,24 @@ func (a *App) pollLoop() {
|
||||
continue
|
||||
}
|
||||
|
||||
if result.LastID > 0 {
|
||||
a.mu.Lock()
|
||||
a.lastQID = result.LastID
|
||||
// A poll sent before stop was closed answers for the earlier
|
||||
// connection.
|
||||
a.mu.Lock()
|
||||
|
||||
select {
|
||||
case <-stop:
|
||||
a.mu.Unlock()
|
||||
|
||||
return
|
||||
default:
|
||||
}
|
||||
|
||||
if result.LastID > 0 {
|
||||
a.lastQID = result.LastID
|
||||
}
|
||||
|
||||
a.mu.Unlock()
|
||||
|
||||
for i := range result.Messages {
|
||||
a.handleServerMessage(&result.Messages[i])
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user