Browse Source

persist lastSignoff in the database

tags/v2.0.0-rc1
Shivaram Lingamneni 4 years ago
parent
commit
4472683d58
3 changed files with 66 additions and 9 deletions
  1. 34
    1
      irc/accounts.go
  2. 25
    8
      irc/client.go
  3. 7
    0
      irc/getters.go

+ 34
- 1
irc/accounts.go View File

@@ -35,6 +35,7 @@ const (
35 35
 	keyCertToAccount           = "account.creds.certfp %s"
36 36
 	keyAccountChannels         = "account.channels %s" // channels registered to the account
37 37
 	keyAccountJoinedChannels   = "account.joinedto %s" // channels a persistent client has joined
38
+	keyAccountLastSignoff      = "account.lastsignoff %s"
38 39
 
39 40
 	keyVHostQueueAcctToId = "vhostQueue %s"
40 41
 	vhostRequestIdx       = "vhostQueue"
@@ -103,7 +104,7 @@ func (am *AccountManager) createAlwaysOnClients(config *Config) {
103 104
 		account, err := am.LoadAccount(accountName)
104 105
 		if err == nil && account.Verified &&
105 106
 			persistenceEnabled(config.Accounts.Bouncer.AlwaysOn, account.Settings.AlwaysOn) {
106
-			am.server.AddAlwaysOnClient(account, am.loadChannels(accountName))
107
+			am.server.AddAlwaysOnClient(account, am.loadChannels(accountName), am.loadLastSignoff(accountName))
107 108
 		}
108 109
 	}
109 110
 }
@@ -534,6 +535,36 @@ func (am *AccountManager) loadChannels(account string) (channels []string) {
534 535
 	return
535 536
 }
536 537
 
