Code style updates.
This commit is contained in:
parent
c9cc5ff23a
commit
4104e40843
42 changed files with 292 additions and 317 deletions
|
@ -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();
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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');
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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(@"<{0}>_", StatusMessage.Substring(0, Math.Min(StatusMessage.Length, 5)).ToUpperInvariant());
|
||||
sb.AppendFormat(@"<{0}>_", 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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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');
|
||||
|
|
|
@ -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');
|
||||
|
|
|
@ -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');
|
||||
|
|
|
@ -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');
|
||||
|
|
|
@ -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');
|
||||
|
|
|
@ -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');
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
|
|
|
@ -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');
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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');
|
||||
|
|
|
@ -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');
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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');
|
||||
|
|
|
@ -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');
|
||||
|
|
|
@ -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');
|
||||
|
|
|
@ -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');
|
||||
|
|
|
@ -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');
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue