mirror of
https://github.com/shazow/ssh-chat.git
synced 2025-06-06 10:23:03 +03:00
commands: /ignore, /unignore
#154 * Add `/ignore`/`/unignore` commands * Move set to common package, use set for ignores * `chat/set.go` is now `common/set.go` * use `*IdSet` as type for ignored list for users * remove `IsIgnoring` and `IgnoredNames` user functions, so to use directly `IdSet` methods * refactor code accordingly
This commit is contained in:
parent
2abe368022
commit
58e1cb60bd
@ -8,6 +8,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/shazow/ssh-chat/chat/message"
|
"github.com/shazow/ssh-chat/chat/message"
|
||||||
|
"github.com/shazow/ssh-chat/common"
|
||||||
)
|
)
|
||||||
|
|
||||||
// The error returned when an invalid command is issued.
|
// The error returned when an invalid command is issued.
|
||||||
@ -240,4 +241,62 @@ func InitCommands(c *Commands) {
|
|||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
|
c.Add(Command{
|
||||||
|
Prefix: "/ignore",
|
||||||
|
PrefixHelp: "[USER]",
|
||||||
|
Help: "Ignore messages from USER, list ignored users without parameters.",
|
||||||
|
Handler: func(room *Room, msg message.CommandMsg) error {
|
||||||
|
id := strings.TrimSpace(strings.TrimLeft(msg.Body(), "/ignore"))
|
||||||
|
if id == "" {
|
||||||
|
var names []string
|
||||||
|
msg.From().Ignored.Each(func(i common.Identified) {
|
||||||
|
names = append(names, i.Id())
|
||||||
|
})
|
||||||
|
|
||||||
|
var systemMsg string
|
||||||
|
if len(names) == 0 {
|
||||||
|
systemMsg = "0 users ignored."
|
||||||
|
} else {
|
||||||
|
systemMsg = fmt.Sprintf("%d ignored: %s", len(names), strings.Join(names, ", "))
|
||||||
|
}
|
||||||
|
|
||||||
|
room.Send(message.NewSystemMsg(systemMsg, msg.From()))
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
target, ok := room.MemberById(id)
|
||||||
|
if !ok {
|
||||||
|
return fmt.Errorf("user %s not found.", id)
|
||||||
|
}
|
||||||
|
|
||||||
|
err := msg.From().Ignore(target)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
room.Send(message.NewSystemMsg(fmt.Sprintf("%s is now being ignored.", target.Name()), msg.From()))
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
c.Add(Command{
|
||||||
|
Prefix: "/unignore",
|
||||||
|
PrefixHelp: "[USER]",
|
||||||
|
Help: "Stop ignoring USER.",
|
||||||
|
Handler: func(room *Room, msg message.CommandMsg) error {
|
||||||
|
id := strings.TrimSpace(strings.TrimLeft(msg.Body(), "/unignore"))
|
||||||
|
if id == "" {
|
||||||
|
return errors.New("missing user id")
|
||||||
|
}
|
||||||
|
|
||||||
|
err := msg.From().Unignore(id)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
room.Send(message.NewSystemMsg(fmt.Sprintf("%s is not ignored anymore.", id), msg.From()))
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
@ -8,6 +8,8 @@ import (
|
|||||||
"regexp"
|
"regexp"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/shazow/ssh-chat/common"
|
||||||
)
|
)
|
||||||
|
|
||||||
const messageBuffer = 5
|
const messageBuffer = 5
|
||||||
@ -24,6 +26,7 @@ type User struct {
|
|||||||
joined time.Time
|
joined time.Time
|
||||||
msg chan Message
|
msg chan Message
|
||||||
done chan struct{}
|
done chan struct{}
|
||||||
|
Ignored *common.IdSet
|
||||||
|
|
||||||
replyTo *User // Set when user gets a /msg, for replying.
|
replyTo *User // Set when user gets a /msg, for replying.
|
||||||
screen io.WriteCloser
|
screen io.WriteCloser
|
||||||
@ -37,6 +40,7 @@ func NewUser(identity Identifier) *User {
|
|||||||
joined: time.Now(),
|
joined: time.Now(),
|
||||||
msg: make(chan Message, messageBuffer),
|
msg: make(chan Message, messageBuffer),
|
||||||
done: make(chan struct{}),
|
done: make(chan struct{}),
|
||||||
|
Ignored: common.NewIdSet(),
|
||||||
}
|
}
|
||||||
u.SetColorIdx(rand.Int())
|
u.SetColorIdx(rand.Int())
|
||||||
|
|
||||||
@ -114,6 +118,17 @@ func (u *User) ConsumeOne() Message {
|
|||||||
return <-u.msg
|
return <-u.msg
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check if there are pending messages, used for testing
|
||||||
|
func (u *User) HasMessages() bool {
|
||||||
|
select {
|
||||||
|
case msg := <-u.msg:
|
||||||
|
u.msg <- msg
|
||||||
|
return true
|
||||||
|
default:
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// SetHighlight sets the highlighting regular expression to match string.
|
// SetHighlight sets the highlighting regular expression to match string.
|
||||||
func (u *User) SetHighlight(s string) error {
|
func (u *User) SetHighlight(s string) error {
|
||||||
re, err := regexp.Compile(fmt.Sprintf(reHighlight, s))
|
re, err := regexp.Compile(fmt.Sprintf(reHighlight, s))
|
||||||
@ -161,6 +176,36 @@ func (u *User) Send(m Message) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (u *User) Ignore(identified common.Identified) error {
|
||||||
|
if identified == nil {
|
||||||
|
return errors.New("user is nil.")
|
||||||
|
}
|
||||||
|
|
||||||
|
if identified.Id() == u.Id() {
|
||||||
|
return errors.New("cannot ignore self.")
|
||||||
|
}
|
||||||
|
|
||||||
|
if u.Ignored.In(identified) {
|
||||||
|
return errors.New("user already ignored.")
|
||||||
|
}
|
||||||
|
|
||||||
|
u.Ignored.Add(identified)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *User) Unignore(id string) error {
|
||||||
|
if id == "" {
|
||||||
|
return errors.New("user is nil.")
|
||||||
|
}
|
||||||
|
|
||||||
|
identified, err := u.Ignored.Get(id)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return u.Ignored.Remove(identified)
|
||||||
|
}
|
||||||
|
|
||||||
// Container for per-user configurations.
|
// Container for per-user configurations.
|
||||||
type UserConfig struct {
|
type UserConfig struct {
|
||||||
Highlight *regexp.Regexp
|
Highlight *regexp.Regexp
|
||||||
|
19
chat/room.go
19
chat/room.go
@ -7,6 +7,7 @@ import (
|
|||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"github.com/shazow/ssh-chat/chat/message"
|
"github.com/shazow/ssh-chat/chat/message"
|
||||||
|
"github.com/shazow/ssh-chat/common"
|
||||||
)
|
)
|
||||||
|
|
||||||
const historyLen = 20
|
const historyLen = 20
|
||||||
@ -34,8 +35,8 @@ type Room struct {
|
|||||||
closed bool
|
closed bool
|
||||||
closeOnce sync.Once
|
closeOnce sync.Once
|
||||||
|
|
||||||
Members *idSet
|
Members *common.IdSet
|
||||||
Ops *idSet
|
Ops *common.IdSet
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewRoom creates a new room.
|
// NewRoom creates a new room.
|
||||||
@ -47,8 +48,8 @@ func NewRoom() *Room {
|
|||||||
history: message.NewHistory(historyLen),
|
history: message.NewHistory(historyLen),
|
||||||
commands: *defaultCommands,
|
commands: *defaultCommands,
|
||||||
|
|
||||||
Members: newIdSet(),
|
Members: common.NewIdSet(),
|
||||||
Ops: newIdSet(),
|
Ops: common.NewIdSet(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -61,7 +62,7 @@ func (r *Room) SetCommands(commands Commands) {
|
|||||||
func (r *Room) Close() {
|
func (r *Room) Close() {
|
||||||
r.closeOnce.Do(func() {
|
r.closeOnce.Do(func() {
|
||||||
r.closed = true
|
r.closed = true
|
||||||
r.Members.Each(func(m identified) {
|
r.Members.Each(func(m common.Identified) {
|
||||||
m.(*Member).Close()
|
m.(*Member).Close()
|
||||||
})
|
})
|
||||||
r.Members.Clear()
|
r.Members.Clear()
|
||||||
@ -95,8 +96,14 @@ func (r *Room) HandleMsg(m message.Message) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
r.history.Add(m)
|
r.history.Add(m)
|
||||||
r.Members.Each(func(u identified) {
|
r.Members.Each(func(u common.Identified) {
|
||||||
user := u.(*Member).User
|
user := u.(*Member).User
|
||||||
|
|
||||||
|
if fromMsg != nil && user.Ignored.In(fromMsg.From()) {
|
||||||
|
// Skip because ignored
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
if skip && skipUser == user {
|
if skip && skipUser == user {
|
||||||
// Skip
|
// Skip
|
||||||
return
|
return
|
||||||
|
@ -1,8 +1,11 @@
|
|||||||
package chat
|
package chat
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
"reflect"
|
"reflect"
|
||||||
"testing"
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/shazow/ssh-chat/chat/message"
|
"github.com/shazow/ssh-chat/chat/message"
|
||||||
)
|
)
|
||||||
@ -40,6 +43,134 @@ func TestRoomServe(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type ScreenedUser struct {
|
||||||
|
user *message.User
|
||||||
|
screen *MockScreen
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestIgnore(t *testing.T) {
|
||||||
|
var buffer []byte
|
||||||
|
|
||||||
|
ch := NewRoom()
|
||||||
|
go ch.Serve()
|
||||||
|
defer ch.Close()
|
||||||
|
|
||||||
|
// Create 3 users, join the room and clear their screen buffers
|
||||||
|
users := make([]ScreenedUser, 3)
|
||||||
|
for i := 0; i < 3; i++ {
|
||||||
|
screen := &MockScreen{}
|
||||||
|
user := message.NewUserScreen(message.SimpleId(fmt.Sprintf("user%d", i)), screen)
|
||||||
|
users[i] = ScreenedUser{
|
||||||
|
user: user,
|
||||||
|
screen: screen,
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err := ch.Join(user)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, u := range users {
|
||||||
|
for i := 0; i < 3; i++ {
|
||||||
|
u.user.HandleMsg(u.user.ConsumeOne())
|
||||||
|
u.screen.Read(&buffer)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Use some handy variable names for distinguish between roles
|
||||||
|
ignorer := users[0]
|
||||||
|
ignored := users[1]
|
||||||
|
other := users[2]
|
||||||
|
|
||||||
|
// test ignoring unexisting user
|
||||||
|
if err := sendCommand("/ignore test", ignorer, ch, &buffer); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
expectOutput(t, buffer, "-> Err: user test not found."+message.Newline)
|
||||||
|
|
||||||
|
// test ignoring existing user
|
||||||
|
if err := sendCommand("/ignore "+ignored.user.Name(), ignorer, ch, &buffer); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
expectOutput(t, buffer, "-> "+ignored.user.Name()+" is now being ignored."+message.Newline)
|
||||||
|
|
||||||
|
// ignoring the same user twice returns an error message and doesn't add the user twice
|
||||||
|
if err := sendCommand("/ignore "+ignored.user.Name(), ignorer, ch, &buffer); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
expectOutput(t, buffer, "-> Err: user already ignored."+message.Newline)
|
||||||
|
if ignoredList := ignorer.user.Ignored.ListPrefix(""); len(ignoredList) != 1 {
|
||||||
|
t.Fatalf("should have %d ignored users, has %d", 1, len(ignoredList))
|
||||||
|
}
|
||||||
|
|
||||||
|
// when a message is sent from the ignored user, it is delivered to non-ignoring users
|
||||||
|
ch.Send(message.NewPublicMsg("hello", ignored.user))
|
||||||
|
other.user.HandleMsg(other.user.ConsumeOne())
|
||||||
|
other.screen.Read(&buffer)
|
||||||
|
expectOutput(t, buffer, ignored.user.Name()+": hello"+message.Newline)
|
||||||
|
|
||||||
|
// ensure ignorer doesn't have received any message
|
||||||
|
if ignorer.user.HasMessages() {
|
||||||
|
t.Fatal("should not have messages")
|
||||||
|
}
|
||||||
|
|
||||||
|
// `/ignore` returns a list of ignored users
|
||||||
|
if err := sendCommand("/ignore", ignorer, ch, &buffer); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
expectOutput(t, buffer, "-> 1 ignored: "+ignored.user.Name()+message.Newline)
|
||||||
|
|
||||||
|
// `/unignore [USER]` removes the user from ignored ones
|
||||||
|
if err := sendCommand("/unignore "+ignored.user.Name(), users[0], ch, &buffer); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
expectOutput(t, buffer, "-> "+ignored.user.Name()+" is not ignored anymore."+message.Newline)
|
||||||
|
|
||||||
|
if err := sendCommand("/ignore", users[0], ch, &buffer); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
expectOutput(t, buffer, "-> 0 users ignored."+message.Newline)
|
||||||
|
|
||||||
|
if ignoredList := ignorer.user.Ignored.ListPrefix(""); len(ignoredList) != 0 {
|
||||||
|
t.Fatalf("should have %d ignored users, has %d", 0, len(ignoredList))
|
||||||
|
}
|
||||||
|
|
||||||
|
// after unignoring a user, its messages can be received again
|
||||||
|
ch.Send(message.NewPublicMsg("hello again!", ignored.user))
|
||||||
|
|
||||||
|
// give some time for the channel to get the message
|
||||||
|
time.Sleep(100)
|
||||||
|
|
||||||
|
// ensure ignorer has received the message
|
||||||
|
if !ignorer.user.HasMessages() {
|
||||||
|
t.Fatal("should have messages")
|
||||||
|
}
|
||||||
|
ignorer.user.HandleMsg(ignorer.user.ConsumeOne())
|
||||||
|
ignorer.screen.Read(&buffer)
|
||||||
|
expectOutput(t, buffer, ignored.user.Name()+": hello again!"+message.Newline)
|
||||||
|
}
|
||||||
|
|
||||||
|
func expectOutput(t *testing.T, buffer []byte, expected string) {
|
||||||
|
bytes := []byte(expected)
|
||||||
|
if !reflect.DeepEqual(buffer, bytes) {
|
||||||
|
t.Errorf("Got: %q; Expected: %q", buffer, expected)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func sendCommand(cmd string, mock ScreenedUser, room *Room, buffer *[]byte) error {
|
||||||
|
msg, ok := message.NewPublicMsg(cmd, mock.user).ParseCommand()
|
||||||
|
if !ok {
|
||||||
|
return errors.New("cannot parse command message")
|
||||||
|
}
|
||||||
|
|
||||||
|
room.Send(msg)
|
||||||
|
mock.user.HandleMsg(mock.user.ConsumeOne())
|
||||||
|
mock.screen.Read(buffer)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func TestRoomJoin(t *testing.T) {
|
func TestRoomJoin(t *testing.T) {
|
||||||
var expected, actual []byte
|
var expected, actual []byte
|
||||||
|
|
||||||
|
@ -4,11 +4,12 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/shazow/ssh-chat/chat/message"
|
"github.com/shazow/ssh-chat/chat/message"
|
||||||
|
"github.com/shazow/ssh-chat/common"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestSet(t *testing.T) {
|
func TestSet(t *testing.T) {
|
||||||
var err error
|
var err error
|
||||||
s := newIdSet()
|
s := common.NewIdSet()
|
||||||
u := message.NewUser(message.SimpleId("foo"))
|
u := message.NewUser(message.SimpleId("foo"))
|
||||||
|
|
||||||
if s.In(u) {
|
if s.In(u) {
|
||||||
@ -31,7 +32,7 @@ func TestSet(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
err = s.Add(u2)
|
err = s.Add(u2)
|
||||||
if err != ErrIdTaken {
|
if err != common.ErrIdTaken {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
package chat
|
package common
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
@ -10,45 +10,45 @@ import (
|
|||||||
var ErrIdTaken = errors.New("id already taken")
|
var ErrIdTaken = errors.New("id already taken")
|
||||||
|
|
||||||
// The error returned when a requested item does not exist in the set.
|
// The error returned when a requested item does not exist in the set.
|
||||||
var ErridentifiedMissing = errors.New("item does not exist")
|
var ErrIdentifiedMissing = errors.New("item does not exist")
|
||||||
|
|
||||||
// Interface for an item storeable in the set
|
// Interface for an item storeable in the set
|
||||||
type identified interface {
|
type Identified interface {
|
||||||
Id() string
|
Id() string
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set with string lookup.
|
// Set with string lookup.
|
||||||
// TODO: Add trie for efficient prefix lookup?
|
// TODO: Add trie for efficient prefix lookup?
|
||||||
type idSet struct {
|
type IdSet struct {
|
||||||
sync.RWMutex
|
sync.RWMutex
|
||||||
lookup map[string]identified
|
lookup map[string]Identified
|
||||||
}
|
}
|
||||||
|
|
||||||
// newIdSet creates a new set.
|
// newIdSet creates a new set.
|
||||||
func newIdSet() *idSet {
|
func NewIdSet() *IdSet {
|
||||||
return &idSet{
|
return &IdSet{
|
||||||
lookup: map[string]identified{},
|
lookup: map[string]Identified{},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clear removes all items and returns the number removed.
|
// Clear removes all items and returns the number removed.
|
||||||
func (s *idSet) Clear() int {
|
func (s *IdSet) Clear() int {
|
||||||
s.Lock()
|
s.Lock()
|
||||||
n := len(s.lookup)
|
n := len(s.lookup)
|
||||||
s.lookup = map[string]identified{}
|
s.lookup = map[string]Identified{}
|
||||||
s.Unlock()
|
s.Unlock()
|
||||||
return n
|
return n
|
||||||
}
|
}
|
||||||
|
|
||||||
// Len returns the size of the set right now.
|
// Len returns the size of the set right now.
|
||||||
func (s *idSet) Len() int {
|
func (s *IdSet) Len() int {
|
||||||
s.RLock()
|
s.RLock()
|
||||||
defer s.RUnlock()
|
defer s.RUnlock()
|
||||||
return len(s.lookup)
|
return len(s.lookup)
|
||||||
}
|
}
|
||||||
|
|
||||||
// In checks if an item exists in this set.
|
// In checks if an item exists in this set.
|
||||||
func (s *idSet) In(item identified) bool {
|
func (s *IdSet) In(item Identified) bool {
|
||||||
s.RLock()
|
s.RLock()
|
||||||
_, ok := s.lookup[item.Id()]
|
_, ok := s.lookup[item.Id()]
|
||||||
s.RUnlock()
|
s.RUnlock()
|
||||||
@ -56,20 +56,20 @@ func (s *idSet) In(item identified) bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Get returns an item with the given Id.
|
// Get returns an item with the given Id.
|
||||||
func (s *idSet) Get(id string) (identified, error) {
|
func (s *IdSet) Get(id string) (Identified, error) {
|
||||||
s.RLock()
|
s.RLock()
|
||||||
item, ok := s.lookup[id]
|
item, ok := s.lookup[id]
|
||||||
s.RUnlock()
|
s.RUnlock()
|
||||||
|
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, ErridentifiedMissing
|
return nil, ErrIdentifiedMissing
|
||||||
}
|
}
|
||||||
|
|
||||||
return item, nil
|
return item, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add item to this set if it does not exist already.
|
// Add item to this set if it does not exist already.
|
||||||
func (s *idSet) Add(item identified) error {
|
func (s *IdSet) Add(item Identified) error {
|
||||||
s.Lock()
|
s.Lock()
|
||||||
defer s.Unlock()
|
defer s.Unlock()
|
||||||
|
|
||||||
@ -83,21 +83,21 @@ func (s *idSet) Add(item identified) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Remove item from this set.
|
// Remove item from this set.
|
||||||
func (s *idSet) Remove(item identified) error {
|
func (s *IdSet) Remove(item Identified) error {
|
||||||
s.Lock()
|
s.Lock()
|
||||||
defer s.Unlock()
|
defer s.Unlock()
|
||||||
id := item.Id()
|
id := item.Id()
|
||||||
_, found := s.lookup[id]
|
_, found := s.lookup[id]
|
||||||
if !found {
|
if !found {
|
||||||
return ErridentifiedMissing
|
return ErrIdentifiedMissing
|
||||||
}
|
}
|
||||||
delete(s.lookup, id)
|
delete(s.lookup, id)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Replace item from old id with new identified.
|
// Replace item from old id with new Identified.
|
||||||
// Used for moving the same identified to a new Id, such as a rename.
|
// Used for moving the same Identified to a new Id, such as a rename.
|
||||||
func (s *idSet) Replace(oldId string, item identified) error {
|
func (s *IdSet) Replace(oldId string, item Identified) error {
|
||||||
s.Lock()
|
s.Lock()
|
||||||
defer s.Unlock()
|
defer s.Unlock()
|
||||||
|
|
||||||
@ -110,11 +110,11 @@ func (s *idSet) Replace(oldId string, item identified) error {
|
|||||||
// Remove oldId
|
// Remove oldId
|
||||||
_, found = s.lookup[oldId]
|
_, found = s.lookup[oldId]
|
||||||
if !found {
|
if !found {
|
||||||
return ErridentifiedMissing
|
return ErrIdentifiedMissing
|
||||||
}
|
}
|
||||||
delete(s.lookup, oldId)
|
delete(s.lookup, oldId)
|
||||||
|
|
||||||
// Add new identified
|
// Add new Identified
|
||||||
s.lookup[item.Id()] = item
|
s.lookup[item.Id()] = item
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
@ -122,7 +122,7 @@ func (s *idSet) Replace(oldId string, item identified) error {
|
|||||||
|
|
||||||
// Each loops over every item while holding a read lock and applies fn to each
|
// Each loops over every item while holding a read lock and applies fn to each
|
||||||
// element.
|
// element.
|
||||||
func (s *idSet) Each(fn func(item identified)) {
|
func (s *IdSet) Each(fn func(item Identified)) {
|
||||||
s.RLock()
|
s.RLock()
|
||||||
for _, item := range s.lookup {
|
for _, item := range s.lookup {
|
||||||
fn(item)
|
fn(item)
|
||||||
@ -131,8 +131,8 @@ func (s *idSet) Each(fn func(item identified)) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ListPrefix returns a list of items with a prefix, case insensitive.
|
// ListPrefix returns a list of items with a prefix, case insensitive.
|
||||||
func (s *idSet) ListPrefix(prefix string) []identified {
|
func (s *IdSet) ListPrefix(prefix string) []Identified {
|
||||||
r := []identified{}
|
r := []Identified{}
|
||||||
prefix = strings.ToLower(prefix)
|
prefix = strings.ToLower(prefix)
|
||||||
|
|
||||||
s.RLock()
|
s.RLock()
|
Loading…
x
Reference in New Issue
Block a user