3
0
mirror of https://github.com/ergochat/ergo.git synced 2024-11-29 07:29:31 +01:00
ergo/irc/monitor.go

130 lines
3.5 KiB
Go
Raw Normal View History

2017-03-27 14:15:02 +02:00
// Copyright (c) 2016-2017 Daniel Oaks <daniel@danieloaks.net>
2016-10-16 12:14:56 +02:00
// released under the MIT license
package irc
import (
"sync"
2016-10-16 12:14:56 +02:00
"github.com/ergochat/ergo/irc/caps"
2022-03-30 06:44:51 +02:00
"github.com/ergochat/ergo/irc/utils"
"github.com/ergochat/irc-go/ircmsg"
2016-10-16 12:14:56 +02:00
)
2017-10-05 15:29:34 +02:00
// MonitorManager keeps track of who's monitoring which nicks.
type MonitorManager struct {
2017-11-22 10:41:11 +01:00
sync.RWMutex // tier 2
2020-06-22 05:51:31 +02:00
// client -> (casefolded nick it's watching -> uncasefolded nick)
watching map[*Session]map[string]string
// casefolded nick -> clients watching it
2022-03-30 06:44:51 +02:00
watchedby map[string]utils.HashSet[*Session]
}
2019-05-12 10:30:48 +02:00
func (mm *MonitorManager) Initialize() {
2020-06-22 05:51:31 +02:00
mm.watching = make(map[*Session]map[string]string)
2022-03-30 06:44:51 +02:00
mm.watchedby = make(map[string]utils.HashSet[*Session])
2016-10-16 12:14:56 +02:00
}
// AddMonitors adds clients using extended-monitor monitoring `client`'s nick to the passed user set.
2022-03-30 06:44:51 +02:00
func (manager *MonitorManager) AddMonitors(users utils.HashSet[*Session], cfnick string, capabs ...caps.Capability) {
manager.RLock()
defer manager.RUnlock()
for session := range manager.watchedby[cfnick] {
if session.capabilities.Has(caps.ExtendedMonitor) && session.capabilities.HasAll(capabs...) {
2022-03-30 06:44:51 +02:00
users.Add(session)
}
}
}
// AlertAbout alerts everyone monitoring `client`'s nick that `client` is now {on,off}line.
2020-05-28 23:55:53 +02:00
func (manager *MonitorManager) AlertAbout(nick, cfnick string, online bool) {
2020-06-22 05:51:31 +02:00
var watchers []*Session
// safely copy the list of clients watching our nick
manager.RLock()
2020-06-22 05:51:31 +02:00
for session := range manager.watchedby[cfnick] {
watchers = append(watchers, session)
}
manager.RUnlock()
command := RPL_MONOFFLINE
if online {
command = RPL_MONONLINE
}
2020-06-22 05:51:31 +02:00
for _, session := range watchers {
session.Send(nil, session.client.server.name, command, session.client.Nick(), nick)
2017-10-30 10:21:47 +01:00
}
}
// Add registers `client` to receive notifications about `nick`.
2020-06-22 05:51:31 +02:00
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()
2020-06-22 05:51:31 +02:00
if manager.watching[session] == nil {
manager.watching[session] = make(map[string]string)
}
2020-06-22 05:51:31 +02:00
if manager.watchedby[cfnick] == nil {
2022-03-30 06:44:51 +02:00
manager.watchedby[cfnick] = make(utils.HashSet[*Session])
2016-10-16 12:14:56 +02:00
}
2020-06-22 05:51:31 +02:00
if len(manager.watching[session]) >= limit {
2018-02-03 13:03:36 +01:00
return errMonitorLimitExceeded
}
2020-06-22 05:51:31 +02:00
manager.watching[session][cfnick] = nick
2022-03-30 06:44:51 +02:00
manager.watchedby[cfnick].Add(session)
return nil
}
// Remove unregisters `client` from receiving notifications about `nick`.
2020-06-22 05:51:31 +02:00
func (manager *MonitorManager) Remove(session *Session, nick string) (err error) {
cfnick, err := CasefoldName(nick)
if err != nil {
return
}
manager.Lock()
defer manager.Unlock()
2020-06-22 05:51:31 +02:00
delete(manager.watching[session], cfnick)
2022-03-30 06:44:51 +02:00
manager.watchedby[cfnick].Remove(session)
return nil
}
// RemoveAll unregisters `client` from receiving notifications about *all* nicks.
2020-06-22 05:51:31 +02:00
func (manager *MonitorManager) RemoveAll(session *Session) {
manager.Lock()
defer manager.Unlock()
2020-06-22 05:51:31 +02:00
for cfnick := range manager.watching[session] {
2022-03-30 06:44:51 +02:00
manager.watchedby[cfnick].Remove(session)
}
2020-06-22 05:51:31 +02:00
delete(manager.watching, session)
}
// List lists all nicks that `client` is registered to receive notifications about.
2020-06-22 05:51:31 +02:00
func (manager *MonitorManager) List(session *Session) (nicks []string) {
manager.RLock()
defer manager.RUnlock()
2020-06-22 05:51:31 +02:00
for _, nick := range manager.watching[session] {
nicks = append(nicks, nick)
}
return nicks
2016-10-16 12:14:56 +02:00
}
var (
2021-03-11 02:07:43 +01:00
monitorSubcommands = map[string]func(server *Server, client *Client, msg ircmsg.Message, rb *ResponseBuffer) bool{
2016-10-16 12:14:56 +02:00
"-": monitorRemoveHandler,
"+": monitorAddHandler,
"c": monitorClearHandler,
"l": monitorListHandler,
"s": monitorStatusHandler,
}
)