538
+func (am *AccountManager) saveLastSignoff(account string, lastSignoff time.Time) {
539
+	key := fmt.Sprintf(keyAccountLastSignoff, account)
540
+	var val string
541
+	if !lastSignoff.IsZero() {
542
+		val = strconv.FormatInt(lastSignoff.UnixNano(), 10)
543
+	}
544
+	am.server.store.Update(func(tx *buntdb.Tx) error {
545
+		if val != "" {
546
+			tx.Set(key, val, nil)
547
+		} else {
548
+			tx.Delete(key)
549
+		}
550
+		return nil
551
+	})
552
+}
553
+
554
+func (am *AccountManager) loadLastSignoff(account string) (lastSignoff time.Time) {
555
+	key := fmt.Sprintf(keyAccountLastSignoff, account)
556
+	var lsText string
557
+	am.server.store.View(func(tx *buntdb.Tx) error {
558
+		lsText, _ = tx.Get(key)
559
+		return nil
560
+	})
561
+	lsNum, err := strconv.ParseInt(lsText, 10, 64)
562
+	if err != nil {
563
+		return time.Unix(0, lsNum)
564
+	}
565
+	return
566
+}
567
+
537 568
 func (am *AccountManager) addRemoveCertfp(account, certfp string, add bool, hasPrivs bool) (err error) {
538 569
 	certfp, err = utils.NormalizeCertfp(certfp)
539 570
 	if err != nil {
@@ -1034,6 +1065,7 @@ func (am *AccountManager) Unregister(account string) error {
1034 1065
 	vhostQueueKey := fmt.Sprintf(keyVHostQueueAcctToId, casefoldedAccount)
1035 1066
 	channelsKey := fmt.Sprintf(keyAccountChannels, casefoldedAccount)
1036 1067
 	joinedChannelsKey := fmt.Sprintf(keyAccountJoinedChannels, casefoldedAccount)
1068
+	lastSignoffKey := fmt.Sprintf(keyAccountLastSignoff, casefoldedAccount)
1037 1069
 
1038 1070
 	var clients []*Client
1039 1071
 
@@ -1070,6 +1102,7 @@ func (am *AccountManager) Unregister(account string) error {
1070 1102
 		channelsStr, _ = tx.Get(channelsKey)
1071 1103
 		tx.Delete(channelsKey)
1072 1104
 		tx.Delete(joinedChannelsKey)
1105
+		tx.Delete(lastSignoffKey)
1073 1106
 
1074 1107
 		_, err := tx.Delete(vhostQueueKey)
1075 1108
 		am.decrementVHostQueueCount(casefoldedAccount, err)

+ 25
- 8
irc/client.go View File

@@ -306,7 +306,7 @@ func (server *Server) RunClient(conn clientConn, proxyLine string) {
306 306
 	client.run(session, proxyLine)
307 307
 }
308 308
 
309
-func (server *Server) AddAlwaysOnClient(account ClientAccount, chnames []string) {
309
+func (server *Server) AddAlwaysOnClient(account ClientAccount, chnames []string, lastSignoff time.Time) {
310 310
 	now := time.Now().UTC()
311 311
 	config := server.Config()
312 312
 
@@ -322,7 +322,8 @@ func (server *Server) AddAlwaysOnClient(account ClientAccount, chnames []string)
322 322
 		rawHostname: server.name,
323 323
 		realIP:      utils.IPv4LoopbackAddress,
324 324
 
325
-		alwaysOn: true,
325
+		alwaysOn:    true,
326
+		lastSignoff: lastSignoff,
326 327
 	}
327 328
 
328 329
 	client.SetMode(modes.TLS, true)
@@ -1187,10 +1188,17 @@ func (client *Client) destroy(session *Session) {
1187 1188
 	}
1188 1189
 	if alwaysOn && remainingSessions == 0 {
1189 1190
 		client.lastSignoff = lastSignoff
1191
+		client.dirtyBits |= IncludeLastSignoff
1192
+	} else {
1193
+		lastSignoff = time.Time{}
1190 1194
 	}
1191 1195
 	exitedSnomaskSent := client.exitedSnomaskSent
1192 1196
 	client.stateMutex.Unlock()
1193 1197
 
1198
+	if !lastSignoff.IsZero() {
1199
+		client.wakeWriter()
1200
+	}
1201
+
1194 1202
 	// destroy all applicable sessions:
1195 1203
 	var quitMessage string
1196 1204
 	for _, session := range sessionsToDestroy {
@@ -1573,6 +1581,7 @@ func (client *Client) historyStatus(config *Config) (persistent, ephemeral bool,
1573 1581
 // TODO add a dirty flag for lastSignoff
1574 1582
 const (
1575 1583
 	IncludeChannels uint = 1 << iota
1584
+	IncludeLastSignoff
1576 1585
 )
1577 1586
 
1578 1587
 func (client *Client) markDirty(dirtyBits uint) {
@@ -1609,7 +1618,7 @@ func (client *Client) writeLoop() {
1609 1618
 
1610 1619
 func (client *Client) performWrite() {
1611 1620
 	client.stateMutex.Lock()
1612
-	// TODO actually read dirtyBits in the future
1621
+	dirtyBits := client.dirtyBits
1613 1622
 	client.dirtyBits = 0
1614 1623
 	account := client.account
1615 1624
 	client.stateMutex.Unlock()
@@ -1619,10 +1628,18 @@ func (client *Client) performWrite() {
1619 1628
 		return
1620 1629
 	}
1621 1630
 
1622
-	channels := client.Channels()
1623
-	channelNames := make([]string, len(channels))
1624
-	for i, channel := range channels {
1625
-		channelNames[i] = channel.Name()
1631
+	if (dirtyBits & IncludeChannels) != 0 {
1632
+		channels := client.Channels()
1633
+		channelNames := make([]string, len(channels))
1634
+		for i, channel := range channels {
1635
+			channelNames[i] = channel.Name()
1636
+		}
1637
+		client.server.accounts.saveChannels(account, channelNames)
1638
+	}
1639
+	if (dirtyBits & IncludeLastSignoff) != 0 {
1640
+		client.stateMutex.RLock()
1641
+		lastSignoff := client.lastSignoff
1642
+		client.stateMutex.RUnlock()
1643
+		client.server.accounts.saveLastSignoff(account, lastSignoff)
1626 1644
 	}
1627
-	client.server.accounts.saveChannels(account, channelNames)
1628 1645
 }

+ 7
- 0
irc/getters.go View File

@@ -94,6 +94,12 @@ func (client *Client) AllSessionData(currentSession *Session) (data []SessionDat
94 94
 }
95 95
 
96 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
+
97 103
 	client.stateMutex.Lock()
98 104
 	defer client.stateMutex.Unlock()
99 105
 
@@ -111,6 +117,7 @@ func (client *Client) AddSession(session *Session) (success bool, numSessions in
111 117
 		// on the server with no sessions:
112 118
 		lastSignoff = client.lastSignoff
113 119
 		client.lastSignoff = time.Time{}
120
+		client.dirtyBits |= IncludeLastSignoff
114 121
 	}
115 122
 	client.sessions = newSessions
116 123
 	return true, len(client.sessions), lastSignoff

Loading…
Cancel
Save