From 1c44c714e68e097325bad2879642b9a5615d1287 Mon Sep 17 00:00:00 2001 From: Andrey Petrov Date: Sat, 16 Mar 2019 15:27:43 -0400 Subject: [PATCH] chat: Sort NamesPrefix by recently active --- chat/message/user.go | 13 +++++++++++++ chat/room.go | 18 ++++++++++++++---- chat/room_test.go | 42 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 69 insertions(+), 4 deletions(-) diff --git a/chat/message/user.go b/chat/message/user.go index d094bde..43da001 100644 --- a/chat/message/user.go +++ b/chat/message/user.go @@ -238,3 +238,16 @@ func init() { // TODO: Seed random? } + +// RecentActiveUsers is a slice of *Users that knows how to be sorted by the time of the last message. +type RecentActiveUsers []*User + +func (a RecentActiveUsers) Len() int { return len(a) } +func (a RecentActiveUsers) Swap(i, j int) { a[i], a[j] = a[j], a[i] } +func (a RecentActiveUsers) Less(i, j int) bool { + a[i].mu.Lock() + defer a[i].mu.Unlock() + a[j].mu.Lock() + defer a[j].mu.Unlock() + return a[i].lastMsg.After(a[j].lastMsg) +} diff --git a/chat/room.go b/chat/room.go index 71e3171..851d0e3 100644 --- a/chat/room.go +++ b/chat/room.go @@ -4,6 +4,7 @@ import ( "errors" "fmt" "io" + "sort" "sync" "github.com/shazow/ssh-chat/chat/message" @@ -227,12 +228,21 @@ func (r *Room) SetTopic(s string) { } // NamesPrefix lists all members' names with a given prefix, used to query -// for autocompletion purposes. +// for autocompletion purposes. Sorted by which user was last active. func (r *Room) NamesPrefix(prefix string) []string { items := r.Members.ListPrefix(prefix) - names := make([]string, len(items)) - for i, item := range items { - names[i] = item.Value().(*Member).User.Name() + + // Sort results by recently active + users := make([]*message.User, 0, len(items)) + for _, item := range items { + users = append(users, item.Value().(*Member).User) + } + sort.Sort(message.RecentActiveUsers(users)) + + // Pull out names + names := make([]string, 0, len(items)) + for _, user := range users { + names = append(names, user.Name()) } return names } diff --git a/chat/room_test.go b/chat/room_test.go index e30c170..77c77f7 100644 --- a/chat/room_test.go +++ b/chat/room_test.go @@ -8,6 +8,7 @@ import ( "time" "github.com/shazow/ssh-chat/chat/message" + "github.com/shazow/ssh-chat/set" ) // Used for testing @@ -362,3 +363,44 @@ func TestRoomNames(t *testing.T) { t.Errorf("Got: %q; Expected: %q", actual, expected) } } + +func TestRoomNamesPrefix(t *testing.T) { + r := NewRoom() + + s := &MockScreen{} + members := []*Member{ + &Member{User: message.NewUserScreen(message.SimpleID("aaa"), s)}, + &Member{User: message.NewUserScreen(message.SimpleID("aab"), s)}, + &Member{User: message.NewUserScreen(message.SimpleID("aac"), s)}, + &Member{User: message.NewUserScreen(message.SimpleID("foo"), s)}, + } + + for _, m := range members { + if err := r.Members.Add(set.Itemize(m.ID(), m)); err != nil { + t.Fatal(err) + } + } + + // Inject some activity + members[2].HandleMsg(message.NewMsg("hi")) // aac + members[0].HandleMsg(message.NewMsg("hi")) // aaa + members[3].HandleMsg(message.NewMsg("hi")) // foo + members[1].HandleMsg(message.NewMsg("hi")) // aab + + if got, want := r.NamesPrefix("a"), []string{"aab", "aaa", "aac"}; !reflect.DeepEqual(got, want) { + t.Errorf("got: %q; want: %q", got, want) + } + + members[2].HandleMsg(message.NewMsg("hi")) // aac + if got, want := r.NamesPrefix("a"), []string{"aac", "aab", "aaa"}; !reflect.DeepEqual(got, want) { + t.Errorf("got: %q; want: %q", got, want) + } + + if got, want := r.NamesPrefix("f"), []string{"foo"}; !reflect.DeepEqual(got, want) { + t.Errorf("got: %q; want: %q", got, want) + } + + if got, want := r.NamesPrefix("bar"), []string{}; !reflect.DeepEqual(got, want) { + t.Errorf("got: %q; want: %q", got, want) + } +}