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.
193 lines
6.1 KiB
C#
193 lines
6.1 KiB
C#
using SharpChat.Snowflake;
|
|
|
|
namespace SharpChat.Channels;
|
|
|
|
public class ChannelsContext(RandomSnowflake snowflake) {
|
|
private readonly Dictionary<long, Channel> Channels = [];
|
|
private Channel? DefaultChannel = null;
|
|
private readonly Lock @lock = new();
|
|
|
|
public bool ChannelExists(Func<Channel, bool> predicate) {
|
|
lock(@lock)
|
|
return Channels.Values.Any(predicate);
|
|
}
|
|
|
|
public bool ChannelExists(string name) {
|
|
return ChannelExists(c => c.NameEquals(name));
|
|
}
|
|
|
|
public Channel GetDefaultChannel() {
|
|
lock(@lock) {
|
|
DefaultChannel ??= GetChannel(c => c.IsPublic && !c.IsTemporary) ?? throw new NoDefaultChannelException();
|
|
return DefaultChannel;
|
|
}
|
|
}
|
|
|
|
public void SetDefaultChannel(Channel channel)
|
|
=> SetDefaultChannel(channel.Name);
|
|
|
|
public void SetDefaultChannel(string channelName) {
|
|
lock(@lock)
|
|
DefaultChannel = GetChannel(channelName) ?? throw new ChannelNotFoundException(nameof(channelName));
|
|
}
|
|
|
|
public Channel? GetChannel(Func<Channel, bool> predicate) {
|
|
lock(@lock)
|
|
return Channels.Values.FirstOrDefault(predicate);
|
|
}
|
|
|
|
public Channel? GetChannel(string name) {
|
|
return GetChannel(c => c.NameEquals(name));
|
|
}
|
|
|
|
public Channel? GetChannel(long id) {
|
|
lock(@lock)
|
|
return Channels.TryGetValue(id, out Channel? channel) ? channel : null;
|
|
}
|
|
|
|
public IEnumerable<Channel> GetChannels() {
|
|
lock(@lock)
|
|
return [.. Channels.Values];
|
|
}
|
|
|
|
public IEnumerable<Channel> GetChannels(IEnumerable<long> ids) {
|
|
return [.. ids.Select(GetChannel).Where(c => c is not null).Cast<Channel>()];
|
|
}
|
|
|
|
public IEnumerable<Channel> GetChannels(Func<Channel, bool> predicate) {
|
|
lock(@lock)
|
|
return [.. Channels.Values.Where(predicate)];
|
|
}
|
|
|
|
public IEnumerable<Channel> GetChannels(IEnumerable<string> names) {
|
|
return GetChannels(c => names.Any(n => c.NameEquals(n)));
|
|
}
|
|
|
|
public IEnumerable<Channel> GetChannels(int maxRank) {
|
|
return GetChannels(c => c.Rank <= maxRank);
|
|
}
|
|
|
|
public Channel CreateChannel(
|
|
string name,
|
|
string password = "",
|
|
bool temporary = false,
|
|
int rank = 0,
|
|
string ownerId = "",
|
|
long? id = null
|
|
) {
|
|
if(!Channel.CheckName(name))
|
|
throw new ChannelNameFormatException(nameof(name));
|
|
|
|
lock(@lock) {
|
|
if(ChannelExists(name))
|
|
throw new ChannelExistsException(nameof(name));
|
|
|
|
id ??= snowflake.Next();
|
|
if(Channels.ContainsKey(id.Value))
|
|
throw new ChannelExistsException(nameof(id));
|
|
|
|
Channel channel = new(id.Value, name, password, temporary, rank, ownerId);
|
|
Channels.Add(id.Value, channel);
|
|
|
|
return channel;
|
|
}
|
|
}
|
|
|
|
public ChannelDiff UpdateChannel(
|
|
long id,
|
|
string? name = null,
|
|
string? password = null,
|
|
bool? temporary = null,
|
|
int? rank = null,
|
|
string? ownerId = null
|
|
) => UpdateChannelInternal(
|
|
GetChannel(id) ?? throw new ChannelNotFoundException(nameof(id)),
|
|
name, password, temporary, rank, ownerId
|
|
);
|
|
|
|
public ChannelDiff UpdateChannel(
|
|
string currentName,
|
|
string? name = null,
|
|
string? password = null,
|
|
bool? temporary = null,
|
|
int? rank = null,
|
|
string? ownerId = null
|
|
) => UpdateChannelInternal(
|
|
GetChannel(currentName) ?? throw new ChannelNotFoundException(nameof(currentName)),
|
|
name, password, temporary, rank, ownerId
|
|
);
|
|
|
|
public ChannelDiff UpdateChannel(
|
|
Channel channel,
|
|
string? name = null,
|
|
string? password = null,
|
|
bool? temporary = null,
|
|
int? rank = null,
|
|
string? ownerId = null
|
|
) => UpdateChannel(channel.Id, name, password, temporary, rank, ownerId);
|
|
|
|
private ChannelDiff UpdateChannelInternal(
|
|
Channel channel,
|
|
string? name = null,
|
|
string? password = null,
|
|
bool? temporary = null,
|
|
int? rank = null,
|
|
string? ownerId = null
|
|
) {
|
|
lock(@lock) {
|
|
StringDiff nameDiff = new(channel.Name, name);
|
|
if(nameDiff.Changed) {
|
|
if(!Channel.CheckName(nameDiff.After))
|
|
throw new ChannelNameFormatException(nameof(name));
|
|
if(ChannelExists(nameDiff.After))
|
|
throw new ChannelExistsException(nameof(name));
|
|
|
|
channel.Name = nameDiff.After;
|
|
}
|
|
|
|
StringDiff passwordDiff = new(channel.Password, password);
|
|
if(passwordDiff.Changed)
|
|
channel.Password = passwordDiff.After;
|
|
|
|
ValueDiff<bool> temporaryDiff = new(channel.IsTemporary, temporary);
|
|
if(temporaryDiff.Changed)
|
|
channel.IsTemporary = temporaryDiff.After;
|
|
|
|
ValueDiff<int> rankDiff = new(channel.Rank, rank);
|
|
if(rankDiff.Changed)
|
|
channel.Rank = rankDiff.After;
|
|
|
|
StringDiff ownerIdDiff = new(channel.OwnerId, ownerId);
|
|
if(ownerIdDiff.Changed)
|
|
channel.OwnerId = ownerIdDiff.After;
|
|
|
|
return new(
|
|
channel,
|
|
nameDiff,
|
|
passwordDiff,
|
|
temporaryDiff,
|
|
rankDiff,
|
|
ownerIdDiff
|
|
);
|
|
}
|
|
}
|
|
|
|
public void RemoveChannel(long id)
|
|
=> RemoveChannelInternal(GetChannel(id) ?? throw new ChannelNotFoundException(nameof(id)), nameof(id));
|
|
|
|
public void RemoveChannel(Channel channel)
|
|
=> RemoveChannel(channel.Name);
|
|
|
|
public void RemoveChannel(string name)
|
|
=> RemoveChannelInternal(GetChannel(name) ?? throw new ChannelNotFoundException(nameof(name)), nameof(name));
|
|
|
|
private void RemoveChannelInternal(Channel channel, string argName) {
|
|
lock(@lock) {
|
|
Channel defaultChannel = GetDefaultChannel();
|
|
if(channel == defaultChannel || defaultChannel.NameEquals(channel.Name))
|
|
throw new ChannelIsDefaultException(argName);
|
|
|
|
Channels.Remove(channel.Id);
|
|
}
|
|
}
|
|
}
|