Documentation
¶
Index ¶
- Constants
- Variables
- func AddFunctionExporter(f FunctionExporter)
- func CharacterNameSearch(nameToFind string) (foundUserId int, foundUserName string)
- func CopyoverContributor() copyover.Contributor
- func CreateUser(u *UserRecord) error
- func DeleteUser(userId int) error
- func DoFilenameMigrationV1() error
- func DoUserMigrations()
- func Exists(name string) bool
- func FindUserId(username string) int
- func GetConnectionId(userId int) connections.ConnectionId
- func GetConnectionIds(userIds []int) []connections.ConnectionId
- func GetExpiredLinkDeadUsers(expirationTurn uint64) []int
- func GetExportedFunction(fName string) (any, bool)
- func GetMemoryUsage() map[string]util.MemoryResult
- func GetOnlineUserIds() []int
- func GetUniqueUserId() int
- func IsLinkDeadConnection(connectionId connections.ConnectionId) bool
- func LogOutUserByConnectionId(connectionId connections.ConnectionId) error
- func RemoveLinkDeadConnection(connectionId connections.ConnectionId)
- func RemoveLinkDeadUser(userId int)
- func RemoveTestUser(userId int)
- func ResetActiveUsers()
- func SaveAllUsers(isAutoSave ...bool)
- func SaveUser(u UserRecord, isAutoSave ...bool) error
- func SearchOfflineUsers(searchFunc func(u *UserRecord) bool)
- func SetLinkDeadUser(userId int)
- func SetTestConnection(connectionId connections.ConnectionId, userId int)
- func SetTestUser(u *UserRecord)
- func UpdateOnlineUser(updated UserRecord)
- func ValidateName(name string) error
- func ValidatePassword(pw string) error
- type ActiveUsers
- type CharacterIndex
- func (ci *CharacterIndex) Add(name string, userId int)
- func (ci *CharacterIndex) Find(name string) (userId int, found bool)
- func (ci *CharacterIndex) ForEach(fn func(name string, userId int) bool)
- func (ci *CharacterIndex) Len() int
- func (ci *CharacterIndex) Rebuild()
- func (ci *CharacterIndex) Remove(name string)
- type CharacterSearchResult
- type FunctionExporter
- type IndexMetaData
- type IndexUserRecord
- type OnlineInfo
- type Storage
- type UserIndex
- func (idx *UserIndex) AddUser(userId int, username string) error
- func (idx *UserIndex) Create() error
- func (idx *UserIndex) Delete()
- func (idx *UserIndex) Exists() bool
- func (idx *UserIndex) FindByUserId(userId int) (string, bool)
- func (idx *UserIndex) FindByUsername(username string) (int, bool)
- func (idx *UserIndex) ForEachRecord(fn func(rec IndexUserRecord) bool)
- func (idx *UserIndex) GetHighestUserId() int
- func (idx *UserIndex) GetMetaData() IndexMetaData
- func (idx *UserIndex) IsUpToDate() bool
- func (idx *UserIndex) Rebuild() error
- func (idx *UserIndex) RemoveByUsername(username string) error
- type UserLog
- type UserLogEntry
- type UserRecord
- func CopyoverReconnectUser(user *UserRecord, connectionId connections.ConnectionId) (*UserRecord, string, error)
- func GetAllActiveUsers() []*UserRecord
- func GetByCharacterName(name string) *UserRecord
- func GetByConnectionId(connectionId connections.ConnectionId) *UserRecord
- func GetByUserId(userId int) *UserRecord
- func LoadUser(username string, skipValidation ...bool) (*UserRecord, error)
- func LoadUserById(userId int) (*UserRecord, error)
- func LoginUser(user *UserRecord, connectionId connections.ConnectionId) (*UserRecord, string, error)
- func NewUserRecord(userId int, connectionId uint64) *UserRecord
- func (u *UserRecord) AddBuff(buffId int, source string)
- func (u *UserRecord) AddCommandAlias(input string, output string) (addedAlias string, deletedAlias string)
- func (u *UserRecord) BlockInput()
- func (u *UserRecord) ClearPrompt()
- func (u *UserRecord) ClientSettings() connections.ClientSettings
- func (u *UserRecord) Command(inputTxt string, waitSeconds ...float64)
- func (u *UserRecord) CommandFlagged(inputTxt string, flagData events.EventFlag, waitSeconds ...float64)
- func (u *UserRecord) ConnectionId() uint64
- func (u *UserRecord) DidTip(tipName string, completed ...bool) bool
- func (u *UserRecord) GetCommandPrompt() string
- func (u *UserRecord) GetConfigOption(key string) any
- func (u *UserRecord) GetConnectTime() time.Time
- func (u *UserRecord) GetLastInputRound() uint64
- func (u *UserRecord) GetOnlineInfo() OnlineInfo
- func (u *UserRecord) GetPrompt() *prompt.Prompt
- func (u *UserRecord) GetTempData(key string) any
- func (u *UserRecord) GetUnsentText() (unsent string, suggestion string)
- func (u *UserRecord) GrantXP(amt int, source string)
- func (u *UserRecord) HasPermission(permissionId string) bool
- func (u *UserRecord) HasPlaintextPassword() bool
- func (u *UserRecord) HasRolePermission(permissionId string, simpleMatch ...bool) bool
- func (u *UserRecord) HasShop() bool
- func (u *UserRecord) InputBlocked() bool
- func (u *UserRecord) PasswordMatches(input string) bool
- func (u *UserRecord) PlayMusic(musicFileOrId string)
- func (u *UserRecord) PlaySound(soundId string, category string)
- func (u *UserRecord) ProcessPromptString(promptStr string) string
- func (u *UserRecord) ReplaceCharacter(replacement *characters.Character)
- func (u *UserRecord) RoundTick()
- func (u *UserRecord) SendText(txt string)
- func (u *UserRecord) SendWebClientCommand(txt string)
- func (u *UserRecord) SetCharacterName(cn string) error
- func (u *UserRecord) SetConfigOption(key string, value any)
- func (u *UserRecord) SetLastInputRound(rdNum uint64)
- func (u *UserRecord) SetPassword(pw string) error
- func (u *UserRecord) SetTempData(key string, value any)
- func (u *UserRecord) SetUnsentText(t string, suggest string)
- func (u *UserRecord) SetUsername(un string) error
- func (u *UserRecord) ShorthandId() string
- func (u *UserRecord) StartPrompt(command string, rest string) (*prompt.Prompt, bool)
- func (u *UserRecord) TempName() string
- func (u *UserRecord) TryCommandAlias(input string) string
- func (u *UserRecord) UnblockInput()
- func (u *UserRecord) WimpyCheck()
- type UserSearchResult
Constants ¶
const ( IndexVersion = 2 IndexLineTerminatorV1 = byte(10) // "\n" IndexRecordSizeV1 = 89 FixedHeaderTotalLength = 100 // 99 bytes header content + 1 byte newline )
const ( LogMinAllocation = 50 LogMaxAllocation = 1000 )
Variables ¶
var ( ErrIndexMissing = errors.New(`index does not exist`) ErrUserFilesOldFormat = errors.New(`user files are in old format of username.yaml`) ErrIndexVersionInvalid = errors.New(`version out of date.`) ErrSearchNameTooLong = errors.New(`search name provided is too long`) ErrNotFound = errors.New("user not found") )
var ( // immutable roles RoleGuest string = "guest" RoleUser string = "user" RoleMod string = "mod" RoleAdmin string = "admin" )
var (
ErrBothFilesExist = errors.New("could not migrate due to both file formats existing")
)
Functions ¶
func AddFunctionExporter ¶ added in v0.9.8
func AddFunctionExporter(f FunctionExporter)
AddFunctionExporter registers a function exporter (called from main.go with plugins.GetPluginRegistry()).
func CharacterNameSearch ¶
CharacterNameSearch returns the userId and username for the given character name. It consults the in-memory CharacterIndex, which is populated at startup with every active character name and, when the alt-characters module is loaded, with all stored alt names as well.
func CopyoverContributor ¶ added in v0.9.8
func CopyoverContributor() copyover.Contributor
CopyoverContributor returns the users contributor for registration.
func DeleteUser ¶ added in v0.9.8
DeleteUser permanently removes a user record, their YAML file, and all index entries. It refuses to delete a user that is currently online.
func DoFilenameMigrationV1 ¶
func DoFilenameMigrationV1() error
func DoUserMigrations ¶
func DoUserMigrations()
func FindUserId ¶
func GetConnectionId ¶
func GetConnectionId(userId int) connections.ConnectionId
func GetConnectionIds ¶
func GetConnectionIds(userIds []int) []connections.ConnectionId
func GetExpiredLinkDeadUsers ¶ added in v0.9.8
Returns a slice of userId's These userId's are link-dead players that have reached expiration
func GetExportedFunction ¶ added in v0.9.8
GetExportedFunction looks up a named function across all registered exporters.
func GetMemoryUsage ¶
func GetMemoryUsage() map[string]util.MemoryResult
func GetOnlineUserIds ¶
func GetOnlineUserIds() []int
func GetUniqueUserId ¶
func GetUniqueUserId() int
func IsLinkDeadConnection ¶ added in v0.9.8
func IsLinkDeadConnection(connectionId connections.ConnectionId) bool
func LogOutUserByConnectionId ¶
func LogOutUserByConnectionId(connectionId connections.ConnectionId) error
func RemoveLinkDeadConnection ¶ added in v0.9.8
func RemoveLinkDeadConnection(connectionId connections.ConnectionId)
func RemoveLinkDeadUser ¶ added in v0.9.8
func RemoveLinkDeadUser(userId int)
func RemoveTestUser ¶ added in v0.9.8
func RemoveTestUser(userId int)
RemoveTestUser removes a user from the active users map. For testing only.
func ResetActiveUsers ¶ added in v0.9.8
func ResetActiveUsers()
ResetActiveUsers resets the user manager to a clean state. For testing only.
func SaveAllUsers ¶
func SaveAllUsers(isAutoSave ...bool)
func SaveUser ¶
func SaveUser(u UserRecord, isAutoSave ...bool) error
func SearchOfflineUsers ¶
func SearchOfflineUsers(searchFunc func(u *UserRecord) bool)
Loads all user recvords and runs against a function. Stops searching if false is returned.
func SetLinkDeadUser ¶ added in v0.9.8
func SetLinkDeadUser(userId int)
func SetTestConnection ¶ added in v0.9.8
func SetTestConnection(connectionId connections.ConnectionId, userId int)
SetTestConnection registers a connection-to-user mapping. Must be called alongside SetTestUser so that GetByConnectionId resolves correctly. For testing only.
func SetTestUser ¶ added in v0.9.8
func SetTestUser(u *UserRecord)
SetTestUser adds a user directly to the active users map. For testing only.
func UpdateOnlineUser ¶ added in v0.9.8
func UpdateOnlineUser(updated UserRecord)
UpdateOnlineUser applies updated exported fields to the in-memory user record if the user is currently online. Connection state and other runtime-only fields are preserved from the live record.
func ValidateName ¶
func ValidatePassword ¶
Types ¶
type ActiveUsers ¶
type ActiveUsers struct {
Users map[int]*UserRecord // userId to UserRecord
Usernames map[string]int // username to userId
Connections map[connections.ConnectionId]int // connectionId to userId
UserConnections map[int]connections.ConnectionId // userId to connectionId
LinkDeadConnections map[connections.ConnectionId]uint64 // connectionId to turn they became link-dead
}
type CharacterIndex ¶ added in v0.9.8
type CharacterIndex struct {
// contains filtered or unexported fields
}
CharacterIndex is an in-memory index mapping lowercase character names to user IDs. One user ID may own multiple character names (active character plus any stored alts). The index is rebuilt at startup from user records; the alt-characters module is responsible for populating alt names.
func GetCharacterIndex ¶ added in v0.9.8
func GetCharacterIndex() *CharacterIndex
GetCharacterIndex returns the singleton CharacterIndex.
func (*CharacterIndex) Add ¶ added in v0.9.8
func (ci *CharacterIndex) Add(name string, userId int)
Add registers a character name as belonging to userId. The name is normalized to lowercase before storage. If the name is already present it is overwritten with the new userId.
func (*CharacterIndex) Find ¶ added in v0.9.8
func (ci *CharacterIndex) Find(name string) (userId int, found bool)
Find looks up a character name and returns the owning userId. The lookup is case-insensitive. Returns (0, false) when the name is not found.
func (*CharacterIndex) ForEach ¶ added in v0.9.8
func (ci *CharacterIndex) ForEach(fn func(name string, userId int) bool)
ForEach calls fn for every entry in the index in unspecified order. Returning false from fn stops iteration. The index is read-locked for the duration of the call; fn must not call any CharacterIndex method.
func (*CharacterIndex) Len ¶ added in v0.9.8
func (ci *CharacterIndex) Len() int
Len returns the number of character names currently in the index.
func (*CharacterIndex) Rebuild ¶ added in v0.9.8
func (ci *CharacterIndex) Rebuild()
Rebuild clears the index and repopulates it from every user record 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 (*CharacterIndex) Remove ¶ added in v0.9.8
func (ci *CharacterIndex) Remove(name string)
Remove deletes the entry for name from the index. It is a no-op if the name is not present.
type CharacterSearchResult ¶ added in v0.9.8
type CharacterSearchResult struct {
UserId int `json:"user_id"`
Username string `json:"username"`
CharacterName string `json:"character_name"`
}
CharacterSearchResult holds the data returned by character search endpoints.
func SearchCharacters ¶ added in v0.9.8
func SearchCharacters(searchName string) []CharacterSearchResult
SearchCharacters searches the character index for names matching searchName. An exact match (case-insensitive) returns a single result. When there is no exact match, all names that have searchName as a prefix are returned (up to 100). The results include the owning userId and username.
type FunctionExporter ¶ added in v0.9.8
FunctionExporter is satisfied by the plugin registry, allowing the users package to call exported plugin functions without importing internal/plugins.
type IndexMetaData ¶
type IndexMetaData struct {
MetaDataSize uint64 // size of the metadata header (in bytes)
IndexVersion uint64
RecordCount uint64
RecordSize uint64
Checksum uint64 // FNV-64 fingerprint of user directory contents; 0 when IndexChecksumEnabled is false
}
IndexMetaData holds header info that helps in reading the file.
func (IndexMetaData) Format ¶
func (m IndexMetaData) Format() ([]byte, error)
Format formats the metadata header as a fixed-width string. The header (without newline) is exactly 99 bytes.
type IndexUserRecord ¶
IndexUserRecord represents one fixed-width record.
type OnlineInfo ¶
type UserIndex ¶
type UserIndex struct {
Filename string
// contains filtered or unexported fields
}
UserIndex is the central struct that holds the index filename and methods to work with the index.
func GetUserIndex ¶ added in v0.9.8
func GetUserIndex() *UserIndex
GetUserIndex returns the singleton UserIndex, initializing it if needed.
func InitUserIndex ¶ added in v0.9.8
func InitUserIndex() *UserIndex
InitUserIndex creates and initializes the singleton UserIndex. Called once at startup.
func (*UserIndex) FindByUserId ¶
FindByUserId searches for a user record matching the provided userId.
func (*UserIndex) FindByUsername ¶
FindByUsername searches the index for a username and returns its userId.
func (*UserIndex) ForEachRecord ¶ added in v0.9.8
func (idx *UserIndex) ForEachRecord(fn func(rec IndexUserRecord) bool)
ForEachRecord iterates over all index records, calling fn for each. Returning false from fn stops iteration.
func (*UserIndex) GetHighestUserId ¶
func (*UserIndex) GetMetaData ¶
func (idx *UserIndex) GetMetaData() IndexMetaData
func (*UserIndex) IsUpToDate ¶ added in v0.9.8
IsUpToDate returns true if the index file exists, has the current version, and its stored FNV-64 checksum matches the current state of the user directory.
func (*UserIndex) Rebuild ¶
Rebuild recreates the index from all offline user records. It calls Create() internally so it is self-contained. After building, it computes and persists a directory checksum so that IsUpToDate can detect stale indexes on the next startup.
func (*UserIndex) RemoveByUsername ¶
RemoveByUsername removes the first record matching the username and rewrites the index.
type UserLog ¶
type UserLog []UserLogEntry
func (*UserLog) Items ¶
func (ul *UserLog) Items(yield func(UserLogEntry) bool)
type UserLogEntry ¶
type UserRecord ¶
type UserRecord struct {
UserId int `yaml:"userid"`
Role string `yaml:"role"` // user, mod, or admin
Permissions []string `yaml:"permissions,omitempty"` // Discrete permissions for mod role
Username string `yaml:"username"`
Password string `yaml:"password"`
Joined time.Time `yaml:"joined"`
Macros map[string]string `yaml:"macros,omitempty"` // Up to 10 macros, just string commands.
Aliases map[string]string `yaml:"aliases,omitempty"` // string=>string remapping of commands
Character *characters.Character `yaml:"character,omitempty"`
ConfigOptions map[string]any `yaml:"configoptions,omitempty"`
Muted bool `yaml:"muted,omitempty"` // Cannot SEND custom communications to anyone but admin/mods
ScreenReader bool `yaml:"screenreader,omitempty"` // Are they using a screen reader? (We should remove excess symbols)
EmailAddress string `yaml:"emailaddress,omitempty"` // Email address (if provided)
TipsComplete map[string]bool `yaml:"tipscomplete,omitempty"` // Tips the user has followed/completed so they can be quiet
EventLog UserLog `yaml:"-"` // Do not retain in user file (for now)
LastMusic string `yaml:"-"` // Keeps track of the last music that was played
// contains filtered or unexported fields
}
func CopyoverReconnectUser ¶ added in v0.9.8
func CopyoverReconnectUser(user *UserRecord, connectionId connections.ConnectionId) (*UserRecord, string, error)
CopyoverReconnectUser takes over an existing session for a user who is reconnecting after a copyover. The caller must have already validated a one-time reconnect token that proves the identity of the connecting client. Unlike LoginUser, this always succeeds for users that are currently tracked (zombie or not), because the old connection is a stale copyover socket that is no longer connected.
func GetAllActiveUsers ¶
func GetAllActiveUsers() []*UserRecord
func GetByCharacterName ¶
func GetByCharacterName(name string) *UserRecord
func GetByConnectionId ¶
func GetByConnectionId(connectionId connections.ConnectionId) *UserRecord
func GetByUserId ¶
func GetByUserId(userId int) *UserRecord
func LoadUserById ¶ added in v0.9.8
func LoadUserById(userId int) (*UserRecord, error)
func LoginUser ¶
func LoginUser(user *UserRecord, connectionId connections.ConnectionId) (*UserRecord, string, error)
First time creating a user.
func NewUserRecord ¶
func NewUserRecord(userId int, connectionId uint64) *UserRecord
func (*UserRecord) AddBuff ¶
func (u *UserRecord) AddBuff(buffId int, source string)
func (*UserRecord) AddCommandAlias ¶
func (u *UserRecord) AddCommandAlias(input string, output string) (addedAlias string, deletedAlias string)
func (*UserRecord) BlockInput ¶
func (u *UserRecord) BlockInput()
func (*UserRecord) ClearPrompt ¶
func (u *UserRecord) ClearPrompt()
func (*UserRecord) ClientSettings ¶
func (u *UserRecord) ClientSettings() connections.ClientSettings
func (*UserRecord) Command ¶
func (u *UserRecord) Command(inputTxt string, waitSeconds ...float64)
func (*UserRecord) CommandFlagged ¶
func (u *UserRecord) CommandFlagged(inputTxt string, flagData events.EventFlag, waitSeconds ...float64)
func (*UserRecord) ConnectionId ¶
func (u *UserRecord) ConnectionId() uint64
func (*UserRecord) GetCommandPrompt ¶
func (u *UserRecord) GetCommandPrompt() string
func (*UserRecord) GetConfigOption ¶
func (u *UserRecord) GetConfigOption(key string) any
func (*UserRecord) GetConnectTime ¶
func (u *UserRecord) GetConnectTime() time.Time
func (*UserRecord) GetLastInputRound ¶
func (u *UserRecord) GetLastInputRound() uint64
func (*UserRecord) GetOnlineInfo ¶
func (u *UserRecord) GetOnlineInfo() OnlineInfo
func (*UserRecord) GetPrompt ¶
func (u *UserRecord) GetPrompt() *prompt.Prompt
func (*UserRecord) GetTempData ¶
func (u *UserRecord) GetTempData(key string) any
func (*UserRecord) GetUnsentText ¶
func (u *UserRecord) GetUnsentText() (unsent string, suggestion string)
func (*UserRecord) GrantXP ¶
func (u *UserRecord) GrantXP(amt int, source string)
Grants experience to the user and notifies them Additionally accepts `source` as a short identifier of the XP source Example source: "combat", "quest progress", "trash cleanup", "exploration"
func (*UserRecord) HasPermission ¶ added in v0.9.8
func (u *UserRecord) HasPermission(permissionId string) bool
HasPermission is a convenience wrapper around HasRolePermission without the simpleMatch parameter — used by web middleware where prefix-only matching is always desired.
func (*UserRecord) HasPlaintextPassword ¶ added in v0.9.8
func (u *UserRecord) HasPlaintextPassword() bool
func (*UserRecord) HasRolePermission ¶
func (u *UserRecord) HasRolePermission(permissionId string, simpleMatch ...bool) bool
HasRolePermission returns true when the user has the given permission. Admins always pass. Mods are checked against their Permissions slice using prefix-match semantics: a granted key of "room" also satisfies "room.edit", "room.edit.exits", etc. The optional simpleMatch parameter additionally allows the inverse direction (requested "room" matches granted "room.edit").
func (*UserRecord) HasShop ¶
func (u *UserRecord) HasShop() bool
func (*UserRecord) InputBlocked ¶
func (u *UserRecord) InputBlocked() bool
func (*UserRecord) PasswordMatches ¶
func (u *UserRecord) PasswordMatches(input string) bool
func (*UserRecord) PlayMusic ¶
func (u *UserRecord) PlayMusic(musicFileOrId string)
func (*UserRecord) PlaySound ¶
func (u *UserRecord) PlaySound(soundId string, category string)
func (*UserRecord) ProcessPromptString ¶
func (u *UserRecord) ProcessPromptString(promptStr string) string
func (*UserRecord) ReplaceCharacter ¶
func (u *UserRecord) ReplaceCharacter(replacement *characters.Character)
Replace a characters information with another.
func (*UserRecord) RoundTick ¶
func (u *UserRecord) RoundTick()
func (*UserRecord) SendText ¶
func (u *UserRecord) SendText(txt string)
func (*UserRecord) SendWebClientCommand ¶
func (u *UserRecord) SendWebClientCommand(txt string)
func (*UserRecord) SetCharacterName ¶
func (u *UserRecord) SetCharacterName(cn string) error
func (*UserRecord) SetConfigOption ¶
func (u *UserRecord) SetConfigOption(key string, value any)
func (*UserRecord) SetLastInputRound ¶
func (u *UserRecord) SetLastInputRound(rdNum uint64)
func (*UserRecord) SetPassword ¶
func (u *UserRecord) SetPassword(pw string) error
func (*UserRecord) SetTempData ¶
func (u *UserRecord) SetTempData(key string, value any)
func (*UserRecord) SetUnsentText ¶
func (u *UserRecord) SetUnsentText(t string, suggest string)
The purpose of SetUnsentText(), GetUnsentText() is to Capture what the user is typing so that when we redraw the "prompt" or status bar, we can redraw what they were in the middle of typing. I don't like the idea of capturing it every time they hit a key though There is probably a better way.
func (*UserRecord) SetUsername ¶
func (u *UserRecord) SetUsername(un string) error
func (*UserRecord) ShorthandId ¶
func (u *UserRecord) ShorthandId() string
func (*UserRecord) StartPrompt ¶
Prompt related functionality
func (*UserRecord) TempName ¶
func (u *UserRecord) TempName() string
func (*UserRecord) TryCommandAlias ¶
func (u *UserRecord) TryCommandAlias(input string) string
func (*UserRecord) UnblockInput ¶
func (u *UserRecord) UnblockInput()
func (*UserRecord) WimpyCheck ¶
func (u *UserRecord) WimpyCheck()
type UserSearchResult ¶ added in v0.9.8
type UserSearchResult struct {
UserId int `json:"user_id"`
Username string `json:"username"`
Role string `json:"role"`
Email string `json:"email"`
}
UserSearchResult holds the subset of user data returned by search endpoints.
func SearchUsers ¶ added in v0.9.8
func SearchUsers(searchName string) []UserSearchResult
SearchUsers searches for users matching searchName.
If searchName is a valid integer, the search matches by userId (exact match only). Otherwise it searches by username: an exact match returns a single result; all prefix matches are returned when there is no exact match. The username search is case-insensitive.
func SearchUsersByRole ¶ added in v0.9.8
func SearchUsersByRole(role string) []UserSearchResult
SearchUsersByRole returns all users whose Role matches the given role string (case-insensitive). Results are capped at 500.