From cb530050f1f3030ba94a7c2b61bd7095db9cbfe7 Mon Sep 17 00:00:00 2001 From: Shivaram Lingamneni Date: Sun, 21 Jun 2020 23:51:31 -0400 Subject: [PATCH] fix #1053, #1083 --- irc/client.go | 5 ++-- irc/handlers.go | 19 ++++---------- irc/monitor.go | 68 +++++++++++++++++++++++++++---------------------- 3 files changed, 46 insertions(+), 46 deletions(-) diff --git a/irc/client.go b/irc/client.go index 4a36e926..d7b612aa 100644 --- a/irc/client.go +++ b/irc/client.go @@ -1316,6 +1316,9 @@ func (client *Client) destroy(session *Session) { session.SetDestroyed() session.socket.Close() + // clean up monitor state + client.server.monitorManager.RemoveAll(session) + // remove from connection limits var source string if session.isTor { @@ -1381,8 +1384,6 @@ func (client *Client) destroy(session *Session) { if registered { client.server.monitorManager.AlertAbout(details.nick, details.nickCasefolded, false) } - // clean up monitor state - client.server.monitorManager.RemoveAll(client) // clean up channels // (note that if this is a reattach, client has no channels and therefore no friends) diff --git a/irc/handlers.go b/irc/handlers.go index c4f9d515..5d263a9c 100644 --- a/irc/handlers.go +++ b/irc/handlers.go @@ -1722,11 +1722,7 @@ func monitorRemoveHandler(server *Server, client *Client, msg ircmsg.IrcMessage, targets := strings.Split(msg.Params[1], ",") for _, target := range targets { - cfnick, err := CasefoldName(target) - if err != nil { - continue - } - server.monitorManager.Remove(client, cfnick) + server.monitorManager.Remove(rb.session, target) } return false @@ -1752,12 +1748,7 @@ func monitorAddHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb } // add target - casefoldedTarget, err := CasefoldName(target) - if err != nil { - continue - } - - err = server.monitorManager.Add(client, casefoldedTarget, limits.MonitorEntries) + err := server.monitorManager.Add(rb.session, target, limits.MonitorEntries) if err == errMonitorLimitExceeded { rb.Add(nil, server.name, ERR_MONLISTFULL, client.Nick(), strconv.Itoa(limits.MonitorEntries), strings.Join(targets, ",")) break @@ -1786,14 +1777,14 @@ func monitorAddHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb // MONITOR C func monitorClearHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *ResponseBuffer) bool { - server.monitorManager.RemoveAll(client) + server.monitorManager.RemoveAll(rb.session) return false } // MONITOR L func monitorListHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *ResponseBuffer) bool { nick := client.Nick() - monitorList := server.monitorManager.List(client) + monitorList := server.monitorManager.List(rb.session) var nickList []string for _, cfnick := range monitorList { @@ -1820,7 +1811,7 @@ func monitorStatusHandler(server *Server, client *Client, msg ircmsg.IrcMessage, var online []string var offline []string - monitorList := server.monitorManager.List(client) + monitorList := server.monitorManager.List(rb.session) for _, name := range monitorList { currentNick := server.getCurrentNick(name) diff --git a/irc/monitor.go b/irc/monitor.go index e9cde7c4..b20aa4ea 100644 --- a/irc/monitor.go +++ b/irc/monitor.go @@ -12,25 +12,24 @@ import ( // MonitorManager keeps track of who's monitoring which nicks. type MonitorManager struct { sync.RWMutex // tier 2 - // client -> nicks it's watching - watching map[*Client]map[string]bool - // nick -> clients watching it - watchedby map[string]map[*Client]bool - // (all nicks must be normalized externally by casefolding) + // client -> (casefolded nick it's watching -> uncasefolded nick) + watching map[*Session]map[string]string + // casefolded nick -> clients watching it + watchedby map[string]map[*Session]empty } func (mm *MonitorManager) Initialize() { - mm.watching = make(map[*Client]map[string]bool) - mm.watchedby = make(map[string]map[*Client]bool) + mm.watching = make(map[*Session]map[string]string) + mm.watchedby = make(map[string]map[*Session]empty) } // AlertAbout alerts everyone monitoring `client`'s nick that `client` is now {on,off}line. func (manager *MonitorManager) AlertAbout(nick, cfnick string, online bool) { - var watchers []*Client + var watchers []*Session // safely copy the list of clients watching our nick manager.RLock() - for client := range manager.watchedby[cfnick] { - watchers = append(watchers, client) + for session := range manager.watchedby[cfnick] { + watchers = append(watchers, session) } manager.RUnlock() @@ -39,58 +38,67 @@ func (manager *MonitorManager) AlertAbout(nick, cfnick string, online bool) { command = RPL_MONONLINE } - for _, mClient := range watchers { - mClient.Send(nil, mClient.server.name, command, mClient.Nick(), nick) + for _, session := range watchers { + session.Send(nil, session.client.server.name, command, session.client.Nick(), 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() defer manager.Unlock() - if manager.watching[client] == nil { - manager.watching[client] = make(map[string]bool) + if manager.watching[session] == nil { + manager.watching[session] = make(map[string]string) } - if manager.watchedby[nick] == nil { - manager.watchedby[nick] = make(map[*Client]bool) + if manager.watchedby[cfnick] == nil { + manager.watchedby[cfnick] = make(map[*Session]empty) } - if len(manager.watching[client]) >= limit { + if len(manager.watching[session]) >= limit { return errMonitorLimitExceeded } - manager.watching[client][nick] = true - manager.watchedby[nick][client] = true + manager.watching[session][cfnick] = nick + manager.watchedby[cfnick][session] = empty{} return nil } // 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() defer manager.Unlock() - // deleting from nil maps is fine - delete(manager.watching[client], nick) - delete(manager.watchedby[nick], client) + delete(manager.watching[session], cfnick) + delete(manager.watchedby[cfnick], session) return nil } // RemoveAll unregisters `client` from receiving notifications about *all* nicks. -func (manager *MonitorManager) RemoveAll(client *Client) { +func (manager *MonitorManager) RemoveAll(session *Session) { manager.Lock() defer manager.Unlock() - for nick := range manager.watching[client] { - delete(manager.watchedby[nick], client) + for cfnick := range manager.watching[session] { + 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. -func (manager *MonitorManager) List(client *Client) (nicks []string) { +func (manager *MonitorManager) List(session *Session) (nicks []string) { manager.RLock() defer manager.RUnlock() - for nick := range manager.watching[client] { + for _, nick := range manager.watching[session] { nicks = append(nicks, nick) } return nicks