Browse Source

Merge pull request #828 from slingamn/sessionrace.1

change "last signoff" tracking to "last seen"
tags/v2.0.0-rc1
Shivaram Lingamneni 4 years ago
parent
commit
e0f2475b80
No account linked to committer's email address
7 changed files with 78 additions and 91 deletions
  1. 15
    11
      irc/accounts.go
  2. 2
    2
      irc/channel.go
  3. 51
    47
      irc/client.go
  4. 2
    2
      irc/client_lookup_set.go
  5. 3
    2
      irc/commands.go
  6. 5
    15
      irc/getters.go
  7. 0
    12
      irc/idletimer.go

+ 15
- 11
irc/accounts.go View File

35
 	keyCertToAccount           = "account.creds.certfp %s"
35
 	keyCertToAccount           = "account.creds.certfp %s"
36
 	keyAccountChannels         = "account.channels %s" // channels registered to the account
36
 	keyAccountChannels         = "account.channels %s" // channels registered to the account
37
 	keyAccountJoinedChannels   = "account.joinedto %s" // channels a persistent client has joined
37
 	keyAccountJoinedChannels   = "account.joinedto %s" // channels a persistent client has joined
38
-	keyAccountLastSignoff      = "account.lastsignoff %s"
38
+	keyAccountLastSeen         = "account.lastseen %s"
39
 
39
 
40
 	keyVHostQueueAcctToId = "vhostQueue %s"
40
 	keyVHostQueueAcctToId = "vhostQueue %s"
41
 	vhostRequestIdx       = "vhostQueue"
41
 	vhostRequestIdx       = "vhostQueue"
104
 		account, err := am.LoadAccount(accountName)
104
 		account, err := am.LoadAccount(accountName)
105
 		if err == nil && account.Verified &&
105
 		if err == nil && account.Verified &&
106
 			persistenceEnabled(config.Accounts.Multiclient.AlwaysOn, account.Settings.AlwaysOn) {
106
 			persistenceEnabled(config.Accounts.Multiclient.AlwaysOn, account.Settings.AlwaysOn) {
107
-			am.server.AddAlwaysOnClient(account, am.loadChannels(accountName), am.loadLastSignoff(accountName))
107
+			am.server.AddAlwaysOnClient(account, am.loadChannels(accountName), am.loadLastSeen(accountName))
108
 		}
108
 		}
109
 	}
109
 	}
110
 }
110
 }
535
 	return
535
 	return
536
 }
536
 }
537
 
537
 
538
-func (am *AccountManager) saveLastSignoff(account string, lastSignoff time.Time) {
539
-	key := fmt.Sprintf(keyAccountLastSignoff, account)
538
+func (am *AccountManager) saveLastSeen(account string, lastSeen time.Time) {
539
+	key := fmt.Sprintf(keyAccountLastSeen, account)
540
 	var val string
540
 	var val string
541
-	if !lastSignoff.IsZero() {
542
-		val = strconv.FormatInt(lastSignoff.UnixNano(), 10)
541
+	if !lastSeen.IsZero() {
542
+		val = strconv.FormatInt(lastSeen.UnixNano(), 10)
543
 	}
543
 	}
544
 	am.server.store.Update(func(tx *buntdb.Tx) error {
544
 	am.server.store.Update(func(tx *buntdb.Tx) error {
545
 		if val != "" {
545
 		if val != "" {
551
 	})
551
 	})
552
 }
552
 }
553
 
553
 
554
-func (am *AccountManager) loadLastSignoff(account string) (lastSignoff time.Time) {
555
-	key := fmt.Sprintf(keyAccountLastSignoff, account)
554
+func (am *AccountManager) loadLastSeen(account string) (lastSeen time.Time) {
555
+	key := fmt.Sprintf(keyAccountLastSeen, account)
556
 	var lsText string
556
 	var lsText string
557
-	am.server.store.View(func(tx *buntdb.Tx) error {
557
+	am.server.store.Update(func(tx *buntdb.Tx) error {
558
 		lsText, _ = tx.Get(key)
558
 		lsText, _ = tx.Get(key)
559
+		// XXX clear this on startup, because it's not clear when it's
560
+		// going to be overwritten, and restarting the server twice in a row
561
+		// could result in a large amount of duplicated history replay
562
+		tx.Delete(key)
559
 		return nil
563
 		return nil
560
 	})
564
 	})
561
 	lsNum, err := strconv.ParseInt(lsText, 10, 64)
565
 	lsNum, err := strconv.ParseInt(lsText, 10, 64)
1071
 	vhostQueueKey := fmt.Sprintf(keyVHostQueueAcctToId, casefoldedAccount)
1075
 	vhostQueueKey := fmt.Sprintf(keyVHostQueueAcctToId, casefoldedAccount)
1072
 	channelsKey := fmt.Sprintf(keyAccountChannels, casefoldedAccount)
1076
 	channelsKey := fmt.Sprintf(keyAccountChannels, casefoldedAccount)
1073
 	joinedChannelsKey := fmt.Sprintf(keyAccountJoinedChannels, casefoldedAccount)
1077
 	joinedChannelsKey := fmt.Sprintf(keyAccountJoinedChannels, casefoldedAccount)
1074
-	lastSignoffKey := fmt.Sprintf(keyAccountLastSignoff, casefoldedAccount)
1078
+	lastSeenKey := fmt.Sprintf(keyAccountLastSeen, casefoldedAccount)
1075
 
1079
 
1076
 	var clients []*Client
1080
 	var clients []*Client
1077
 
1081
 
1108
 		channelsStr, _ = tx.Get(channelsKey)
1112
 		channelsStr, _ = tx.Get(channelsKey)
1109
 		tx.Delete(channelsKey)
1113
 		tx.Delete(channelsKey)
1110
 		tx.Delete(joinedChannelsKey)
1114
 		tx.Delete(joinedChannelsKey)
1111
-		tx.Delete(lastSignoffKey)
1115
+		tx.Delete(lastSeenKey)
1112
 
1116
 
1113
 		_, err := tx.Delete(vhostQueueKey)
1117
 		_, err := tx.Delete(vhostQueueKey)
1114
 		am.decrementVHostQueueCount(casefoldedAccount, err)
1118
 		am.decrementVHostQueueCount(casefoldedAccount, err)

+ 2
- 2
irc/channel.go View File

775
 	var after, before time.Time
775
 	var after, before time.Time
776
 	if rb.session.zncPlaybackTimes != nil && (rb.session.zncPlaybackTimes.targets == nil || rb.session.zncPlaybackTimes.targets.Has(channel.NameCasefolded())) {
776
 	if rb.session.zncPlaybackTimes != nil && (rb.session.zncPlaybackTimes.targets == nil || rb.session.zncPlaybackTimes.targets.Has(channel.NameCasefolded())) {
777
 		after, before = rb.session.zncPlaybackTimes.after, rb.session.zncPlaybackTimes.before
777
 		after, before = rb.session.zncPlaybackTimes.after, rb.session.zncPlaybackTimes.before
778
-	} else if !rb.session.lastSignoff.IsZero() {
778
+	} else if !rb.session.autoreplayMissedSince.IsZero() {
779
 		// we already checked for history caps in `playReattachMessages`
779
 		// we already checked for history caps in `playReattachMessages`
780
-		after = rb.session.lastSignoff
780
+		after = rb.session.autoreplayMissedSince
781
 	}
781
 	}
782
 
782
 
783
 	if !after.IsZero() || !before.IsZero() {
783
 	if !after.IsZero() || !before.IsZero() {

+ 51
- 47
irc/client.go View File

47
 	accountName        string // display name of the account: uncasefolded, '*' if not logged in
47
 	accountName        string // display name of the account: uncasefolded, '*' if not logged in
48
 	accountRegDate     time.Time
48
 	accountRegDate     time.Time
49
 	accountSettings    AccountSettings
49
 	accountSettings    AccountSettings
50
-	atime              time.Time
51
 	away               bool
50
 	away               bool
52
 	awayMessage        string
51
 	awayMessage        string
53
 	brbTimer           BrbTimer
52
 	brbTimer           BrbTimer
60
 	invitedTo          map[string]bool
59
 	invitedTo          map[string]bool
61
 	isSTSOnly          bool
60
 	isSTSOnly          bool
62
 	languages          []string
61
 	languages          []string
63
-	lastSignoff        time.Time // for always-on clients, the time their last session quit
62
+	lastActive         time.Time // last time they sent a command that wasn't PONG or similar
63
+	lastSeen           time.Time // last time they sent any kind of command
64
 	loginThrottle      connection_limits.GenericThrottle
64
 	loginThrottle      connection_limits.GenericThrottle
65
 	nick               string
65
 	nick               string
66
 	nickCasefolded     string
66
 	nickCasefolded     string
103
 type Session struct {
103
 type Session struct {
104
 	client *Client
104
 	client *Client
105
 
105
 
106
-	ctime time.Time
107
-	atime time.Time
106
+	ctime      time.Time
107
+	lastActive time.Time
108
 
108
 
109
 	socket      *Socket
109
 	socket      *Socket
110
 	realIP      net.IP
110
 	realIP      net.IP
130
 
130
 
131
 	registrationMessages int
131
 	registrationMessages int
132
 
132
 
133
-	resumeID         string
134
-	resumeDetails    *ResumeDetails
135
-	zncPlaybackTimes *zncPlaybackTimes
136
-	lastSignoff      time.Time
133
+	resumeID              string
134
+	resumeDetails         *ResumeDetails
135
+	zncPlaybackTimes      *zncPlaybackTimes
136
+	autoreplayMissedSince time.Time
137
 
137
 
138
 	batch MultilineBatch
138
 	batch MultilineBatch
139
 }
139
 }
247
 	// give them 1k of grace over the limit:
247
 	// give them 1k of grace over the limit:
248
 	socket := NewSocket(conn.Conn, ircmsg.MaxlenTagsFromClient+512+1024, config.Server.MaxSendQBytes)
248
 	socket := NewSocket(conn.Conn, ircmsg.MaxlenTagsFromClient+512+1024, config.Server.MaxSendQBytes)
249
 	client := &Client{
249
 	client := &Client{
250
-		atime:     now,
251
-		channels:  make(ChannelSet),
252
-		ctime:     now,
253
-		isSTSOnly: conn.Config.STSOnly,
254
-		languages: server.Languages().Default(),
250
+		lastSeen:   now,
251
+		lastActive: now,
252
+		channels:   make(ChannelSet),
253
+		ctime:      now,
254
+		isSTSOnly:  conn.Config.STSOnly,
255
+		languages:  server.Languages().Default(),
255
 		loginThrottle: connection_limits.GenericThrottle{
256
 		loginThrottle: connection_limits.GenericThrottle{
256
 			Duration: config.Accounts.LoginThrottling.Duration,
257
 			Duration: config.Accounts.LoginThrottling.Duration,
257
 			Limit:    config.Accounts.LoginThrottling.MaxAttempts,
258
 			Limit:    config.Accounts.LoginThrottling.MaxAttempts,
270
 		capVersion: caps.Cap301,
271
 		capVersion: caps.Cap301,
271
 		capState:   caps.NoneState,
272
 		capState:   caps.NoneState,
272
 		ctime:      now,
273
 		ctime:      now,
273
-		atime:      now,
274
+		lastActive: now,
274
 		realIP:     realIP,
275
 		realIP:     realIP,
275
 		isTor:      conn.Config.Tor,
276
 		isTor:      conn.Config.Tor,
276
 	}
277
 	}
306
 	client.run(session, proxyLine)
307
 	client.run(session, proxyLine)
307
 }
308
 }
308
 
309
 
309
-func (server *Server) AddAlwaysOnClient(account ClientAccount, chnames []string, lastSignoff time.Time) {
310
+func (server *Server) AddAlwaysOnClient(account ClientAccount, chnames []string, lastActive time.Time) {
310
 	now := time.Now().UTC()
311
 	now := time.Now().UTC()
311
 	config := server.Config()
312
 	config := server.Config()
313
+	if lastActive.IsZero() {
314
+		lastActive = now
315
+	}
312
 
316
 
313
 	client := &Client{
317
 	client := &Client{
314
-		atime:     now,
315
-		channels:  make(ChannelSet),
316
-		ctime:     now,
317
-		languages: server.Languages().Default(),
318
-		server:    server,
318
+		lastSeen:   now,
319
+		lastActive: lastActive,
320
+		channels:   make(ChannelSet),
321
+		ctime:      now,
322
+		languages:  server.Languages().Default(),
323
+		server:     server,
319
 
324
 
320
 		// TODO figure out how to set these on reattach?
325
 		// TODO figure out how to set these on reattach?
321
 		username:    "~user",
326
 		username:    "~user",
322
 		rawHostname: server.name,
327
 		rawHostname: server.name,
323
 		realIP:      utils.IPv4LoopbackAddress,
328
 		realIP:      utils.IPv4LoopbackAddress,
324
 
329
 
325
-		alwaysOn:    true,
326
-		lastSignoff: lastSignoff,
330
+		alwaysOn: true,
327
 	}
331
 	}
328
 
332
 
329
 	client.SetMode(modes.TLS, true)
333
 	client.SetMode(modes.TLS, true)
662
 		channel.autoReplayHistory(client, rb, "")
666
 		channel.autoReplayHistory(client, rb, "")
663
 		rb.Send(true)
667
 		rb.Send(true)
664
 	}
668
 	}
665
-	if !session.lastSignoff.IsZero() && !hasHistoryCaps {
669
+	if !session.autoreplayMissedSince.IsZero() && !hasHistoryCaps {
666
 		rb := NewResponseBuffer(session)
670
 		rb := NewResponseBuffer(session)
667
-		zncPlayPrivmsgs(client, rb, session.lastSignoff, time.Time{})
671
+		zncPlayPrivmsgs(client, rb, session.autoreplayMissedSince, time.Time{})
668
 		rb.Send(true)
672
 		rb.Send(true)
669
 	}
673
 	}
670
-	session.lastSignoff = time.Time{}
674
+	session.autoreplayMissedSince = time.Time{}
671
 }
675
 }
672
 
676
 
673
 //
677
 //
674
 // idle, quit, timers and timeouts
678
 // idle, quit, timers and timeouts
675
 //
679
 //
676
 
680
 
677
-// Active updates when the client was last 'active' (i.e. the user should be sitting in front of their client).
678
-func (client *Client) Active(session *Session) {
681
+// Touch indicates that we received a line from the client (so the connection is healthy
682
+// at this time, modulo network latency and fakelag). `active` means not a PING or suchlike
683
+// (i.e. the user should be sitting in front of their client).
684
+func (client *Client) Touch(active bool, session *Session) {
679
 	now := time.Now().UTC()
685
 	now := time.Now().UTC()
680
 	client.stateMutex.Lock()
686
 	client.stateMutex.Lock()
681
 	defer client.stateMutex.Unlock()
687
 	defer client.stateMutex.Unlock()
682
-	session.atime = now
683
-	client.atime = now
688
+	client.lastSeen = now
689
+	if active {
690
+		client.lastActive = now
691
+		session.lastActive = now
692
+	}
684
 }
693
 }
685
 
694
 
686
 // Ping sends the client a PING message.
695
 // Ping sends the client a PING message.
896
 func (client *Client) IdleTime() time.Duration {
905
 func (client *Client) IdleTime() time.Duration {
897
 	client.stateMutex.RLock()
906
 	client.stateMutex.RLock()
898
 	defer client.stateMutex.RUnlock()
907
 	defer client.stateMutex.RUnlock()
899
-	return time.Since(client.atime)
908
+	return time.Since(client.lastActive)
900
 }
909
 }
901
 
910
 
902
 // SignonTime returns this client's signon time as a unix timestamp.
911
 // SignonTime returns this client's signon time as a unix timestamp.
1151
 // has no more sessions.
1160
 // has no more sessions.
1152
 func (client *Client) destroy(session *Session) {
1161
 func (client *Client) destroy(session *Session) {
1153
 	var sessionsToDestroy []*Session
1162
 	var sessionsToDestroy []*Session
1154
-	var lastSignoff time.Time
1155
-	if session != nil {
1156
-		lastSignoff = session.idletimer.LastTouch()
1157
-	} else {
1158
-		lastSignoff = time.Now().UTC()
1159
-	}
1160
 
1163
 
1161
 	client.stateMutex.Lock()
1164
 	client.stateMutex.Lock()
1162
 	details := client.detailsNoMutex()
1165
 	details := client.detailsNoMutex()
1166
 	sessionRemoved := false
1169
 	sessionRemoved := false
1167
 	registered := client.registered
1170
 	registered := client.registered
1168
 	alwaysOn := client.alwaysOn
1171
 	alwaysOn := client.alwaysOn
1172
+	saveLastSeen := alwaysOn && client.accountSettings.AutoreplayMissed
1169
 	var remainingSessions int
1173
 	var remainingSessions int
1170
 	if session == nil {
1174
 	if session == nil {
1171
 		sessionsToDestroy = client.sessions
1175
 		sessionsToDestroy = client.sessions
1187
 		// if it's our job to destroy it, don't let anyone else try
1191
 		// if it's our job to destroy it, don't let anyone else try
1188
 		client.destroyed = true
1192
 		client.destroyed = true
1189
 	}
1193
 	}
1190
-	if alwaysOn && remainingSessions == 0 {
1191
-		client.lastSignoff = lastSignoff
1192
-		client.dirtyBits |= IncludeLastSignoff
1193
-	} else {
1194
-		lastSignoff = time.Time{}
1194
+	if saveLastSeen {
1195
+		client.dirtyBits |= IncludeLastSeen
1195
 	}
1196
 	}
1196
 	exitedSnomaskSent := client.exitedSnomaskSent
1197
 	exitedSnomaskSent := client.exitedSnomaskSent
1197
 	client.stateMutex.Unlock()
1198
 	client.stateMutex.Unlock()
1198
 
1199
 
1199
-	if !lastSignoff.IsZero() {
1200
+	// XXX there is no particular reason to persist this state here rather than
1201
+	// any other place: it would be correct to persist it after every `Touch`. However,
1202
+	// I'm not comfortable introducing that many database writes, and I don't want to
1203
+	// design a throttle.
1204
+	if saveLastSeen {
1200
 		client.wakeWriter()
1205
 		client.wakeWriter()
1201
 	}
1206
 	}
1202
 
1207
 
1571
 
1576
 
1572
 // these are bit flags indicating what part of the client status is "dirty"
1577
 // these are bit flags indicating what part of the client status is "dirty"
1573
 // and needs to be read from memory and written to the db
1578
 // and needs to be read from memory and written to the db
1574
-// TODO add a dirty flag for lastSignoff
1575
 const (
1579
 const (
1576
 	IncludeChannels uint = 1 << iota
1580
 	IncludeChannels uint = 1 << iota
1577
-	IncludeLastSignoff
1581
+	IncludeLastSeen
1578
 )
1582
 )
1579
 
1583
 
1580
 func (client *Client) markDirty(dirtyBits uint) {
1584
 func (client *Client) markDirty(dirtyBits uint) {
1629
 		}
1633
 		}
1630
 		client.server.accounts.saveChannels(account, channelNames)
1634
 		client.server.accounts.saveChannels(account, channelNames)
1631
 	}
1635
 	}
1632
-	if (dirtyBits & IncludeLastSignoff) != 0 {
1636
+	if (dirtyBits & IncludeLastSeen) != 0 {
1633
 		client.stateMutex.RLock()
1637
 		client.stateMutex.RLock()
1634
-		lastSignoff := client.lastSignoff
1638
+		lastSeen := client.lastSeen
1635
 		client.stateMutex.RUnlock()
1639
 		client.stateMutex.RUnlock()
1636
-		client.server.accounts.saveLastSignoff(account, lastSignoff)
1640
+		client.server.accounts.saveLastSeen(account, lastSeen)
1637
 	}
1641
 	}
1638
 }
1642
 }

+ 2
- 2
irc/client_lookup_set.go View File

174
 		if registered || !bouncerAllowed || account == "" || account != currentClient.Account() || client.HasMode(modes.TLS) != currentClient.HasMode(modes.TLS) {
174
 		if registered || !bouncerAllowed || account == "" || account != currentClient.Account() || client.HasMode(modes.TLS) != currentClient.HasMode(modes.TLS) {
175
 			return "", errNicknameInUse
175
 			return "", errNicknameInUse
176
 		}
176
 		}
177
-		reattachSuccessful, numSessions, lastSignoff := currentClient.AddSession(session)
177
+		reattachSuccessful, numSessions, lastSeen := currentClient.AddSession(session)
178
 		if !reattachSuccessful {
178
 		if !reattachSuccessful {
179
 			return "", errNicknameInUse
179
 			return "", errNicknameInUse
180
 		}
180
 		}
183
 			operator := client.HasMode(modes.Operator) || client.HasMode(modes.LocalOperator)
183
 			operator := client.HasMode(modes.Operator) || client.HasMode(modes.LocalOperator)
184
 			client.server.stats.AddRegistered(invisible, operator)
184
 			client.server.stats.AddRegistered(invisible, operator)
185
 		}
185
 		}
