Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 35 additions & 4 deletions internal/users/charindex.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package users

import (
"bytes"
"strings"
"sync"
)
Expand Down Expand Up @@ -69,16 +70,23 @@ func (ci *CharacterIndex) Find(name string) (userId int, found bool) {
return
}

// Rebuild clears the index and repopulates it from every user record on disk
// Rebuild clears the index and repopulates it from every user file on disk
// plus all currently online users. Only active character names are added here;
// the alt-characters module is responsible for adding alt names after this
// runs.
func (ci *CharacterIndex) Rebuild() {
ci.RebuildFromScan(ScanUserFiles())
}

// RebuildFromIndex repopulates the character index straight from the user
// index records plus all currently online users, without opening a single
// user file.
func (ci *CharacterIndex) RebuildFromIndex(idx *UserIndex) {
newMap := make(map[string]int)

SearchOfflineUsers(func(u *UserRecord) bool {
if u.Character != nil && u.Character.Name != "" {
newMap[strings.ToLower(u.Character.Name)] = u.UserId
idx.ForEachRecord(func(rec IndexUserRecord) bool {
if name := string(bytes.TrimRight(rec.CharacterName[:], "\x00")); name != `` {
newMap[strings.ToLower(name)] = int(rec.UserID)
}
return true
})
Expand All @@ -93,3 +101,26 @@ func (ci *CharacterIndex) Rebuild() {
ci.byName = newMap
ci.mu.Unlock()
}

// RebuildFromScan is Rebuild fed by an existing user file scan, so startup
// can share one scan between the user index and the character index instead
// of fully parsing every user record a second time.
func (ci *CharacterIndex) RebuildFromScan(scan []UserFileScan) {
newMap := make(map[string]int, len(scan))

for _, s := range scan {
if s.CharacterName != "" {
newMap[strings.ToLower(s.CharacterName)] = s.UserId
}
}

for _, u := range GetAllActiveUsers() {
if u.Character != nil && u.Character.Name != "" {
newMap[strings.ToLower(u.Character.Name)] = u.UserId
}
}

ci.mu.Lock()
ci.byName = newMap
ci.mu.Unlock()
}
10 changes: 8 additions & 2 deletions internal/users/charindex_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import (
"fmt"
"sync"
"testing"

"github.com/GoMudEngine/GoMud/internal/mudlog"
)

func freshCharacterIndex() *CharacterIndex {
Expand Down Expand Up @@ -116,8 +118,12 @@ func TestCharacterIndex_MultipleUsersMultipleNames(t *testing.T) {
}

func TestCharacterIndex_Rebuild(t *testing.T) {
// The scan warns about the missing users directory in a test env, so the
// logger must be initialized.
mudlog.SetupLogger(nil, "", "", false)

// Swap in a fresh singleton so Rebuild exercises the real code path
// without touching disk (SearchOfflineUsers finds nothing in a test env).
// without touching disk (ScanUserFiles finds nothing in a test env).
orig := characterIndex
defer func() { characterIndex = orig }()

Expand All @@ -127,7 +133,7 @@ func TestCharacterIndex_Rebuild(t *testing.T) {
// Pre-populate with stale data that Rebuild should clear.
ci.Add("stale", 99)

// Rebuild will call SearchOfflineUsers (returns nothing in test env) and
// Rebuild will call ScanUserFiles (returns nothing in test env) and
// GetAllActiveUsers (returns nothing since userManager is empty). The stale
// entry must be gone.
ci.Rebuild()
Expand Down
Loading