mirror of
https://github.com/ergochat/ergo.git
synced 2025-12-20 02:00:11 -08:00
refactor monitor and /oper implementations
This commit is contained in:
parent
5e9767c46d
commit
26686d7e86
5 changed files with 185 additions and 173 deletions
236
irc/monitor.go
236
irc/monitor.go
|
|
@ -4,50 +4,108 @@
|
|||
package irc
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/goshuirc/irc-go/ircmsg"
|
||||
)
|
||||
|
||||
// alertMonitors alerts everyone monitoring us that we're online.
|
||||
func (client *Client) alertMonitors() {
|
||||
// get monitors
|
||||
client.server.monitoringMutex.RLock()
|
||||
monitors := client.server.monitoring[client.nickCasefolded]
|
||||
client.server.monitoringMutex.RUnlock()
|
||||
type MonitorManager struct {
|
||||
sync.RWMutex
|
||||
// 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)
|
||||
}
|
||||
|
||||
// alert monitors
|
||||
for _, mClient := range monitors {
|
||||
// don't have to notify ourselves
|
||||
if mClient != client {
|
||||
mClient.SendFromClient("", client, nil, RPL_MONONLINE, mClient.nick, client.nickMaskString)
|
||||
}
|
||||
func NewMonitorManager() *MonitorManager {
|
||||
mm := MonitorManager{
|
||||
watching: make(map[*Client]map[string]bool),
|
||||
watchedby: make(map[string]map[*Client]bool),
|
||||
}
|
||||
return &mm
|
||||
}
|
||||
|
||||
var MonitorLimitExceeded = errors.New("Monitor limit exceeded")
|
||||
|
||||
// alertMonitors alerts everyone monitoring us that we're online.
|
||||
func (manager *MonitorManager) alertMonitors(client *Client, online bool) {
|
||||
cfnick := client.getNickCasefolded()
|
||||
nick := client.getNick()
|
||||
var watchers []*Client
|
||||
// safely copy the list of clients watching our nick
|
||||
manager.RLock()
|
||||
for client := range manager.watchedby[cfnick] {
|
||||
watchers = append(watchers, client)
|
||||
}
|
||||
manager.RUnlock()
|
||||
|
||||
command := RPL_MONOFFLINE
|
||||
if online {
|
||||
command = RPL_MONONLINE
|
||||
}
|
||||
|
||||
// asynchronously send all the notifications
|
||||
go func() {
|
||||
for _, mClient := range watchers {
|
||||
// don't have to notify ourselves
|
||||
if mClient != client {
|
||||
mClient.SendFromClient("", client, nil, command, mClient.getNick(), nick)
|
||||
}
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
// clearMonitorList clears our MONITOR list.
|
||||
func (client *Client) clearMonitorList() {
|
||||
// lockin' everything
|
||||
client.monitoringMutex.Lock()
|
||||
defer client.monitoringMutex.Unlock()
|
||||
client.server.monitoringMutex.Lock()
|
||||
defer client.server.monitoringMutex.Unlock()
|
||||
func (manager *MonitorManager) clearMonitorList(client *Client) {
|
||||
manager.Lock()
|
||||
defer manager.Unlock()
|
||||
|
||||
for name := range client.monitoring {
|
||||
// just removes current client from the list
|
||||
orig := client.server.monitoring[name]
|
||||
var index int
|
||||
for i, cli := range orig {
|
||||
if cli == client {
|
||||
index = i
|
||||
break
|
||||
}
|
||||
}
|
||||
client.server.monitoring[name] = append(orig[:index], orig[index+1:]...)
|
||||
for nick, _ := range manager.watching[client] {
|
||||
delete(manager.watchedby[nick], client)
|
||||
}
|
||||
delete(manager.watching, client)
|
||||
}
|
||||
|
||||
func (manager *MonitorManager) addMonitor(client *Client, nick string, limit int) error {
|
||||
manager.Lock()
|
||||
defer manager.Unlock()
|
||||
|
||||
if manager.watching[client] == nil {
|
||||
manager.watching[client] = make(map[string]bool)
|
||||
}
|
||||
if manager.watchedby[nick] == nil {
|
||||
manager.watchedby[nick] = make(map[*Client]bool)
|
||||
}
|
||||
|
||||
client.monitoring = make(map[string]bool)
|
||||
if len(manager.watching[client]) >= limit {
|
||||
return MonitorLimitExceeded
|
||||
}
|
||||
|
||||
manager.watching[client][nick] = true
|
||||
manager.watchedby[nick][client] = true
|
||||
return nil
|
||||
}
|
||||
|
||||
func (manager *MonitorManager) removeMonitor(client *Client, nick string) error {
|
||||
manager.Lock()
|
||||
defer manager.Unlock()
|
||||
// deleting from nil maps is fine
|
||||
delete(manager.watching[client], nick)
|
||||
delete(manager.watchedby[nick], client)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (manager *MonitorManager) listMonitors(client *Client) (nicks []string) {
|
||||
manager.RLock()
|
||||
defer manager.RUnlock()
|
||||
for nick := range manager.watching[client] {
|
||||
nicks = append(nicks, nick)
|
||||
}
|
||||
return nicks
|
||||
}
|
||||
|
||||
var (
|
||||
|
|
@ -64,7 +122,7 @@ func monitorHandler(server *Server, client *Client, msg ircmsg.IrcMessage) bool
|
|||
handler, exists := metadataSubcommands[strings.ToLower(msg.Params[0])]
|
||||
|
||||
if !exists {
|
||||
client.Send(nil, server.name, ERR_UNKNOWNERROR, client.nick, "MONITOR", msg.Params[0], "Unknown subcommand")
|
||||
client.Send(nil, server.name, ERR_UNKNOWNERROR, client.getNick(), "MONITOR", msg.Params[0], "Unknown subcommand")
|
||||
return false
|
||||
}
|
||||
|
||||
|
|
@ -73,49 +131,17 @@ func monitorHandler(server *Server, client *Client, msg ircmsg.IrcMessage) bool
|
|||
|
||||
func monitorRemoveHandler(server *Server, client *Client, msg ircmsg.IrcMessage) bool {
|
||||
if len(msg.Params) < 2 {
|
||||
client.Send(nil, server.name, ERR_NEEDMOREPARAMS, client.nick, msg.Command, "Not enough parameters")
|
||||
client.Send(nil, server.name, ERR_NEEDMOREPARAMS, client.getNick(), msg.Command, "Not enough parameters")
|
||||
return false
|
||||
}
|
||||
|
||||
targets := strings.Split(msg.Params[1], ",")
|
||||
for len(targets) > 0 {
|
||||
// check name length
|
||||
if len(targets[0]) < 1 {
|
||||
targets = targets[1:]
|
||||
continue
|
||||
}
|
||||
|
||||
// remove target
|
||||
casefoldedTarget, err := CasefoldName(targets[0])
|
||||
for _, target := range targets {
|
||||
cfnick, err := CasefoldName(target)
|
||||
if err != nil {
|
||||
// skip silently I guess
|
||||
targets = targets[1:]
|
||||
continue
|
||||
}
|
||||
|
||||
client.monitoringMutex.Lock()
|
||||
client.server.monitoringMutex.Lock()
|
||||
|
||||
if client.monitoring[casefoldedTarget] {
|
||||
// just removes current client from the list
|
||||
orig := server.monitoring[casefoldedTarget]
|
||||
var index int
|
||||
for i, cli := range orig {
|
||||
if cli == client {
|
||||
index = i
|
||||
break
|
||||
}
|
||||
}
|
||||
server.monitoring[casefoldedTarget] = append(orig[:index], orig[index+1:]...)
|
||||
|
||||
delete(client.monitoring, casefoldedTarget)
|
||||
}
|
||||
|
||||
client.monitoringMutex.Unlock()
|
||||
client.server.monitoringMutex.Unlock()
|
||||
|
||||
// remove first element of targets list
|
||||
targets = targets[1:]
|
||||
server.monitorManager.removeMonitor(client, cfnick)
|
||||
}
|
||||
|
||||
return false
|
||||
|
|
@ -123,88 +149,68 @@ func monitorRemoveHandler(server *Server, client *Client, msg ircmsg.IrcMessage)
|
|||
|
||||
func monitorAddHandler(server *Server, client *Client, msg ircmsg.IrcMessage) bool {
|
||||
if len(msg.Params) < 2 {
|
||||
client.Send(nil, server.name, ERR_NEEDMOREPARAMS, client.nick, msg.Command, "Not enough parameters")
|
||||
client.Send(nil, server.name, ERR_NEEDMOREPARAMS, client.getNick(), msg.Command, "Not enough parameters")
|
||||
return false
|
||||
}
|
||||
|
||||
var online []string
|
||||
var offline []string
|
||||
|
||||
targets := strings.Split(msg.Params[1], ",")
|
||||
for len(targets) > 0 {
|
||||
// check name length
|
||||
if len(targets[0]) < 1 || len(targets[0]) > server.limits.NickLen {
|
||||
targets = targets[1:]
|
||||
continue
|
||||
}
|
||||
limit := server.getLimits().MonitorEntries
|
||||
|
||||
// check the monitor list length
|
||||
if len(client.monitoring) >= server.limits.MonitorEntries {
|
||||
client.Send(nil, server.name, ERR_MONLISTFULL, client.nick, strconv.Itoa(server.limits.MonitorEntries), strings.Join(targets, ","))
|
||||
break
|
||||
targets := strings.Split(msg.Params[1], ",")
|
||||
for _, target := range targets {
|
||||
// check name length
|
||||
if len(target) < 1 || len(targets) > server.limits.NickLen {
|
||||
continue
|
||||
}
|
||||
|
||||
// add target
|
||||
casefoldedTarget, err := CasefoldName(targets[0])
|
||||
if err != nil {
|
||||
// skip silently I guess
|
||||
targets = targets[1:]
|
||||
continue
|
||||
}
|
||||
|
||||
client.monitoringMutex.Lock()
|
||||
client.server.monitoringMutex.Lock()
|
||||
|
||||
if !client.monitoring[casefoldedTarget] {
|
||||
client.monitoring[casefoldedTarget] = true
|
||||
|
||||
orig := server.monitoring[casefoldedTarget]
|
||||
server.monitoring[casefoldedTarget] = append(orig, client)
|
||||
err = server.monitorManager.addMonitor(client, casefoldedTarget, limit)
|
||||
if err == MonitorLimitExceeded {
|
||||
client.Send(nil, server.name, ERR_MONLISTFULL, client.getNick(), strconv.Itoa(server.limits.MonitorEntries), strings.Join(targets, ","))
|
||||
break
|
||||
} else if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
client.monitoringMutex.Unlock()
|
||||
client.server.monitoringMutex.Unlock()
|
||||
|
||||
// add to online / offline lists
|
||||
target := server.clients.Get(casefoldedTarget)
|
||||
if target == nil {
|
||||
if target := server.clients.Get(casefoldedTarget); target == nil {
|
||||
offline = append(offline, targets[0])
|
||||
} else {
|
||||
online = append(online, target.nickMaskString)
|
||||
online = append(online, target.getNick())
|
||||
}
|
||||
|
||||
// remove first element of targets list
|
||||
targets = targets[1:]
|
||||
}
|
||||
|
||||
if len(online) > 0 {
|
||||
client.Send(nil, server.name, RPL_MONONLINE, client.nick, strings.Join(online, ","))
|
||||
client.Send(nil, server.name, RPL_MONONLINE, client.getNick(), strings.Join(online, ","))
|
||||
}
|
||||
if len(offline) > 0 {
|
||||
client.Send(nil, server.name, RPL_MONOFFLINE, client.nick, strings.Join(offline, ","))
|
||||
client.Send(nil, server.name, RPL_MONOFFLINE, client.getNick(), strings.Join(offline, ","))
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func monitorClearHandler(server *Server, client *Client, msg ircmsg.IrcMessage) bool {
|
||||
client.clearMonitorList()
|
||||
|
||||
server.monitorManager.clearMonitorList(client)
|
||||
return false
|
||||
}
|
||||
|
||||
func monitorListHandler(server *Server, client *Client, msg ircmsg.IrcMessage) bool {
|
||||
var monitorList []string
|
||||
client.monitoringMutex.RLock()
|
||||
for name := range client.monitoring {
|
||||
monitorList = append(monitorList, name)
|
||||
}
|
||||
client.monitoringMutex.RUnlock()
|
||||
monitorList := server.monitorManager.listMonitors(client)
|
||||
|
||||
for _, line := range argsToStrings(maxLastArgLength, monitorList, ",") {
|
||||
client.Send(nil, server.name, RPL_MONLIST, client.nick, line)
|
||||
client.Send(nil, server.name, RPL_MONLIST, client.getNick(), line)
|
||||
}
|
||||
|
||||
client.Send(nil, server.name, RPL_ENDOFMONLIST, "End of MONITOR list")
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
|
|
@ -212,27 +218,25 @@ func monitorStatusHandler(server *Server, client *Client, msg ircmsg.IrcMessage)
|
|||
var online []string
|
||||
var offline []string
|
||||
|
||||
client.monitoringMutex.RLock()
|
||||
monitoring := client.monitoring
|
||||
client.monitoringMutex.RUnlock()
|
||||
monitorList := server.monitorManager.listMonitors(client)
|
||||
|
||||
for name := range monitoring {
|
||||
for _, name := range monitorList {
|
||||
target := server.clients.Get(name)
|
||||
if target == nil {
|
||||
offline = append(offline, name)
|
||||
} else {
|
||||
online = append(online, target.nickMaskString)
|
||||
online = append(online, target.getNick())
|
||||
}
|
||||
}
|
||||
|
||||
if len(online) > 0 {
|
||||
for _, line := range argsToStrings(maxLastArgLength, online, ",") {
|
||||
client.Send(nil, server.name, RPL_MONONLINE, client.nick, line)
|
||||
client.Send(nil, server.name, RPL_MONONLINE, client.getNick(), line)
|
||||
}
|
||||
}
|
||||
if len(offline) > 0 {
|
||||
for _, line := range argsToStrings(maxLastArgLength, offline, ",") {
|
||||
client.Send(nil, server.name, RPL_MONOFFLINE, client.nick, line)
|
||||
client.Send(nil, server.name, RPL_MONOFFLINE, client.getNick(), line)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue