Ви не можете вибрати більше 25 тем Теми мають розпочинатися з літери або цифри, можуть містити дефіси (-) і не повинні перевищувати 35 символів.

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115
  1. // Copyright (c) 2016-2017 Daniel Oaks <daniel@danieloaks.net>
  2. // released under the MIT license
  3. package irc
  4. import (
  5. "sync"
  6. "github.com/ergochat/irc-go/ircmsg"
  7. )
  8. // MonitorManager keeps track of who's monitoring which nicks.
  9. type MonitorManager struct {
  10. sync.RWMutex // tier 2
  11. // client -> (casefolded nick it's watching -> uncasefolded nick)
  12. watching map[*Session]map[string]string
  13. // casefolded nick -> clients watching it
  14. watchedby map[string]map[*Session]empty
  15. }
  16. func (mm *MonitorManager) Initialize() {
  17. mm.watching = make(map[*Session]map[string]string)
  18. mm.watchedby = make(map[string]map[*Session]empty)
  19. }
  20. // AlertAbout alerts everyone monitoring `client`'s nick that `client` is now {on,off}line.
  21. func (manager *MonitorManager) AlertAbout(nick, cfnick string, online bool) {
  22. var watchers []*Session
  23. // safely copy the list of clients watching our nick
  24. manager.RLock()
  25. for session := range manager.watchedby[cfnick] {
  26. watchers = append(watchers, session)
  27. }
  28. manager.RUnlock()
  29. command := RPL_MONOFFLINE
  30. if online {
  31. command = RPL_MONONLINE
  32. }
  33. for _, session := range watchers {
  34. session.Send(nil, session.client.server.name, command, session.client.Nick(), nick)
  35. }
  36. }
  37. // Add registers `client` to receive notifications about `nick`.
  38. func (manager *MonitorManager) Add(session *Session, nick string, limit int) error {
  39. cfnick, err := CasefoldName(nick)
  40. if err != nil {
  41. return err
  42. }
  43. manager.Lock()
  44. defer manager.Unlock()
  45. if manager.watching[session] == nil {
  46. manager.watching[session] = make(map[string]string)
  47. }
  48. if manager.watchedby[cfnick] == nil {
  49. manager.watchedby[cfnick] = make(map[*Session]empty)
  50. }
  51. if len(manager.watching[session]) >= limit {
  52. return errMonitorLimitExceeded
  53. }
  54. manager.watching[session][cfnick] = nick
  55. manager.watchedby[cfnick][session] = empty{}
  56. return nil
  57. }
  58. // Remove unregisters `client` from receiving notifications about `nick`.
  59. func (manager *MonitorManager) Remove(session *Session, nick string) (err error) {
  60. cfnick, err := CasefoldName(nick)
  61. if err != nil {
  62. return
  63. }
  64. manager.Lock()
  65. defer manager.Unlock()
  66. delete(manager.watching[session], cfnick)
  67. delete(manager.watchedby[cfnick], session)
  68. return nil
  69. }
  70. // RemoveAll unregisters `client` from receiving notifications about *all* nicks.
  71. func (manager *MonitorManager) RemoveAll(session *Session) {
  72. manager.Lock()
  73. defer manager.Unlock()
  74. for cfnick := range manager.watching[session] {
  75. delete(manager.watchedby[cfnick], session)
  76. }
  77. delete(manager.watching, session)
  78. }
  79. // List lists all nicks that `client` is registered to receive notifications about.
  80. func (manager *MonitorManager) List(session *Session) (nicks []string) {
  81. manager.RLock()
  82. defer manager.RUnlock()
  83. for _, nick := range manager.watching[session] {
  84. nicks = append(nicks, nick)
  85. }
  86. return nicks
  87. }
  88. var (
  89. monitorSubcommands = map[string]func(server *Server, client *Client, msg ircmsg.Message, rb *ResponseBuffer) bool{
  90. "-": monitorRemoveHandler,
  91. "+": monitorAddHandler,
  92. "c": monitorClearHandler,
  93. "l": monitorListHandler,
  94. "s": monitorStatusHandler,
  95. }
  96. )