Code style updates.

This commit is contained in:
flash 2023-02-07 16:01:56 +01:00
parent c9cc5ff23a
commit 4104e40843
42 changed files with 292 additions and 317 deletions

View file

@ -26,7 +26,9 @@ namespace SharpChat {
Username = fb.Username;
}
public override string ToString() => Username;
public override string ToString() {
return Username;
}
}
public class BannedIPAddress : IBan {
@ -41,7 +43,9 @@ namespace SharpChat {
Expires = fb.Expires;
}
public override string ToString() => Address.ToString();
public override string ToString() {
return Address.ToString();
}
}
public class BanManager : IDisposable {
@ -168,8 +172,9 @@ namespace SharpChat {
return BanList.ToList();
}
~BanManager()
=> DoDispose();
~BanManager() {
DoDispose();
}
public void Dispose() {
DoDispose();

View file

@ -9,7 +9,7 @@ namespace SharpChat {
public class ChannelInvalidNameException : ChannelException { }
public class ChannelManager : IDisposable {
private readonly List<ChatChannel> Channels = new List<ChatChannel>();
private readonly List<ChatChannel> Channels = new();
public readonly ChatContext Context;
@ -23,43 +23,43 @@ namespace SharpChat {
public ChatChannel DefaultChannel {
get {
if (_DefaultChannel == null)
if(_DefaultChannel == null)
_DefaultChannel = Channels.FirstOrDefault();
return _DefaultChannel;
}
set {
if (value == null)
if(value == null)
return;
if (Channels.Contains(value))
if(Channels.Contains(value))
_DefaultChannel = value;
}
}
public void Add(ChatChannel channel) {
if (channel == null)
if(channel == null)
throw new ArgumentNullException(nameof(channel));
if (!channel.Name.All(c => char.IsLetter(c) || char.IsNumber(c) || c == '-'))
if(!channel.Name.All(c => char.IsLetter(c) || char.IsNumber(c) || c == '-'))
throw new ChannelInvalidNameException();
if (Get(channel.Name) != null)
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)
if(_DefaultChannel == null)
_DefaultChannel = channel;
// Broadcast creation of channel
foreach (ChatUser user in Context.Users.OfHierarchy(channel.Rank))
foreach(ChatUser user in Context.Users.OfHierarchy(channel.Rank))
user.Send(new ChannelCreatePacket(channel));
}
public void Remove(ChatChannel channel) {
if (channel == null || channel == DefaultChannel)
if(channel == null || channel == DefaultChannel)
return;
// Remove channel from the listing
@ -67,94 +67,94 @@ namespace SharpChat {
// 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()) {
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))
foreach(ChatUser user in Context.Users.OfHierarchy(channel.Rank))
user.Send(new ChannelDeletePacket(channel));
}
public bool Contains(ChatChannel chan) {
if (chan == null)
if(chan == null)
return false;
lock (Channels)
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)
if(channel == null)
throw new ArgumentNullException(nameof(channel));
if (!Channels.Contains(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 == '-'))
if(nameUpdated) {
if(!name.All(c => char.IsLetter(c) || char.IsNumber(c) || c == '-'))
throw new ChannelInvalidNameException();
if (Get(name) != null)
if(Get(name) != null)
throw new ChannelExistException();
channel.Name = name;
}
if (temporary.HasValue)
if(temporary.HasValue)
channel.IsTemporary = temporary.Value;
if (hierarchy.HasValue)
if(hierarchy.HasValue)
channel.Rank = hierarchy.Value;
if (password != null)
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)) {
foreach(ChatUser user in Context.Users.OfHierarchy(channel.Rank)) {
user.Send(new ChannelUpdatePacket(prevName, channel));
if (nameUpdated)
if(nameUpdated)
user.ForceChannel();
}
}
public ChatChannel Get(string name) {
if (string.IsNullOrWhiteSpace(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)
if(user == null)
return null;
return Channels.Where(x => x.HasUser(user));
}
public IEnumerable<ChatChannel> OfHierarchy(int hierarchy) {
lock (Channels)
lock(Channels)
return Channels.Where(c => c.Rank <= hierarchy).ToList();
}
~ChannelManager()
=> Dispose(false);
~ChannelManager() {
DoDispose();
}
public void Dispose()
=> Dispose(true);
public void Dispose() {
DoDispose();
GC.SuppressFinalize(this);
}
private void Dispose(bool disposing) {
if (IsDisposed)
private void DoDispose() {
if(IsDisposed)
return;
IsDisposed = true;
Channels.Clear();
if (disposing)
GC.SuppressFinalize(this);
}
}
}

View file

@ -10,8 +10,7 @@ namespace SharpChat {
public int Rank { get; set; } = 0;
public ChatUser Owner { get; set; } = null;
private List<ChatUser> Users { get; } = new List<ChatUser>();
private List<ChatChannelTyping> Typing { get; } = new List<ChatChannelTyping>();
private List<ChatUser> Users { get; } = new();
public bool HasPassword
=> !string.IsNullOrWhiteSpace(Password);
@ -26,73 +25,51 @@ namespace SharpChat {
}
public bool HasUser(ChatUser user) {
lock (Users)
lock(Users)
return Users.Contains(user);
}
public void UserJoin(ChatUser user) {
if (!user.InChannel(this)) {
if(!user.InChannel(this)) {
// Remove this, a different means for this should be established for V1 compat.
user.Channel?.UserLeave(user);
user.JoinChannel(this);
}
lock (Users) {
if (!HasUser(user))
lock(Users) {
if(!HasUser(user))
Users.Add(user);
}
}
public void UserLeave(ChatUser user) {
lock (Users)
lock(Users)
Users.Remove(user);
if (user.InChannel(this))
if(user.InChannel(this))
user.LeaveChannel(this);
}
public void Send(IServerPacket packet) {
lock (Users) {
foreach (ChatUser user in Users)
lock(Users) {
foreach(ChatUser user in Users)
user.Send(packet);
}
}
public IEnumerable<ChatUser> GetUsers(IEnumerable<ChatUser> exclude = null) {
lock (Users) {
lock(Users) {
IEnumerable<ChatUser> users = Users.OrderByDescending(x => x.Rank);
if (exclude != null)
if(exclude != null)
users = users.Except(exclude);
return users.ToList();
}
}
public bool IsTyping(ChatUser user) {
if(user == null)
return false;
lock(Typing)
return Typing.Any(x => x.User == user && !x.HasExpired);
}
public bool CanType(ChatUser user) {
if(user == null || !HasUser(user))
return false;
return !IsTyping(user);
}
public ChatChannelTyping RegisterTyping(ChatUser user) {
if(user == null || !HasUser(user))
return null;
ChatChannelTyping typing = new ChatChannelTyping(user);
lock(Typing) {
Typing.RemoveAll(x => x.HasExpired);
Typing.Add(typing);
}
return typing;
}
public string Pack() {
StringBuilder sb = new StringBuilder();
StringBuilder sb = new();
sb.Append(Name);
sb.Append('\t');

View file

@ -1,18 +0,0 @@
using System;
namespace SharpChat {
public class ChatChannelTyping {
public static TimeSpan Lifetime { get; } = TimeSpan.FromSeconds(5);
public ChatUser User { get; }
public DateTimeOffset Started { get; }
public bool HasExpired
=> DateTimeOffset.Now - Started > Lifetime;
public ChatChannelTyping(ChatUser user) {
User = user ?? throw new ArgumentNullException(nameof(user));
Started = DateTimeOffset.Now;
}
}
}

View file

@ -15,7 +15,7 @@
public bool Inherit {
get => (Raw & INHERIT) > 0;
set {
if (value)
if(value)
Raw |= INHERIT;
else
Raw &= ~INHERIT;
@ -47,7 +47,7 @@
}
public override string ToString() {
if (Inherit)
if(Inherit)
return @"inherit";
return string.Format(@"#{0:X6}", Raw);
}

View file

@ -28,10 +28,10 @@ namespace SharpChat {
public ChatContext(HttpClient httpClient, SockChatServer server) {
HttpClient = httpClient;
Server = server;
Bans = new BanManager(httpClient, this);
Users = new UserManager(this);
Channels = new ChannelManager(this);
Events = new ChatEventManager(this);
Bans = new(httpClient, this);
Users = new(this);
Channels = new(this);
Events = new(this);
BumpTimer = new Timer(e => FlashiiBump.SubmitAsync(HttpClient, Users.WithActiveConnections()).Wait(), null, TimeSpan.Zero, TimeSpan.FromMinutes(1));
}
@ -43,10 +43,10 @@ namespace SharpChat {
}
public void BanUser(ChatUser user, DateTimeOffset? until = null, bool banIPs = false, UserDisconnectReason reason = UserDisconnectReason.Kicked) {
if (until.HasValue && until.Value <= DateTimeOffset.UtcNow)
if(until.HasValue && until.Value <= DateTimeOffset.UtcNow)
until = null;
if (until.HasValue) {
if(until.HasValue) {
user.Send(new ForceDisconnectPacket(ForceDisconnectReason.Banned, until.Value));
lock(BansAccess) {
@ -64,7 +64,7 @@ namespace SharpChat {
}
public void HandleJoin(ChatUser user, ChatChannel chan, ChatUserSession sess) {
if (!chan.HasUser(user)) {
if(!chan.HasUser(user)) {
chan.Send(new UserConnectPacket(DateTimeOffset.Now, user));
Events.Add(new UserConnectEvent(DateTimeOffset.Now, user, chan));
}
@ -79,24 +79,24 @@ namespace SharpChat {
sess.Send(new ContextChannelsPacket(Channels.OfHierarchy(user.Rank)));
if (!chan.HasUser(user))
if(!chan.HasUser(user))
chan.UserJoin(user);
if (!Users.Contains(user))
if(!Users.Contains(user))
Users.Add(user);
}
public void UserLeave(ChatChannel chan, ChatUser user, UserDisconnectReason reason = UserDisconnectReason.Leave) {
user.Status = ChatUserStatus.Offline;
if (chan == null) {
if(chan == null) {
foreach(ChatChannel channel in user.GetChannels()) {
UserLeave(channel, user, reason);
}
return;
}
if (chan.IsTemporary && chan.Owner == user)
if(chan.IsTemporary && chan.Owner == user)
Channels.Remove(chan);
chan.UserLeave(user);
@ -105,20 +105,20 @@ namespace SharpChat {
}
public void SwitchChannel(ChatUser user, ChatChannel chan, string password) {
if (user.CurrentChannel == chan) {
if(user.CurrentChannel == chan) {
//user.Send(true, @"samechan", chan.Name);
user.ForceChannel();
return;
}
if (!user.Can(ChatUserPermissions.JoinAnyChannel) && chan.Owner != user) {
if (chan.Rank > user.Rank) {
if(!user.Can(ChatUserPermissions.JoinAnyChannel) && chan.Owner != user) {
if(chan.Rank > user.Rank) {
user.Send(new LegacyCommandResponse(LCR.CHANNEL_INSUFFICIENT_HIERARCHY, true, chan.Name));
user.ForceChannel();
return;
}
if (chan.Password != password) {
if(chan.Password != password) {
user.Send(new LegacyCommandResponse(LCR.CHANNEL_INVALID_PASSWORD, true, chan.Name));
user.ForceChannel();
return;
@ -129,7 +129,7 @@ namespace SharpChat {
}
public void ForceChannelSwitch(ChatUser user, ChatChannel chan) {
if (!Channels.Contains(chan))
if(!Channels.Contains(chan))
return;
ChatChannel oldChan = user.CurrentChannel;
@ -144,20 +144,20 @@ namespace SharpChat {
IEnumerable<IChatEvent> msgs = Events.GetTargetLog(chan);
foreach (IChatEvent msg in msgs)
foreach(IChatEvent msg in msgs)
user.Send(new ContextMessagePacket(msg));
user.ForceChannel(chan);
oldChan.UserLeave(user);
chan.UserJoin(user);
if (oldChan.IsTemporary && oldChan.Owner == user)
if(oldChan.IsTemporary && oldChan.Owner == user)
Channels.Remove(oldChan);
}
public void CheckPings() {
lock(Users)
foreach (ChatUser user in Users.All()) {
foreach(ChatUser user in Users.All()) {
IEnumerable<ChatUserSession> timedOut = user.GetDeadSessions();
foreach(ChatUserSession sess in timedOut) {
@ -172,7 +172,7 @@ namespace SharpChat {
}
public void Send(IServerPacket packet) {
foreach (ChatUser user in Users.All())
foreach(ChatUser user in Users.All())
user.Send(packet);
}
@ -186,7 +186,7 @@ namespace SharpChat {
}
private void DoDispose() {
if (IsDisposed)
if(IsDisposed)
return;
IsDisposed = true;

View file

@ -15,12 +15,12 @@ namespace SharpChat {
public ChatEventManager(ChatContext context) {
Context = context;
if (!Database.HasDatabase)
Events = new List<IChatEvent>();
if(!Database.HasDatabase)
Events = new();
}
public void Add(IChatEvent evt) {
if (evt == null)
if(evt == null)
throw new ArgumentNullException(nameof(evt));
if(Events != null)
@ -32,39 +32,39 @@ namespace SharpChat {
}
public void Remove(IChatEvent evt) {
if (evt == null)
if(evt == null)
return;
if (Events != null)
lock (Events)
if(Events != null)
lock(Events)
Events.Remove(evt);
if (Database.HasDatabase)
if(Database.HasDatabase)
Database.DeleteEvent(evt);
Context.Send(new ChatMessageDeletePacket(evt.SequenceId));
}
public IChatEvent Get(long seqId) {
if (seqId < 1)
if(seqId < 1)
return null;
if (Database.HasDatabase)
if(Database.HasDatabase)
return Database.GetEvent(seqId);
if (Events != null)
lock (Events)
if(Events != null)
lock(Events)
return Events.FirstOrDefault(e => e.SequenceId == seqId);
return null;
}
public IEnumerable<IChatEvent> GetTargetLog(IPacketTarget target, int amount = 20, int offset = 0) {
if (Database.HasDatabase)
if(Database.HasDatabase)
return Database.GetEvents(target, amount, offset).Reverse();
if (Events != null)
lock (Events) {
if(Events != null)
lock(Events) {
IEnumerable<IChatEvent> subset = Events.Where(e => e.Target == target || e.Target == null);
int start = subset.Count() - offset - amount;
@ -80,21 +80,21 @@ namespace SharpChat {
return Enumerable.Empty<IChatEvent>();
}
~ChatEventManager()
=> Dispose(false);
~ChatEventManager() {
DoDispose();
}
public void Dispose()
=> Dispose(true);
public void Dispose() {
DoDispose();
GC.SuppressFinalize(this);
}
private void Dispose(bool disposing) {
if (IsDisposed)
private void DoDispose() {
if(IsDisposed)
return;
IsDisposed = true;
Events?.Clear();
if (disposing)
GC.SuppressFinalize(this);
}
}
}

View file

@ -13,16 +13,16 @@ namespace SharpChat {
private const int FLOOD_PROTECTION_AMOUNT = 30;
private const int FLOOD_PROTECTION_THRESHOLD = 10;
private readonly Queue<DateTimeOffset> TimePoints = new Queue<DateTimeOffset>();
private readonly Queue<DateTimeOffset> TimePoints = new();
public ChatRateLimitState State {
get {
lock (TimePoints) {
if (TimePoints.Count == FLOOD_PROTECTION_AMOUNT) {
if ((TimePoints.Last() - TimePoints.First()).TotalSeconds <= FLOOD_PROTECTION_THRESHOLD)
lock(TimePoints) {
if(TimePoints.Count == FLOOD_PROTECTION_AMOUNT) {
if((TimePoints.Last() - TimePoints.First()).TotalSeconds <= FLOOD_PROTECTION_THRESHOLD)
return ChatRateLimitState.Kick;
if ((TimePoints.Last() - TimePoints.Skip(5).First()).TotalSeconds <= FLOOD_PROTECTION_THRESHOLD)
if((TimePoints.Last() - TimePoints.Skip(5).First()).TotalSeconds <= FLOOD_PROTECTION_THRESHOLD)
return ChatRateLimitState.Warning;
}
@ -32,11 +32,11 @@ namespace SharpChat {
}
public void AddTimePoint(DateTimeOffset? dto = null) {
if (!dto.HasValue)
if(!dto.HasValue)
dto = DateTimeOffset.Now;
lock (TimePoints) {
if (TimePoints.Count >= FLOOD_PROTECTION_AMOUNT)
lock(TimePoints) {
if(TimePoints.Count >= FLOOD_PROTECTION_AMOUNT)
TimePoints.Dequeue();
TimePoints.Enqueue(dto.Value);

View file

@ -23,15 +23,16 @@ namespace SharpChat {
public bool HasFloodProtection
=> Rank < RANK_NO_FLOOD;
public bool Equals([AllowNull] BasicUser other)
=> UserId == other.UserId;
public bool Equals([AllowNull] BasicUser other) {
return UserId == other.UserId;
}
public string DisplayName {
get {
StringBuilder sb = new StringBuilder();
StringBuilder sb = new();
if(Status == ChatUserStatus.Away)
sb.AppendFormat(@"&lt;{0}&gt;_", StatusMessage.Substring(0, Math.Min(StatusMessage.Length, 5)).ToUpperInvariant());
sb.AppendFormat(@"&lt;{0}&gt;_", StatusMessage[..Math.Min(StatusMessage.Length, 5)].ToUpperInvariant());
if(string.IsNullOrWhiteSpace(Nickname))
sb.Append(Username);
@ -50,7 +51,7 @@ namespace SharpChat {
}
public string Pack() {
StringBuilder sb = new StringBuilder();
StringBuilder sb = new();
sb.Append(UserId);
sb.Append('\t');
@ -61,7 +62,7 @@ namespace SharpChat {
sb.Append(Rank);
sb.Append(' ');
sb.Append(Can(ChatUserPermissions.KickUser) ? '1' : '0');
sb.Append(@" 0 ");
sb.Append(@" 0 "); // view logs
sb.Append(Can(ChatUserPermissions.SetOwnNickname) ? '1' : '0');
sb.Append(' ');
sb.Append(Can(ChatUserPermissions.CreateChannel | ChatUserPermissions.SetChannelPermanent, true) ? 2 : (
@ -75,10 +76,10 @@ namespace SharpChat {
public class ChatUser : BasicUser, IPacketTarget {
public DateTimeOffset SilencedUntil { get; set; }
private readonly List<ChatUserSession> Sessions = new List<ChatUserSession>();
private readonly List<ChatChannel> Channels = new List<ChatChannel>();
private readonly List<ChatUserSession> Sessions = new();
private readonly List<ChatChannel> Channels = new();
public readonly ChatRateLimiter RateLimiter = new ChatRateLimiter();
public readonly ChatRateLimiter RateLimiter = new();
public string TargetName => @"@log";
@ -104,7 +105,7 @@ namespace SharpChat {
public int SessionCount {
get {
lock (Sessions)
lock(Sessions)
return Sessions.Where(c => !c.HasTimedOut && !c.IsDisposed).Count();
}
}
@ -127,33 +128,34 @@ namespace SharpChat {
public void ApplyAuth(FlashiiAuth auth, bool invalidateRestrictions = false) {
Username = auth.Username;
if (Status == ChatUserStatus.Offline)
if(Status == ChatUserStatus.Offline)
Status = ChatUserStatus.Online;
Colour = new ChatColour(auth.ColourRaw);
Colour = new(auth.ColourRaw);
Rank = auth.Rank;
Permissions = auth.Permissions;
if (invalidateRestrictions || !IsSilenced)
if(invalidateRestrictions || !IsSilenced)
SilencedUntil = auth.SilencedUntil;
}
public void Send(IServerPacket packet) {
lock(Sessions)
foreach (ChatUserSession conn in Sessions)
foreach(ChatUserSession conn in Sessions)
conn.Send(packet);
}
public void Close() {
lock (Sessions) {
foreach (ChatUserSession conn in Sessions)
lock(Sessions) {
foreach(ChatUserSession conn in Sessions)
conn.Dispose();
Sessions.Clear();
}
}
public void ForceChannel(ChatChannel chan = null)
=> Send(new UserChannelForceJoinPacket(chan ?? CurrentChannel));
public void ForceChannel(ChatChannel chan = null) {
Send(new UserChannelForceJoinPacket(chan ?? CurrentChannel));
}
public void FocusChannel(ChatChannel chan) {
lock(Channels) {
@ -163,12 +165,12 @@ namespace SharpChat {
}
public bool InChannel(ChatChannel chan) {
lock (Channels)
lock(Channels)
return Channels.Contains(chan);
}
public void JoinChannel(ChatChannel chan) {
lock (Channels) {
lock(Channels) {
if(!InChannel(chan)) {
Channels.Add(chan);
CurrentChannel = chan;
@ -184,21 +186,21 @@ namespace SharpChat {
}
public IEnumerable<ChatChannel> GetChannels() {
lock (Channels)
lock(Channels)
return Channels.ToList();
}
public void AddSession(ChatUserSession sess) {
if (sess == null)
if(sess == null)
return;
sess.User = this;
lock (Sessions)
lock(Sessions)
Sessions.Add(sess);
}
public void RemoveSession(ChatUserSession sess) {
if (sess == null)
if(sess == null)
return;
if(!sess.IsDisposed) // this could be possible
sess.User = null;
@ -208,7 +210,7 @@ namespace SharpChat {
}
public IEnumerable<ChatUserSession> GetDeadSessions() {
lock (Sessions)
lock(Sessions)
return Sessions.Where(x => x.HasTimedOut || x.IsDisposed).ToList();
}
}

View file

@ -20,7 +20,7 @@ namespace SharpChat {
public DateTimeOffset LastPing { get; set; } = DateTimeOffset.MinValue;
public ChatUser User { get; set; }
private static int CloseCode { get; set; } = 1000;
private int CloseCode { get; set; } = 1000;
public string TargetName => @"@log";
@ -65,30 +65,32 @@ namespace SharpChat {
Connection.Send(line);
}
public void BumpPing()
=> LastPing = DateTimeOffset.Now;
public void BumpPing() {
LastPing = DateTimeOffset.Now;
}
public bool HasTimedOut
=> DateTimeOffset.Now - LastPing > SessionTimeOut;
public void PrepareForRestart()
=> CloseCode = 1012;
public void PrepareForRestart() {
CloseCode = 1012;
}
public void Dispose()
=> Dispose(true);
~ChatUserSession() {
DoDispose();
}
~ChatUserSession()
=> Dispose(false);
public void Dispose() {
DoDispose();
GC.SuppressFinalize(this);
}
private void Dispose(bool disposing) {
private void DoDispose() {
if(IsDisposed)
return;
IsDisposed = true;
Connection.Close(CloseCode);
if(disposing)
GC.SuppressFinalize(this);
}
}
}

View file

@ -18,7 +18,7 @@ namespace SharpChat.Commands {
else {
statusText = statusText.Trim();
if(statusText.Length > MAX_LENGTH)
statusText = statusText.Substring(0, MAX_LENGTH).Trim();
statusText = statusText[..MAX_LENGTH].Trim();
}
context.User.Status = ChatUserStatus.Away;

View file

@ -17,7 +17,7 @@ namespace SharpChat {
if(!File.Exists(@"mariadb.txt"))
return;
string[] config = File.ReadAllLines(@"mariadb.txt");
if (config.Length < 4)
if(config.Length < 4)
return;
Init(config[0], config[1], config[2], config[3]);
}
@ -43,27 +43,27 @@ namespace SharpChat {
}
private static MySqlConnection GetConnection() {
if (!HasDatabase)
if(!HasDatabase)
return null;
MySqlConnection conn = new MySqlConnection(ConnectionString);
MySqlConnection conn = new(ConnectionString);
conn.Open();
return conn;
}
private static int RunCommand(string command, params MySqlParameter[] parameters) {
if (!HasDatabase)
if(!HasDatabase)
return 0;
try {
using MySqlConnection conn = GetConnection();
using MySqlCommand cmd = conn.CreateCommand();
if (parameters?.Length > 0)
if(parameters?.Length > 0)
cmd.Parameters.AddRange(parameters);
cmd.CommandText = command;
return cmd.ExecuteNonQuery();
} catch (MySqlException ex) {
} catch(MySqlException ex) {
Logger.Write(ex);
}
@ -71,13 +71,13 @@ namespace SharpChat {
}
private static MySqlDataReader RunQuery(string command, params MySqlParameter[] parameters) {
if (!HasDatabase)
if(!HasDatabase)
return null;
try {
MySqlConnection conn = GetConnection();
MySqlCommand cmd = conn.CreateCommand();
if (parameters?.Length > 0)
if(parameters?.Length > 0)
cmd.Parameters.AddRange(parameters);
cmd.CommandText = command;
return cmd.ExecuteReader(System.Data.CommandBehavior.CloseConnection);
@ -89,13 +89,13 @@ namespace SharpChat {
}
private static object RunQueryValue(string command, params MySqlParameter[] parameters) {
if (!HasDatabase)
if(!HasDatabase)
return null;
try {
using MySqlConnection conn = GetConnection();
using MySqlCommand cmd = conn.CreateCommand();
if (parameters?.Length > 0)
if(parameters?.Length > 0)
cmd.Parameters.AddRange(parameters);
cmd.CommandText = command;
cmd.Prepare();
@ -111,7 +111,7 @@ namespace SharpChat {
private static int IdCounter = 0;
public static long GenerateId() {
if (IdCounter > 200)
if(IdCounter > 200)
IdCounter = 0;
long id = 0;
@ -160,7 +160,7 @@ namespace SharpChat {
evt.Flags = (ChatMessageFlags)reader.GetByte(@"event_flags");
evt.DateTime = DateTimeOffset.FromUnixTimeSeconds(reader.GetInt32(@"event_created"));
if (!reader.IsDBNull(reader.GetOrdinal(@"event_sender"))) {
if(!reader.IsDBNull(reader.GetOrdinal(@"event_sender"))) {
evt.Sender = new BasicUser {
UserId = reader.GetInt64(@"event_sender"),
Username = reader.GetString(@"event_sender_name"),
@ -175,7 +175,7 @@ namespace SharpChat {
}
public static IEnumerable<IChatEvent> GetEvents(IPacketTarget target, int amount, int offset) {
List<IChatEvent> events = new List<IChatEvent>();
List<IChatEvent> events = new();
try {
using MySqlDataReader reader = RunQuery(
@ -192,9 +192,9 @@ namespace SharpChat {
new MySqlParameter(@"offset", offset)
);
while (reader.Read()) {
while(reader.Read()) {
IChatEvent evt = ReadEvent(reader, target);
if (evt != null)
if(evt != null)
events.Add(evt);
}
} catch(MySqlException ex) {
@ -215,9 +215,9 @@ namespace SharpChat {
new MySqlParameter(@"id", seqId)
);
while (reader.Read()) {
while(reader.Read()) {
IChatEvent evt = ReadEvent(reader);
if (evt != null)
if(evt != null)
return evt;
}
} catch(MySqlException ex) {

View file

@ -8,7 +8,7 @@ namespace SharpChat {
@"SELECT COUNT(*) FROM `sqc_migrations` WHERE `migration_name` = @name",
new MySqlParameter(@"name", name)
) > 0;
if (!done) {
if(!done) {
Logger.Write($@"Running migration '{name}'...");
action();
RunCommand(

View file

@ -1,23 +1,22 @@
using System;
using System.IO;
using System.IO;
using System.Security.Cryptography;
using System.Text;
namespace SharpChat {
public static class Extensions {
public static string GetSignedHash(this string str, string key = null)
=> Encoding.UTF8.GetBytes(str).GetSignedHash(key);
public static string GetSignedHash(this string str, string key = null) {
return Encoding.UTF8.GetBytes(str).GetSignedHash(key);
}
public static string GetSignedHash(this byte[] bytes, string key = null) {
if (key == null)
key = File.Exists(@"login_key.txt") ? File.ReadAllText(@"login_key.txt") : @"woomy";
key ??= File.Exists(@"login_key.txt") ? File.ReadAllText(@"login_key.txt") : @"woomy";
StringBuilder sb = new StringBuilder();
StringBuilder sb = new();
using (HMACSHA256 algo = new HMACSHA256(Encoding.UTF8.GetBytes(key))) {
using(HMACSHA256 algo = new(Encoding.UTF8.GetBytes(key))) {
byte[] hash = algo.ComputeHash(bytes);
foreach (byte b in hash)
foreach(byte b in hash)
sb.AppendFormat(@"{0:x2}", b);
}
@ -26,7 +25,7 @@ namespace SharpChat {
public static string GetIdString(this byte[] buffer) {
const string id_chars = @"abcdefghijklmnopqrstuvwxyz0123456789-_ABCDEFGHIJKLMNOPQRSTUVWXYZ";
StringBuilder sb = new StringBuilder();
StringBuilder sb = new();
foreach(byte b in buffer)
sb.Append(id_chars[b % id_chars.Length]);
return sb.ToString();

View file

@ -19,8 +19,9 @@ namespace SharpChat.Flashii {
public string Hash
=> string.Join(@"#", UserId, Token, IPAddress).GetSignedHash();
public byte[] GetJSON()
=> JsonSerializer.SerializeToUtf8Bytes(this);
public byte[] GetJSON() {
return JsonSerializer.SerializeToUtf8Bytes(this);
}
}
public class FlashiiAuth {
@ -55,7 +56,7 @@ namespace SharpChat.Flashii {
throw new ArgumentNullException(nameof(authRequest));
#if DEBUG
if (authRequest.UserId >= 10000)
if(authRequest.UserId >= 10000)
return new FlashiiAuth {
Success = true,
UserId = authRequest.UserId,

View file

@ -4,25 +4,31 @@ using System.Text;
namespace SharpChat {
public static class Logger {
public static void Write(string str)
=> Console.WriteLine(string.Format(@"[{1}] {0}", str, DateTime.Now));
public static void Write(string str) {
Console.WriteLine(string.Format(@"[{1}] {0}", str, DateTime.Now));
}
public static void Write(byte[] bytes)
=> Write(Encoding.UTF8.GetString(bytes));
public static void Write(byte[] bytes) {
Write(Encoding.UTF8.GetString(bytes));
}
public static void Write(object obj)
=> Write(obj?.ToString() ?? string.Empty);
public static void Write(object obj) {
Write(obj?.ToString() ?? string.Empty);
}
[Conditional(@"DEBUG")]
public static void Debug(string str)
=> Write(str);
public static void Debug(string str) {
Write(str);
}
[Conditional(@"DEBUG")]
public static void Debug(byte[] bytes)
=> Write(bytes);
public static void Debug(byte[] bytes) {
Write(bytes);
}
[Conditional(@"DEBUG")]
public static void Debug(object obj)
=> Write(obj);
public static void Debug(object obj) {
Write(obj);
}
}
}

View file

@ -16,20 +16,20 @@ namespace SharpChat.Packet {
public AuthFailPacket(AuthFailReason reason, DateTimeOffset? expires = null) {
Reason = reason;
if (reason == AuthFailReason.Banned) {
if (!expires.HasValue)
if(reason == AuthFailReason.Banned) {
if(!expires.HasValue)
throw new ArgumentNullException(nameof(expires));
Expires = expires.Value;
}
}
public override IEnumerable<string> Pack() {
StringBuilder sb = new StringBuilder();
StringBuilder sb = new();
sb.Append('1');
sb.Append("\tn\t");
switch (Reason) {
switch(Reason) {
case AuthFailReason.AuthInvalid:
default:
sb.Append(@"authfail");
@ -42,10 +42,10 @@ namespace SharpChat.Packet {
break;
}
if (Reason == AuthFailReason.Banned) {
if(Reason == AuthFailReason.Banned) {
sb.Append('\t');
if (Expires == DateTimeOffset.MaxValue)
if(Expires == DateTimeOffset.MaxValue)
sb.Append(@"-1");
else
sb.Append(Expires.ToUnixTimeSeconds());

View file

@ -15,7 +15,7 @@ namespace SharpChat.Packet {
}
public override IEnumerable<string> Pack() {
StringBuilder sb = new StringBuilder();
StringBuilder sb = new();
sb.Append('1');
sb.Append("\ty\t");

View file

@ -12,17 +12,17 @@ namespace SharpChat.Packet {
}
public override IEnumerable<string> Pack() {
StringBuilder sb = new StringBuilder();
StringBuilder sb = new();
sb.Append('2');
sb.Append('\t');
sb.Append(DateTimeOffset.Now.ToUnixTimeSeconds());
sb.Append("\t-1\t0\fbanlist\f");
foreach (IBan ban in Bans)
foreach(IBan ban in Bans)
sb.AppendFormat(@"<a href=""javascript:void(0);"" onclick=""Chat.SendMessageWrapper('/unban '+ this.innerHTML);"">{0}</a>, ", ban);
if (Bans.Any())
if(Bans.Any())
sb.Length -= 2;
sb.Append('\t');

View file

@ -10,7 +10,7 @@ namespace SharpChat.Packet {
}
public override IEnumerable<string> Pack() {
StringBuilder sb = new StringBuilder();
StringBuilder sb = new();
sb.Append('4');
sb.Append('\t');

View file

@ -11,7 +11,7 @@ namespace SharpChat.Packet {
}
public override IEnumerable<string> Pack() {
StringBuilder sb = new StringBuilder();
StringBuilder sb = new();
sb.Append('4');
sb.Append('\t');

View file

@ -12,7 +12,7 @@ namespace SharpChat.Packet {
}
public override IEnumerable<string> Pack() {
StringBuilder sb = new StringBuilder();
StringBuilder sb = new();
sb.Append('4');
sb.Append('\t');

View file

@ -10,12 +10,12 @@ namespace SharpChat.Packet {
public ChatMessageAddPacket(IChatMessage message) : base(message?.SequenceId ?? 0) {
Message = message ?? throw new ArgumentNullException(nameof(message));
if (Message.SequenceId < 1)
if(Message.SequenceId < 1)
Message.SequenceId = SequenceId;
}
public override IEnumerable<string> Pack() {
StringBuilder sb = new StringBuilder();
StringBuilder sb = new();
sb.Append('2');
sb.Append('\t');
@ -26,7 +26,7 @@ namespace SharpChat.Packet {
sb.Append(Message.Sender?.UserId ?? -1);
sb.Append('\t');
if (Message.Flags.HasFlag(ChatMessageFlags.Action))
if(Message.Flags.HasFlag(ChatMessageFlags.Action))
sb.Append(@"<i>");
sb.Append(
@ -37,7 +37,7 @@ namespace SharpChat.Packet {
.Replace("\t", @" ")
);
if (Message.Flags.HasFlag(ChatMessageFlags.Action))
if(Message.Flags.HasFlag(ChatMessageFlags.Action))
sb.Append(@"</i>");
sb.Append('\t');

View file

@ -10,7 +10,7 @@ namespace SharpChat.Packet {
}
public override IEnumerable<string> Pack() {
StringBuilder sb = new StringBuilder();
StringBuilder sb = new();
sb.Append('6');
sb.Append('\t');

View file

@ -12,7 +12,7 @@ namespace SharpChat.Packet {
}
public override IEnumerable<string> Pack() {
StringBuilder sb = new StringBuilder();
StringBuilder sb = new();
sb.Append('7');
sb.Append('\t');
@ -20,7 +20,7 @@ namespace SharpChat.Packet {
sb.Append('\t');
sb.Append(Channels.Count());
foreach (ChatChannel channel in Channels) {
foreach(ChatChannel channel in Channels) {
sb.Append('\t');
sb.Append(channel.Pack());
}

View file

@ -23,7 +23,7 @@ namespace SharpChat.Packet {
}
public override IEnumerable<string> Pack() {
StringBuilder sb = new StringBuilder();
StringBuilder sb = new();
sb.Append('8');
sb.Append('\t');

View file

@ -16,7 +16,7 @@ namespace SharpChat.Packet {
private const string V1_CHATBOT = "-1\tChatBot\tinherit\t\t";
public override IEnumerable<string> Pack() {
StringBuilder sb = new StringBuilder();
StringBuilder sb = new();
sb.Append('7');
sb.Append('\t');
@ -25,7 +25,7 @@ namespace SharpChat.Packet {
sb.Append(Event.DateTime.ToUnixTimeSeconds());
sb.Append('\t');
switch (Event) {
switch(Event) {
case IChatMessage msg:
sb.Append(Event.Sender.Pack());
sb.Append('\t');
@ -60,7 +60,7 @@ namespace SharpChat.Packet {
sb.Append(V1_CHATBOT);
sb.Append("0\f");
switch (ude.Reason) {
switch(ude.Reason) {
case UserDisconnectReason.Flood:
sb.Append(@"flood");
break;

View file

@ -12,7 +12,7 @@ namespace SharpChat.Packet {
}
public override IEnumerable<string> Pack() {
StringBuilder sb = new StringBuilder();
StringBuilder sb = new();
sb.Append('7');
sb.Append('\t');
@ -20,7 +20,7 @@ namespace SharpChat.Packet {
sb.Append('\t');
sb.Append(Users.Count());
foreach (ChatUser user in Users) {
foreach(ChatUser user in Users) {
sb.Append('\t');
sb.Append(user.Pack());
sb.Append('\t');

View file

@ -5,7 +5,7 @@ using System.Text;
namespace SharpChat.Packet {
public class FloodWarningPacket : ServerPacket {
public override IEnumerable<string> Pack() {
StringBuilder sb = new StringBuilder();
StringBuilder sb = new();
sb.Append('2');
sb.Append('\t');

View file

@ -15,21 +15,21 @@ namespace SharpChat.Packet {
public ForceDisconnectPacket(ForceDisconnectReason reason, DateTimeOffset? expires = null) {
Reason = reason;
if (reason == ForceDisconnectReason.Banned) {
if (!expires.HasValue)
if(reason == ForceDisconnectReason.Banned) {
if(!expires.HasValue)
throw new ArgumentNullException(nameof(expires));
Expires = expires.Value;
}
}
public override IEnumerable<string> Pack() {
StringBuilder sb = new StringBuilder();
StringBuilder sb = new();
sb.Append('9');
sb.Append('\t');
sb.Append((int)Reason);
if (Reason == ForceDisconnectReason.Banned) {
if(Reason == ForceDisconnectReason.Banned) {
sb.Append('\t');
sb.Append(Expires.ToUnixTimeSeconds());
}

View file

@ -20,9 +20,9 @@ namespace SharpChat.Packet {
}
public override IEnumerable<string> Pack() {
StringBuilder sb = new StringBuilder();
StringBuilder sb = new();
if (StringId == LCR.WELCOME) {
if(StringId == LCR.WELCOME) {
sb.Append('7');
sb.Append('\t');
sb.Append('1');
@ -40,15 +40,15 @@ namespace SharpChat.Packet {
sb.Append('\f');
sb.Append(StringId == LCR.WELCOME ? LCR.BROADCAST : StringId);
if (Arguments?.Any() == true)
foreach (object arg in Arguments) {
if(Arguments?.Any() == true)
foreach(object arg in Arguments) {
sb.Append('\f');
sb.Append(arg);
}
sb.Append('\t');
if (StringId == LCR.WELCOME) {
if(StringId == LCR.WELCOME) {
sb.Append(StringId);
sb.Append("\t0");
} else

View file

@ -11,7 +11,7 @@ namespace SharpChat.Packet {
}
public override IEnumerable<string> Pack() {
StringBuilder sb = new StringBuilder();
StringBuilder sb = new();
sb.Append('0');
sb.Append('\t');

View file

@ -11,7 +11,7 @@ namespace SharpChat.Packet {
}
public override IEnumerable<string> Pack() {
StringBuilder sb = new StringBuilder();
StringBuilder sb = new();
sb.Append('5');
sb.Append('\t');

View file

@ -11,7 +11,7 @@ namespace SharpChat.Packet {
}
public override IEnumerable<string> Pack() {
StringBuilder sb = new StringBuilder();
StringBuilder sb = new();
sb.Append('5');
sb.Append('\t');

View file

@ -11,7 +11,7 @@ namespace SharpChat.Packet {
}
public override IEnumerable<string> Pack() {
StringBuilder sb = new StringBuilder();
StringBuilder sb = new();
sb.Append('5');
sb.Append('\t');

View file

@ -13,7 +13,7 @@ namespace SharpChat.Packet {
}
public override IEnumerable<string> Pack() {
StringBuilder sb = new StringBuilder();
StringBuilder sb = new();
sb.Append('1');
sb.Append('\t');

View file

@ -22,7 +22,7 @@ namespace SharpChat.Packet {
}
public override IEnumerable<string> Pack() {
StringBuilder sb = new StringBuilder();
StringBuilder sb = new();
sb.Append('3');
sb.Append('\t');
@ -31,7 +31,7 @@ namespace SharpChat.Packet {
sb.Append(User.DisplayName);
sb.Append('\t');
switch (Reason) {
switch(Reason) {
case UserDisconnectReason.Leave:
default:
sb.Append(@"leave");

View file

@ -13,11 +13,11 @@ namespace SharpChat.Packet {
}
public override IEnumerable<string> Pack() {
StringBuilder sb = new StringBuilder();
StringBuilder sb = new();
bool isSilent = string.IsNullOrEmpty(PreviousName);
if (!isSilent) {
if(!isSilent) {
sb.Append('2');
sb.Append('\t');
sb.Append(DateTimeOffset.Now.ToUnixTimeSeconds());

View file

@ -3,22 +3,22 @@ using System.Security.Cryptography;
namespace SharpChat {
public static class RNG {
private static object Lock { get; } = new object();
private static Random NormalRandom { get; } = new Random();
private static object Lock { get; } = new();
private static Random NormalRandom { get; } = new();
private static RandomNumberGenerator SecureRandom { get; } = RandomNumberGenerator.Create();
public static int Next() {
lock (Lock)
lock(Lock)
return NormalRandom.Next();
}
public static int Next(int max) {
lock (Lock)
lock(Lock)
return NormalRandom.Next(max);
}
public static int Next(int min, int max) {
lock (Lock)
lock(Lock)
return NormalRandom.Next(min, max);
}

View file

@ -21,7 +21,7 @@ namespace SharpChat {
private Action<IWebSocketConnection> _config;
public SharpChatWebSocketServer(string location, bool supportDualStack = true) {
Uri uri = new Uri(location);
Uri uri = new(location);
Port = uri.Port;
Location = location;
@ -29,15 +29,15 @@ namespace SharpChat {
_locationIP = ParseIPAddress(uri);
_scheme = uri.Scheme;
Socket socket = new Socket(_locationIP.AddressFamily, SocketType.Stream, ProtocolType.IP);
Socket socket = new(_locationIP.AddressFamily, SocketType.Stream, ProtocolType.IP);
socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, 1);
if (SupportDualStack && Type.GetType(@"Mono.Runtime") == null && RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) {
if(SupportDualStack && Type.GetType(@"Mono.Runtime") == null && RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) {
socket.SetSocketOption(SocketOptionLevel.IPv6, SocketOptionName.IPv6Only, false);
}
ListenerSocket = new SocketWrapper(socket);
SupportedSubProtocols = new string[0];
SupportedSubProtocols = Array.Empty<string>();
}
public ISocket ListenerSocket { get; set; }
@ -55,37 +55,38 @@ namespace SharpChat {
public void Dispose() {
ListenerSocket.Dispose();
GC.SuppressFinalize(this);
}
private IPAddress ParseIPAddress(Uri uri) {
private static IPAddress ParseIPAddress(Uri uri) {
string ipStr = uri.Host;
if (ipStr == "0.0.0.0") {
if(ipStr == "0.0.0.0") {
return IPAddress.Any;
} else if (ipStr == "[0000:0000:0000:0000:0000:0000:0000:0000]") {
} else if(ipStr == "[0000:0000:0000:0000:0000:0000:0000:0000]") {
return IPAddress.IPv6Any;
} else {
try {
return IPAddress.Parse(ipStr);
} catch (Exception ex) {
} catch(Exception ex) {
throw new FormatException("Failed to parse the IP address part of the location. Please make sure you specify a valid IP address. Use 0.0.0.0 or [::] to listen on all interfaces.", ex);
}
}
}
public void Start(Action<IWebSocketConnection> config) {
IPEndPoint ipLocal = new IPEndPoint(_locationIP, Port);
IPEndPoint ipLocal = new(_locationIP, Port);
ListenerSocket.Bind(ipLocal);
ListenerSocket.Listen(100);
Port = ((IPEndPoint)ListenerSocket.LocalEndPoint).Port;
FleckLog.Info(string.Format("Server started at {0} (actual port {1})", Location, Port));
if (_scheme == "wss") {
if (Certificate == null) {
if(_scheme == "wss") {
if(Certificate == null) {
FleckLog.Error("Scheme cannot be 'wss' without a Certificate");
return;
}
if (EnabledSslProtocols == SslProtocols.None) {
if(EnabledSslProtocols == SslProtocols.None) {
EnabledSslProtocols = SslProtocols.Tls;
FleckLog.Debug("Using default TLS 1.0 security protocol.");
}
@ -97,16 +98,16 @@ namespace SharpChat {
private void ListenForClients() {
ListenerSocket.Accept(OnClientConnect, e => {
FleckLog.Error("Listener socket is closed", e);
if (RestartAfterListenError) {
if(RestartAfterListenError) {
FleckLog.Info("Listener socket restarting");
try {
ListenerSocket.Dispose();
Socket socket = new Socket(_locationIP.AddressFamily, SocketType.Stream, ProtocolType.IP);
Socket socket = new(_locationIP.AddressFamily, SocketType.Stream, ProtocolType.IP);
socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, 1);
ListenerSocket = new SocketWrapper(socket);
Start(_config);
FleckLog.Info("Listener socket restarted");
} catch (Exception ex) {
} catch(Exception ex) {
FleckLog.Error("Listener could not be restarted", ex);
}
}
@ -114,7 +115,7 @@ namespace SharpChat {
}
private void OnClientConnect(ISocket clientSocket) {
if (clientSocket == null) return; // socket closed
if(clientSocket == null) return; // socket closed
FleckLog.Debug(string.Format("Client connected from {0}:{1}", clientSocket.RemoteIpAddress, clientSocket.RemotePort.ToString()));
ListenForClients();
@ -151,7 +152,7 @@ namespace SharpChat {
},
s => SubProtocolNegotiator.Negotiate(SupportedSubProtocols, s));
if (IsSecure) {
if(IsSecure) {
FleckLog.Debug("Authenticating Secure Connection");
clientSocket
.Authenticate(Certificate,

View file

@ -4,7 +4,7 @@ using System.Linq;
namespace SharpChat {
public class UserManager : IDisposable {
private readonly List<ChatUser> Users = new List<ChatUser>();
private readonly List<ChatUser> Users = new();
public readonly ChatContext Context;
@ -15,7 +15,7 @@ namespace SharpChat {
}
public void Add(ChatUser user) {
if (user == null)
if(user == null)
throw new ArgumentNullException(nameof(user));
lock(Users)
@ -24,7 +24,7 @@ namespace SharpChat {
}
public void Remove(ChatUser user) {
if (user == null)
if(user == null)
return;
lock(Users)
@ -32,10 +32,10 @@ namespace SharpChat {
}
public bool Contains(ChatUser user) {
if (user == null)
if(user == null)
return false;
lock (Users)
lock(Users)
return Users.Contains(user) || Users.Any(x => x.UserId == user.UserId || x.Username.ToLowerInvariant() == user.Username.ToLowerInvariant());
}
@ -45,7 +45,7 @@ namespace SharpChat {
}
public ChatUser Get(string username, bool includeNickName = true, bool includeDisplayName = true) {
if (string.IsNullOrWhiteSpace(username))
if(string.IsNullOrWhiteSpace(username))
return null;
username = username.ToLowerInvariant();
@ -56,35 +56,35 @@ namespace SharpChat {
}
public IEnumerable<ChatUser> OfHierarchy(int hierarchy) {
lock (Users)
lock(Users)
return Users.Where(u => u.Rank >= hierarchy).ToList();
}
public IEnumerable<ChatUser> WithActiveConnections() {
lock (Users)
lock(Users)
return Users.Where(u => u.HasSessions).ToList();
}
public IEnumerable<ChatUser> All() {
lock (Users)
lock(Users)
return Users.ToList();
}
~UserManager()
=> Dispose(false);
~UserManager() {
DoDispose();
}
public void Dispose()
=> Dispose(true);
public void Dispose() {
DoDispose();
GC.SuppressFinalize(this);
}
private void Dispose(bool disposing) {
if (IsDisposed)
private void DoDispose() {
if(IsDisposed)
return;
IsDisposed = true;
Users.Clear();
if (disposing)
GC.SuppressFinalize(this);
}
}
}