186
-		session.lastSignoff = lastSignoff
186
+		session.autoreplayMissedSince = lastSeen
187
 		// XXX SetNames only changes names if they are unset, so the realname change only
187
 		// XXX SetNames only changes names if they are unset, so the realname change only
188
 		// takes effect on first attach to an always-on client (good), but the user/ident
188
 		// takes effect on first attach to an always-on client (good), but the user/ident
189
 		// change is always a no-op (bad). we could make user/ident act the same way as
189
 		// change is always a no-op (bad). we could make user/ident act the same way as

+ 3
- 2
irc/commands.go View File

65
 		session.idletimer.Touch()
65
 		session.idletimer.Touch()
66
 	}
66
 	}
67
 
67
 
68
-	if !exiting && client.registered && !cmd.leaveClientIdle {
69
-		client.Active(session)
68
+	// TODO: eliminate idletimer entirely in favor of this measurement
69
+	if client.registered {
70
+		client.Touch(!cmd.leaveClientIdle, session)
70
 	}
71
 	}
71
 
72
 
72
 	return exiting
73
 	return exiting

+ 5
- 15
irc/getters.go View File

79
 			currentIndex = i
79
 			currentIndex = i
80
 		}
80
 		}
81
 		data[i] = SessionData{
81
 		data[i] = SessionData{
82
-			atime:    session.atime,
82
+			atime:    session.lastActive,
83
 			ctime:    session.ctime,
83
 			ctime:    session.ctime,
84
 			hostname: session.rawHostname,
84
 			hostname: session.rawHostname,
85
 			certfp:   session.certfp,
85
 			certfp:   session.certfp,
93
 	return
93
 	return
94
 }
94
 }
