sharp-chat/SharpChatCommon/Users/UsersContext.cs
flashwave 5a7756894b
First bits of the Context overhaul.
Reintroduces separate contexts for users, channels, connections (now split into sessions and connections) and user-channel associations.
It builds which is as much assurance as I can give about the stability of this commit, but its also the bare minimum of what i like to commit sooooo
A lot of things still need to be broadcast through events throughout the application in order to keep states consistent but we'll cross that bridge when we get to it.
I really need to stop using that phrase thingy, I'm overusing it.
2025-05-03 02:49:51 +00:00

193 lines
5.6 KiB
C#

using SharpChat.Auth;
namespace SharpChat.Users;
public class UsersContext {
private readonly Dictionary<string, User> Users = [];
private readonly Lock @lock = new();
public bool UserExists(string id) {
lock(@lock)
return Users.ContainsKey(id);
}
public bool UserExists(Func<User, bool> predicate) {
lock(@lock)
return Users.Values.Any(predicate);
}
public User? GetUser(string id) {
lock(@lock)
return Users.TryGetValue(id, out User? user) ? user : null;
}
public User? GetUser(Func<User, bool> predicate) {
lock(@lock)
return Users.Values.FirstOrDefault(predicate);
}
public IEnumerable<User> GetUsers() {
lock(@lock)
return [.. Users.Values];
}
public IEnumerable<User> GetUsers(IEnumerable<string> ids) {
return [.. ids.Select(GetUser).Where(u => u is not null).Cast<User>()];
}
public IEnumerable<User> GetUsers(Func<User, bool> predicate) {
lock(@lock)
return [.. Users.Values.Where(predicate)];
}
public IEnumerable<User> GetUsersWithStatus(UserStatus status) {
return GetUsers(u => u.Status == status);
}
public IEnumerable<User> GetUsersOfMinimumRank(int minRank) {
return GetUsers(u => u.Rank >= minRank);
}
public User CreateOrUpdateUser(AuthResult authResult) {
lock(@lock) {
User? user = GetUser(authResult.UserId);
return user is null ? CreateUserInternal(
authResult.UserId,
authResult.UserName,
authResult.UserColour,
authResult.UserRank,
authResult.UserPermissions
) : UpdateUserInternal(
user,
authResult.UserId,
authResult.UserName,
authResult.UserColour,
authResult.UserRank,
authResult.UserPermissions
).User;
}
}
public User CreateUser(
string id,
string name,
ColourInheritable colour,
int rank,
UserPermissions perms,
string nick = "",
UserStatus status = UserStatus.Online,
string statusText = ""
) {
lock(@lock)
return UserExists(id)
? throw new UserExistsException(nameof(id))
: CreateUserInternal(id, name, colour, rank, perms, nick, status, statusText);
}
private User CreateUserInternal(
string id,
string name,
ColourInheritable colour,
int rank,
UserPermissions perms,
string nick = "",
UserStatus status = UserStatus.Online,
string statusText = ""
) {
User user = new(id, name, colour, rank, perms, nick, status, statusText);
Users.Add(id, user);
return user;
}
public UserDiff UpdateUser(
User user,
string? name = null,
ColourInheritable? colour = null,
int? rank = null,
UserPermissions? perms = null,
string? nick = null,
UserStatus? status = null,
string? statusText = null
) => UpdateUser(user.UserId, name, colour, rank, perms, nick, status, statusText);
public UserDiff UpdateUser(
string id,
string? name = null,
ColourInheritable? colour = null,
int? rank = null,
UserPermissions? perms = null,
string? nick = null,
UserStatus? status = null,
string? statusText = null
) {
lock(@lock)
return UpdateUserInternal(
GetUser(id) ?? throw new UserNotFoundException(nameof(id)),
id, name, colour, rank, perms, nick, status, statusText
);
}
private static UserDiff UpdateUserInternal(
User user,
string id,
string? name = null,
ColourInheritable? colour = null,
int? rank = null,
UserPermissions? perms = null,
string? nick = null,
UserStatus? status = null,
string? statusText = null
) {
StringDiff nameDiff = new(user.UserName, name);
if(nameDiff.Changed)
user.UserName = nameDiff.After;
ValueDiff<ColourInheritable> colourDiff = new(user.Colour, colour);
if(colourDiff.Changed)
user.Colour = colourDiff.After;
ValueDiff<int> rankDiff = new(user.Rank, rank);
if(rankDiff.Changed)
user.Rank = rankDiff.After;
ValueDiff<UserPermissions> permsDiff = new(user.Permissions, perms);
if(permsDiff.Changed)
user.Permissions = permsDiff.After;
StringDiff nickDiff = new(user.NickName, nick);
if(nickDiff.Changed)
user.NickName = nickDiff.After;
ValueDiff<UserStatus> statusDiff = new(user.Status, status);
if(statusDiff.Changed)
user.Status = statusDiff.After;
StringDiff statusTextDiff = new(user.StatusText, statusText);
if(statusTextDiff.Changed)
user.StatusText = statusTextDiff.After;
return new(
user,
id,
nameDiff,
colourDiff,
rankDiff,
permsDiff,
nickDiff,
statusDiff,
statusTextDiff
);
}
public void RemoveUser(User user)
=> RemoveUserInternal(user.UserId, nameof(user));
public void RemoveUser(string id)
=> RemoveUserInternal(id, nameof(id));
private void RemoveUserInternal(string id, string argName) {
lock(@lock)
if(!Users.Remove(id))
throw new UserNotFoundException(argName);
}
}