160 lines
5.4 KiB
C#
160 lines
5.4 KiB
C#
using SharpChat.Packet;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
|
|
namespace SharpChat {
|
|
public class ChannelException : Exception { }
|
|
public class ChannelExistException : ChannelException { }
|
|
public class ChannelInvalidNameException : ChannelException { }
|
|
|
|
public class ChannelManager : IDisposable {
|
|
private readonly List<ChatChannel> Channels = new List<ChatChannel>();
|
|
|
|
public readonly ChatContext Context;
|
|
|
|
public bool IsDisposed { get; private set; }
|
|
|
|
public ChannelManager(ChatContext context) {
|
|
Context = context;
|
|
}
|
|
|
|
private ChatChannel _DefaultChannel;
|
|
|
|
public ChatChannel DefaultChannel {
|
|
get {
|
|
if (_DefaultChannel == null)
|
|
_DefaultChannel = Channels.FirstOrDefault();
|
|
|
|
return _DefaultChannel;
|
|
}
|
|
set {
|
|
if (value == null)
|
|
return;
|
|
|
|
if (Channels.Contains(value))
|
|
_DefaultChannel = value;
|
|
}
|
|
}
|
|
|
|
|
|
public void Add(ChatChannel channel) {
|
|
if (channel == null)
|
|
throw new ArgumentNullException(nameof(channel));
|
|
if (!channel.Name.All(c => char.IsLetter(c) || char.IsNumber(c) || c == '-'))
|
|
throw new ChannelInvalidNameException();
|
|
if (Get(channel.Name) != null)
|
|
throw new ChannelExistException();
|
|
|
|
// Add channel to the listing
|
|
Channels.Add(channel);
|
|
|
|
// Set as default if there's none yet
|
|
if (_DefaultChannel == null)
|
|
_DefaultChannel = channel;
|
|
|
|
// Broadcast creation of channel
|
|
foreach (ChatUser user in Context.Users.OfHierarchy(channel.Rank))
|
|
user.Send(new ChannelCreatePacket(channel));
|
|
}
|
|
|
|
public void Remove(ChatChannel channel) {
|
|
if (channel == null || channel == DefaultChannel)
|
|
return;
|
|
|
|
// Remove channel from the listing
|
|
Channels.Remove(channel);
|
|
|
|
// Move all users back to the main channel
|
|
// TODO: Replace this with a kick. SCv2 supports being in 0 channels, SCv1 should force the user back to DefaultChannel.
|
|
foreach (ChatUser user in channel.GetUsers()) {
|
|
Context.SwitchChannel(user, DefaultChannel, string.Empty);
|
|
}
|
|
|
|
// Broadcast deletion of channel
|
|
foreach (ChatUser user in Context.Users.OfHierarchy(channel.Rank))
|
|
user.Send(new ChannelDeletePacket(channel));
|
|
}
|
|
|
|
public bool Contains(ChatChannel chan) {
|
|
if (chan == null)
|
|
return false;
|
|
|
|
lock (Channels)
|
|
return Channels.Contains(chan) || Channels.Any(c => c.Name.ToLowerInvariant() == chan.Name.ToLowerInvariant());
|
|
}
|
|
|
|
public void Update(ChatChannel channel, string name = null, bool? temporary = null, int? hierarchy = null, string password = null) {
|
|
if (channel == null)
|
|
throw new ArgumentNullException(nameof(channel));
|
|
if (!Channels.Contains(channel))
|
|
throw new ArgumentException(@"Provided channel is not registered with this manager.", nameof(channel));
|
|
|
|
string prevName = channel.Name;
|
|
int prevHierarchy = channel.Rank;
|
|
bool nameUpdated = !string.IsNullOrWhiteSpace(name) && name != prevName;
|
|
|
|
if (nameUpdated) {
|
|
if (!name.All(c => char.IsLetter(c) || char.IsNumber(c) || c == '-'))
|
|
throw new ChannelInvalidNameException();
|
|
if (Get(name) != null)
|
|
throw new ChannelExistException();
|
|
|
|
channel.Name = name;
|
|
}
|
|
|
|
if (temporary.HasValue)
|
|
channel.IsTemporary = temporary.Value;
|
|
|
|
if (hierarchy.HasValue)
|
|
channel.Rank = hierarchy.Value;
|
|
|
|
if (password != null)
|
|
channel.Password = password;
|
|
|
|
// Users that no longer have access to the channel/gained access to the channel by the hierarchy change should receive delete and create packets respectively
|
|
foreach (ChatUser user in Context.Users.OfHierarchy(channel.Rank)) {
|
|
user.Send(new ChannelUpdatePacket(prevName, channel));
|
|
|
|
if (nameUpdated)
|
|
user.ForceChannel();
|
|
}
|
|
}
|
|
|
|
public ChatChannel Get(string name) {
|
|
if (string.IsNullOrWhiteSpace(name))
|
|
return null;
|
|
|
|
return Channels.FirstOrDefault(x => x.Name.ToLowerInvariant() == name.ToLowerInvariant());
|
|
}
|
|
|
|
public IEnumerable<ChatChannel> GetUser(ChatUser user) {
|
|
if (user == null)
|
|
return null;
|
|
|
|
return Channels.Where(x => x.HasUser(user));
|
|
}
|
|
|
|
public IEnumerable<ChatChannel> OfHierarchy(int hierarchy) {
|
|
lock (Channels)
|
|
return Channels.Where(c => c.Rank <= hierarchy).ToList();
|
|
}
|
|
|
|
~ChannelManager()
|
|
=> Dispose(false);
|
|
|
|
public void Dispose()
|
|
=> Dispose(true);
|
|
|
|
private void Dispose(bool disposing) {
|
|
if (IsDisposed)
|
|
return;
|
|
IsDisposed = true;
|
|
|
|
Channels.Clear();
|
|
|
|
if (disposing)
|
|
GC.SuppressFinalize(this);
|
|
}
|
|
}
|
|
}
|