3
0
mirror of https://github.com/ergochat/ergo.git synced 2024-11-29 23:49:25 +01:00

Merge pull request #1150 from slingamn/monitor.1

fix #1053, #1083
This commit is contained in:
Shivaram Lingamneni 2020-06-22 20:25:27 -07:00 committed by GitHub
commit 7ee7b1aab5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 46 additions and 46 deletions

View File

@ -1316,6 +1316,9 @@ func (client *Client) destroy(session *Session) {
session.SetDestroyed() session.SetDestroyed()
session.socket.Close() session.socket.Close()
// clean up monitor state
client.server.monitorManager.RemoveAll(session)
// remove from connection limits // remove from connection limits
var source string var source string
if session.isTor { if session.isTor {
@ -1381,8 +1384,6 @@ func (client *Client) destroy(session *Session) {
if registered { if registered {
client.server.monitorManager.AlertAbout(details.nick, details.nickCasefolded, false) client.server.monitorManager.AlertAbout(details.nick, details.nickCasefolded, false)
} }
// clean up monitor state
client.server.monitorManager.RemoveAll(client)
// clean up channels // clean up channels
// (note that if this is a reattach, client has no channels and therefore no friends) // (note that if this is a reattach, client has no channels and therefore no friends)

View File

@ -1722,11 +1722,7 @@ func monitorRemoveHandler(server *Server, client *Client, msg ircmsg.IrcMessage,
targets := strings.Split(msg.Params[1], ",") targets := strings.Split(msg.Params[1], ",")
for _, target := range targets { for _, target := range targets {
cfnick, err := CasefoldName(target) server.monitorManager.Remove(rb.session, target)
if err != nil {
continue
}
server.monitorManager.Remove(client, cfnick)
} }
return false return false
@ -1752,12 +1748,7 @@ func monitorAddHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb
} }
// add target // add target
casefoldedTarget, err := CasefoldName(target) err := server.monitorManager.Add(rb.session, target, limits.MonitorEntries)
if err != nil {
continue
}
err = server.monitorManager.Add(client, casefoldedTarget, limits.MonitorEntries)
if err == errMonitorLimitExceeded { if err == errMonitorLimitExceeded {
rb.Add(nil, server.name, ERR_MONLISTFULL, client.Nick(), strconv.Itoa(limits.MonitorEntries), strings.Join(targets, ",")) rb.Add(nil, server.name, ERR_MONLISTFULL, client.Nick(), strconv.Itoa(limits.MonitorEntries), strings.Join(targets, ","))
break break
@ -1786,14 +1777,14 @@ func monitorAddHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb
// MONITOR C // MONITOR C
func monitorClearHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *ResponseBuffer) bool { func monitorClearHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *ResponseBuffer) bool {
server.monitorManager.RemoveAll(client) server.monitorManager.RemoveAll(rb.session)
return false return false
} }
// MONITOR L // MONITOR L
func monitorListHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *ResponseBuffer) bool { func monitorListHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *ResponseBuffer) bool {
nick := client.Nick() nick := client.Nick()
monitorList := server.monitorManager.List(client) monitorList := server.monitorManager.List(rb.session)
var nickList []string var nickList []string
for _, cfnick := range monitorList { for _, cfnick := range monitorList {
@ -1820,7 +1811,7 @@ func monitorStatusHandler(server *Server, client *Client, msg ircmsg.IrcMessage,
var online []string var online []string
var offline []string var offline []string
monitorList := server.monitorManager.List(client) monitorList := server.monitorManager.List(rb.session)
for _, name := range monitorList { for _, name := range monitorList {
currentNick := server.getCurrentNick(name) currentNick := server.getCurrentNick(name)

View File

@ -12,25 +12,24 @@ import (
// MonitorManager keeps track of who's monitoring which nicks. // MonitorManager keeps track of who's monitoring which nicks.
type MonitorManager struct { type MonitorManager struct {
sync.RWMutex // tier 2 sync.RWMutex // tier 2
// client -> nicks it's watching // client -> (casefolded nick it's watching -> uncasefolded nick)
watching map[*Client]map[string]bool watching map[*Session]map[string]string
// nick -> clients watching it // casefolded nick -> clients watching it
watchedby map[string]map[*Client]bool watchedby map[string]map[*Session]empty
// (all nicks must be normalized externally by casefolding)
} }
func (mm *MonitorManager) Initialize() { func (mm *MonitorManager) Initialize() {
mm.watching = make(map[*Client]map[string]bool) mm.watching = make(map[*Session]map[string]string)
mm.watchedby = make(map[string]map[*Client]bool) mm.watchedby = make(map[string]map[*Session]empty)
} }
// AlertAbout alerts everyone monitoring `client`'s nick that `client` is now {on,off}line. // AlertAbout alerts everyone monitoring `client`'s nick that `client` is now {on,off}line.
func (manager *MonitorManager) AlertAbout(nick, cfnick string, online bool) { func (manager *MonitorManager) AlertAbout(nick, cfnick string, online bool) {
var watchers []*Client var watchers []*Session
// safely copy the list of clients watching our nick // safely copy the list of clients watching our nick
manager.RLock() manager.RLock()
for client := range manager.watchedby[cfnick] { for session := range manager.watchedby[cfnick] {
watchers = append(watchers, client) watchers = append(watchers, session)
} }
manager.RUnlock() manager.RUnlock()
@ -39,58 +38,67 @@ func (manager *MonitorManager) AlertAbout(nick, cfnick string, online bool) {
command = RPL_MONONLINE command = RPL_MONONLINE
} }
for _, mClient := range watchers { for _, session := range watchers {
mClient.Send(nil, mClient.server.name, command, mClient.Nick(), nick) session.Send(nil, session.client.server.name, command, session.client.Nick(), nick)
} }
} }
// Add registers `client` to receive notifications about `nick`. // Add registers `client` to receive notifications about `nick`.
func (manager *MonitorManager) Add(client *Client, nick string, limit int) error { func (manager *MonitorManager) Add(session *Session, nick string, limit int) error {
cfnick, err := CasefoldName(nick)
if err != nil {
return err
}
manager.Lock() manager.Lock()
defer manager.Unlock() defer manager.Unlock()
if manager.watching[client] == nil { if manager.watching[session] == nil {
manager.watching[client] = make(map[string]bool) manager.watching[session] = make(map[string]string)
} }
if manager.watchedby[nick] == nil { if manager.watchedby[cfnick] == nil {
manager.watchedby[nick] = make(map[*Client]bool) manager.watchedby[cfnick] = make(map[*Session]empty)
} }
if len(manager.watching[client]) >= limit { if len(manager.watching[session]) >= limit {
return errMonitorLimitExceeded return errMonitorLimitExceeded
} }
manager.watching[client][nick] = true manager.watching[session][cfnick] = nick
manager.watchedby[nick][client] = true manager.watchedby[cfnick][session] = empty{}
return nil return nil
} }
// Remove unregisters `client` from receiving notifications about `nick`. // Remove unregisters `client` from receiving notifications about `nick`.
func (manager *MonitorManager) Remove(client *Client, nick string) error { func (manager *MonitorManager) Remove(session *Session, nick string) (err error) {
cfnick, err := CasefoldName(nick)
if err != nil {
return
}
manager.Lock() manager.Lock()
defer manager.Unlock() defer manager.Unlock()
// deleting from nil maps is fine delete(manager.watching[session], cfnick)
delete(manager.watching[client], nick) delete(manager.watchedby[cfnick], session)
delete(manager.watchedby[nick], client)
return nil return nil
} }
// RemoveAll unregisters `client` from receiving notifications about *all* nicks. // RemoveAll unregisters `client` from receiving notifications about *all* nicks.
func (manager *MonitorManager) RemoveAll(client *Client) { func (manager *MonitorManager) RemoveAll(session *Session) {
manager.Lock() manager.Lock()
defer manager.Unlock() defer manager.Unlock()
for nick := range manager.watching[client] { for cfnick := range manager.watching[session] {
delete(manager.watchedby[nick], client) delete(manager.watchedby[cfnick], session)
} }
delete(manager.watching, client) delete(manager.watching, session)
} }
// List lists all nicks that `client` is registered to receive notifications about. // List lists all nicks that `client` is registered to receive notifications about.
func (manager *MonitorManager) List(client *Client) (nicks []string) { func (manager *MonitorManager) List(session *Session) (nicks []string) {
manager.RLock() manager.RLock()
defer manager.RUnlock() defer manager.RUnlock()
for nick := range manager.watching[client] { for _, nick := range manager.watching[session] {
nicks = append(nicks, nick) nicks = append(nicks, nick)
} }
return nicks return nicks