95
 
95
 
96
-func (client *Client) AddSession(session *Session) (success bool, numSessions int, lastSignoff time.Time) {
97
-	defer func() {
98
-		if !lastSignoff.IsZero() {
99
-			client.wakeWriter()
100
-		}
101
-	}()
102
-
96
+func (client *Client) AddSession(session *Session) (success bool, numSessions int, lastSeen time.Time) {
103
 	client.stateMutex.Lock()
97
 	client.stateMutex.Lock()
104
 	defer client.stateMutex.Unlock()
98
 	defer client.stateMutex.Unlock()
105
 
99
 
112
 	newSessions := make([]*Session, len(client.sessions)+1)
106
 	newSessions := make([]*Session, len(client.sessions)+1)
113
 	copy(newSessions, client.sessions)
107
 	copy(newSessions, client.sessions)
114
 	newSessions[len(newSessions)-1] = session
108
 	newSessions[len(newSessions)-1] = session
115
-	if len(client.sessions) == 0 && client.accountSettings.AutoreplayMissed {
116
-		// n.b. this is only possible if client is persistent and remained
117
-		// on the server with no sessions:
118
-		lastSignoff = client.lastSignoff
119
-		client.lastSignoff = time.Time{}
120
-		client.dirtyBits |= IncludeLastSignoff
109
+	if client.accountSettings.AutoreplayMissed {
110
+		lastSeen = client.lastSeen
121
 	}
111
 	}
122
 	client.sessions = newSessions
112
 	client.sessions = newSessions
123
-	return true, len(client.sessions), lastSignoff
113
+	return true, len(client.sessions), lastSeen
124
 }
114
 }
