You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

whowas.go 1.9KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100
  1. // Copyright (c) 2012-2014 Jeremy Latt
  2. // Copyright (c) 2016 Daniel Oaks <daniel@danieloaks.net>
  3. // released under the MIT license
  4. package irc
  5. import (
  6. "sync"
  7. )
  8. type WhoWasList struct {
  9. buffer []*WhoWas
  10. start int
  11. end int
  12. accessMutex sync.RWMutex
  13. }
  14. type WhoWas struct {
  15. nicknameCasefolded string
  16. nickname string
  17. username string
  18. hostname string
  19. realname string
  20. }
  21. func NewWhoWasList(size uint) *WhoWasList {
  22. return &WhoWasList{
  23. buffer: make([]*WhoWas, size+1),
  24. }
  25. }
  26. func (list *WhoWasList) Append(client *Client) {
  27. list.accessMutex.Lock()
  28. defer list.accessMutex.Unlock()
  29. list.buffer[list.end] = &WhoWas{
  30. nicknameCasefolded: client.nickCasefolded,
  31. nickname: client.nick,
  32. username: client.username,
  33. hostname: client.hostname,
  34. realname: client.realname,
  35. }
  36. list.end = (list.end + 1) % len(list.buffer)
  37. if list.end == list.start {
  38. list.start = (list.end + 1) % len(list.buffer)
  39. }
  40. }
  41. func (list *WhoWasList) Find(nickname string, limit int64) []*WhoWas {
  42. list.accessMutex.RLock()
  43. defer list.accessMutex.RUnlock()
  44. results := make([]*WhoWas, 0)
  45. casefoldedNickname, err := CasefoldName(nickname)
  46. if err != nil {
  47. return results
  48. }
  49. for whoWas := range list.Each() {
  50. if casefoldedNickname != whoWas.nicknameCasefolded {
  51. continue
  52. }
  53. results = append(results, whoWas)
  54. if int64(len(results)) >= limit {
  55. break
  56. }
  57. }
  58. return results
  59. }
  60. func (list *WhoWasList) prev(index int) int {
  61. list.accessMutex.RLock()
  62. defer list.accessMutex.RUnlock()
  63. index--
  64. if index < 0 {
  65. index += len(list.buffer)
  66. }
  67. return index
  68. }
  69. // Iterate the buffer in reverse.
  70. func (list *WhoWasList) Each() <-chan *WhoWas {
  71. ch := make(chan *WhoWas)
  72. go func() {
  73. defer close(ch)
  74. if list.start == list.end {
  75. return
  76. }
  77. start := list.prev(list.end)
  78. end := list.prev(list.start)
  79. for start != end {
  80. ch <- list.buffer[start]
  81. start = list.prev(start)
  82. }
  83. }()
  84. return ch
  85. }