125
 
115
 
126
 func (client *Client) removeSession(session *Session) (success bool, length int) {
116
 func (client *Client) removeSession(session *Session) (success bool, length int) {

+ 0
- 12
irc/idletimer.go View File

52
 	quitTimeout time.Duration
52
 	quitTimeout time.Duration
53
 	state       TimerState
53
 	state       TimerState
54
 	timer       *time.Timer
54
 	timer       *time.Timer
55
-	lastTouch   time.Time
56
 }
55
 }
57
 
56
 
58
 // Initialize sets up an IdleTimer and starts counting idle time;
57
 // Initialize sets up an IdleTimer and starts counting idle time;
62
 	it.registerTimeout = RegisterTimeout
61
 	it.registerTimeout = RegisterTimeout
63
 	it.idleTimeout, it.quitTimeout = it.recomputeDurations()
62
 	it.idleTimeout, it.quitTimeout = it.recomputeDurations()
64
 	registered := session.client.Registered()
63
 	registered := session.client.Registered()
65
-	now := time.Now().UTC()
66
 
64
 
67
 	it.Lock()
65
 	it.Lock()
68
 	defer it.Unlock()
66
 	defer it.Unlock()
69
-	it.lastTouch = now
70
 	if registered {
67
 	if registered {
71
 		it.state = TimerActive
68
 		it.state = TimerActive
72
 	} else {
69
 	} else {
95
 
92
 
96
 func (it *IdleTimer) Touch() {
93
 func (it *IdleTimer) Touch() {
97
 	idleTimeout, quitTimeout := it.recomputeDurations()
94
 	idleTimeout, quitTimeout := it.recomputeDurations()
98
-	now := time.Now().UTC()
99
 
95
 
100
 	it.Lock()
96
 	it.Lock()
101
 	defer it.Unlock()
97
 	defer it.Unlock()
102
 	it.idleTimeout, it.quitTimeout = idleTimeout, quitTimeout
98
 	it.idleTimeout, it.quitTimeout = idleTimeout, quitTimeout
103
-	it.lastTouch = now
104
 	// a touch transitions TimerUnregistered or TimerIdle into TimerActive
99
 	// a touch transitions TimerUnregistered or TimerIdle into TimerActive
105
 	if it.state != TimerDead {
100
 	if it.state != TimerDead {
106
 		it.state = TimerActive
101
 		it.state = TimerActive
108
 	}
103
 	}
109
 }
104
 }
110
 
105
 
111
-func (it *IdleTimer) LastTouch() (result time.Time) {
112
-	it.Lock()
113
-	result = it.lastTouch
114
-	it.Unlock()
115
-	return
116
-}
117
-
118
 func (it *IdleTimer) processTimeout() {
106
 func (it *IdleTimer) processTimeout() {
119
 	idleTimeout, quitTimeout := it.recomputeDurations()
107
 	idleTimeout, quitTimeout := it.recomputeDurations()
120
 
108
 

Loading…
Cancel
Save