Improved user updating but also other things that were already local.
This commit is contained in:
parent
8de3ba8dbb
commit
82973f7a33
27 changed files with 264 additions and 167 deletions
|
@ -4,19 +4,35 @@ using System.Text;
|
||||||
|
|
||||||
namespace SharpChat {
|
namespace SharpChat {
|
||||||
public class ChatChannel {
|
public class ChatChannel {
|
||||||
public string Name { get; set; }
|
public string Name { get; }
|
||||||
public string Password { get; set; } = string.Empty;
|
public string Password { get; set; }
|
||||||
public bool IsTemporary { get; set; } = false;
|
public bool IsTemporary { get; set; }
|
||||||
public int Rank { get; set; } = 0;
|
public int Rank { get; set; }
|
||||||
public ChatUser Owner { get; set; } = null;
|
public long OwnerId { get; set; }
|
||||||
|
|
||||||
public bool HasPassword
|
public bool HasPassword
|
||||||
=> !string.IsNullOrWhiteSpace(Password);
|
=> !string.IsNullOrWhiteSpace(Password);
|
||||||
|
|
||||||
public ChatChannel() { }
|
public ChatChannel(
|
||||||
|
ChatUser owner,
|
||||||
|
string name,
|
||||||
|
string password = null,
|
||||||
|
bool isTemporary = false,
|
||||||
|
int rank = 0
|
||||||
|
) : this(name, password, isTemporary, rank, owner?.UserId ?? 0) {}
|
||||||
|
|
||||||
public ChatChannel(string name) {
|
public ChatChannel(
|
||||||
|
string name,
|
||||||
|
string password = null,
|
||||||
|
bool isTemporary = false,
|
||||||
|
int rank = 0,
|
||||||
|
long ownerId = 0
|
||||||
|
) {
|
||||||
Name = name;
|
Name = name;
|
||||||
|
Password = password ?? string.Empty;
|
||||||
|
IsTemporary = isTemporary;
|
||||||
|
Rank = rank;
|
||||||
|
OwnerId = ownerId;
|
||||||
}
|
}
|
||||||
|
|
||||||
public string Pack() {
|
public string Pack() {
|
||||||
|
@ -35,6 +51,12 @@ namespace SharpChat {
|
||||||
return string.Equals(name, Name, StringComparison.InvariantCultureIgnoreCase);
|
return string.Equals(name, Name, StringComparison.InvariantCultureIgnoreCase);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public bool IsOwner(ChatUser user) {
|
||||||
|
return OwnerId > 0
|
||||||
|
&& user != null
|
||||||
|
&& OwnerId == user.UserId;
|
||||||
|
}
|
||||||
|
|
||||||
public override int GetHashCode() {
|
public override int GetHashCode() {
|
||||||
return Name.GetHashCode();
|
return Name.GetHashCode();
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
namespace SharpChat {
|
using System.Diagnostics.CodeAnalysis;
|
||||||
|
|
||||||
|
namespace SharpChat {
|
||||||
public struct ChatColour {
|
public struct ChatColour {
|
||||||
public byte Red { get; }
|
public byte Red { get; }
|
||||||
public byte Green { get; }
|
public byte Green { get; }
|
||||||
|
@ -21,6 +23,21 @@
|
||||||
Inherits = false;
|
Inherits = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override bool Equals([NotNullWhen(true)] object obj) {
|
||||||
|
return obj is ChatColour colour && Equals(colour);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Equals(ChatColour other) {
|
||||||
|
return Red == other.Red
|
||||||
|
&& Green == other.Green
|
||||||
|
&& Blue == other.Blue
|
||||||
|
&& Inherits == other.Inherits;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override int GetHashCode() {
|
||||||
|
return ToMisuzu();
|
||||||
|
}
|
||||||
|
|
||||||
public override string ToString() {
|
public override string ToString() {
|
||||||
return Inherits
|
return Inherits
|
||||||
? "inherit"
|
? "inherit"
|
||||||
|
@ -50,5 +67,13 @@
|
||||||
? None
|
? None
|
||||||
: FromRawRGB(raw);
|
: FromRawRGB(raw);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static bool operator ==(ChatColour left, ChatColour right) {
|
||||||
|
return left.Equals(right);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool operator !=(ChatColour left, ChatColour right) {
|
||||||
|
return !(left == right);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,6 +19,7 @@ namespace SharpChat {
|
||||||
public IEventStorage Events { get; }
|
public IEventStorage Events { get; }
|
||||||
public HashSet<ChannelUserAssoc> ChannelUsers { get; } = new();
|
public HashSet<ChannelUserAssoc> ChannelUsers { get; } = new();
|
||||||
public Dictionary<long, RateLimiter> UserRateLimiters { get; } = new();
|
public Dictionary<long, RateLimiter> UserRateLimiters { get; } = new();
|
||||||
|
public Dictionary<long, ChatChannel> UserLastChannel { get; } = new();
|
||||||
|
|
||||||
public ChatContext(IEventStorage evtStore) {
|
public ChatContext(IEventStorage evtStore) {
|
||||||
Events = evtStore ?? throw new ArgumentNullException(nameof(evtStore));
|
Events = evtStore ?? throw new ArgumentNullException(nameof(evtStore));
|
||||||
|
@ -71,6 +72,65 @@ namespace SharpChat {
|
||||||
return Users.Where(u => ids.Contains(u.UserId)).ToArray();
|
return Users.Where(u => ids.Contains(u.UserId)).ToArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void UpdateUser(
|
||||||
|
ChatUser user,
|
||||||
|
string userName = null,
|
||||||
|
string nickName = null,
|
||||||
|
ChatColour? colour = null,
|
||||||
|
ChatUserStatus? status = null,
|
||||||
|
string statusText = null,
|
||||||
|
int? rank = null,
|
||||||
|
ChatUserPermissions? perms = null,
|
||||||
|
bool silent = false
|
||||||
|
) {
|
||||||
|
if(user == null)
|
||||||
|
throw new ArgumentNullException(nameof(user));
|
||||||
|
|
||||||
|
bool hasChanged = false;
|
||||||
|
string previousName = null;
|
||||||
|
|
||||||
|
if(userName != null && !user.UserName.Equals(userName)) {
|
||||||
|
user.UserName = userName;
|
||||||
|
hasChanged = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(nickName != null && !user.NickName.Equals(nickName)) {
|
||||||
|
if(!silent)
|
||||||
|
previousName = string.IsNullOrWhiteSpace(user.NickName) ? user.UserName : user.NickName;
|
||||||
|
|
||||||
|
user.NickName = nickName;
|
||||||
|
hasChanged = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(colour.HasValue && user.Colour != colour.Value) {
|
||||||
|
user.Colour = colour.Value;
|
||||||
|
hasChanged = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(status.HasValue && user.Status != status.Value) {
|
||||||
|
user.Status = status.Value;
|
||||||
|
hasChanged = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(statusText != null && !user.StatusText.Equals(statusText)) {
|
||||||
|
user.StatusText = statusText;
|
||||||
|
hasChanged = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(rank != null && user.Rank != rank) {
|
||||||
|
user.Rank = (int)rank;
|
||||||
|
hasChanged = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(perms.HasValue && user.Permissions != perms) {
|
||||||
|
user.Permissions = perms.Value;
|
||||||
|
hasChanged = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(hasChanged)
|
||||||
|
SendToUserChannels(user, new UserUpdatePacket(user, previousName));
|
||||||
|
}
|
||||||
|
|
||||||
public void BanUser(ChatUser user, TimeSpan duration, UserDisconnectReason reason = UserDisconnectReason.Kicked) {
|
public void BanUser(ChatUser user, TimeSpan duration, UserDisconnectReason reason = UserDisconnectReason.Kicked) {
|
||||||
if(duration > TimeSpan.Zero)
|
if(duration > TimeSpan.Zero)
|
||||||
SendTo(user, new ForceDisconnectPacket(ForceDisconnectReason.Banned, DateTimeOffset.Now + duration));
|
SendTo(user, new ForceDisconnectPacket(ForceDisconnectReason.Banned, DateTimeOffset.Now + duration));
|
||||||
|
@ -102,12 +162,13 @@ namespace SharpChat {
|
||||||
Users.Add(user);
|
Users.Add(user);
|
||||||
|
|
||||||
ChannelUsers.Add(new ChannelUserAssoc(user.UserId, chan.Name));
|
ChannelUsers.Add(new ChannelUserAssoc(user.UserId, chan.Name));
|
||||||
user.CurrentChannel = chan;
|
UserLastChannel[user.UserId] = chan;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void HandleDisconnect(ChatUser user, UserDisconnectReason reason = UserDisconnectReason.Leave) {
|
public void HandleDisconnect(ChatUser user, UserDisconnectReason reason = UserDisconnectReason.Leave) {
|
||||||
user.Status = ChatUserStatus.Offline;
|
UpdateUser(user, status: ChatUserStatus.Offline);
|
||||||
Users.Remove(user);
|
Users.Remove(user);
|
||||||
|
UserLastChannel.Remove(user.UserId);
|
||||||
|
|
||||||
ChatChannel[] channels = GetUserChannels(user);
|
ChatChannel[] channels = GetUserChannels(user);
|
||||||
|
|
||||||
|
@ -117,25 +178,25 @@ namespace SharpChat {
|
||||||
SendTo(chan, new UserDisconnectPacket(DateTimeOffset.Now, user, reason));
|
SendTo(chan, new UserDisconnectPacket(DateTimeOffset.Now, user, reason));
|
||||||
Events.AddEvent(new UserDisconnectEvent(DateTimeOffset.Now, user, chan, reason));
|
Events.AddEvent(new UserDisconnectEvent(DateTimeOffset.Now, user, chan, reason));
|
||||||
|
|
||||||
if(chan.IsTemporary && chan.Owner == user)
|
if(chan.IsTemporary && chan.IsOwner(user))
|
||||||
RemoveChannel(chan);
|
RemoveChannel(chan);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SwitchChannel(ChatUser user, ChatChannel chan, string password) {
|
public void SwitchChannel(ChatUser user, ChatChannel chan, string password) {
|
||||||
if(user.CurrentChannel == chan) {
|
if(UserLastChannel.TryGetValue(user.UserId, out ChatChannel ulc) && chan == ulc) {
|
||||||
ForceChannel(user);
|
ForceChannel(user);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!user.Can(ChatUserPermissions.JoinAnyChannel) && chan.Owner != user) {
|
if(!user.Can(ChatUserPermissions.JoinAnyChannel) && chan.IsOwner(user)) {
|
||||||
if(chan.Rank > user.Rank) {
|
if(chan.Rank > user.Rank) {
|
||||||
SendTo(user, new LegacyCommandResponse(LCR.CHANNEL_INSUFFICIENT_HIERARCHY, true, chan.Name));
|
SendTo(user, new LegacyCommandResponse(LCR.CHANNEL_INSUFFICIENT_HIERARCHY, true, chan.Name));
|
||||||
ForceChannel(user);
|
ForceChannel(user);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(chan.Password != password) {
|
if(!string.IsNullOrEmpty(chan.Password) && chan.Password != password) {
|
||||||
SendTo(user, new LegacyCommandResponse(LCR.CHANNEL_INVALID_PASSWORD, true, chan.Name));
|
SendTo(user, new LegacyCommandResponse(LCR.CHANNEL_INVALID_PASSWORD, true, chan.Name));
|
||||||
ForceChannel(user);
|
ForceChannel(user);
|
||||||
return;
|
return;
|
||||||
|
@ -149,7 +210,7 @@ namespace SharpChat {
|
||||||
if(!Channels.Contains(chan))
|
if(!Channels.Contains(chan))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
ChatChannel oldChan = user.CurrentChannel;
|
ChatChannel oldChan = UserLastChannel[user.UserId];
|
||||||
|
|
||||||
SendTo(oldChan, new UserChannelLeavePacket(user));
|
SendTo(oldChan, new UserChannelLeavePacket(user));
|
||||||
Events.AddEvent(new UserChannelLeaveEvent(DateTimeOffset.Now, user, oldChan));
|
Events.AddEvent(new UserChannelLeaveEvent(DateTimeOffset.Now, user, oldChan));
|
||||||
|
@ -166,9 +227,9 @@ namespace SharpChat {
|
||||||
|
|
||||||
ChannelUsers.Remove(new ChannelUserAssoc(user.UserId, oldChan.Name));
|
ChannelUsers.Remove(new ChannelUserAssoc(user.UserId, oldChan.Name));
|
||||||
ChannelUsers.Add(new ChannelUserAssoc(user.UserId, chan.Name));
|
ChannelUsers.Add(new ChannelUserAssoc(user.UserId, chan.Name));
|
||||||
user.CurrentChannel = chan;
|
UserLastChannel[user.UserId] = chan;
|
||||||
|
|
||||||
if(oldChan.IsTemporary && oldChan.Owner == user)
|
if(oldChan.IsTemporary && oldChan.IsOwner(user))
|
||||||
RemoveChannel(oldChan);
|
RemoveChannel(oldChan);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -204,6 +265,18 @@ namespace SharpChat {
|
||||||
conn.Send(packet);
|
conn.Send(packet);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void SendToUserChannels(ChatUser user, IServerPacket packet) {
|
||||||
|
if(user == null)
|
||||||
|
throw new ArgumentNullException(nameof(user));
|
||||||
|
if(packet == null)
|
||||||
|
throw new ArgumentNullException(nameof(packet));
|
||||||
|
|
||||||
|
IEnumerable<ChatChannel> chans = Channels.Where(c => IsInChannel(user, c));
|
||||||
|
IEnumerable<ChatConnection> conns = Connections.Where(conn => conn.IsAuthed && ChannelUsers.Any(cu => cu.UserId == conn.User.UserId && chans.Any(chan => chan.NameEquals(cu.ChannelName))));
|
||||||
|
foreach(ChatConnection conn in conns)
|
||||||
|
conn.Send(packet);
|
||||||
|
}
|
||||||
|
|
||||||
public IPAddress[] GetRemoteAddresses(ChatUser user) {
|
public IPAddress[] GetRemoteAddresses(ChatUser user) {
|
||||||
return Connections.Where(c => c.IsAlive && c.User == user).Select(c => c.RemoteAddress).Distinct().ToArray();
|
return Connections.Where(c => c.IsAlive && c.User == user).Select(c => c.RemoteAddress).Distinct().ToArray();
|
||||||
}
|
}
|
||||||
|
@ -212,26 +285,18 @@ namespace SharpChat {
|
||||||
if(user == null)
|
if(user == null)
|
||||||
throw new ArgumentNullException(nameof(user));
|
throw new ArgumentNullException(nameof(user));
|
||||||
|
|
||||||
SendTo(user, new UserChannelForceJoinPacket(chan ?? user.CurrentChannel));
|
if(chan == null && !UserLastChannel.TryGetValue(user.UserId, out chan))
|
||||||
|
throw new ArgumentException("no channel???");
|
||||||
|
|
||||||
|
SendTo(user, new UserChannelForceJoinPacket(chan));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void UpdateChannel(ChatChannel channel, string name = null, bool? temporary = null, int? hierarchy = null, string password = null) {
|
public void UpdateChannel(ChatChannel channel, bool? temporary = null, int? hierarchy = null, string password = null) {
|
||||||
if(channel == null)
|
if(channel == null)
|
||||||
throw new ArgumentNullException(nameof(channel));
|
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));
|
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(!ChatChannel.CheckName(name))
|
|
||||||
throw new ArgumentException("Name contains invalid characters.", nameof(name));
|
|
||||||
|
|
||||||
channel.Name = name;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(temporary.HasValue)
|
if(temporary.HasValue)
|
||||||
channel.IsTemporary = temporary.Value;
|
channel.IsTemporary = temporary.Value;
|
||||||
|
|
||||||
|
@ -241,12 +306,9 @@ namespace SharpChat {
|
||||||
if(password != null)
|
if(password != null)
|
||||||
channel.Password = password;
|
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
|
// TODO: 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 Users.Where(u => u.Rank >= channel.Rank)) {
|
foreach(ChatUser user in Users.Where(u => u.Rank >= channel.Rank)) {
|
||||||
SendTo(user, new ChannelUpdatePacket(prevName, channel));
|
SendTo(user, new ChannelUpdatePacket(channel.Name, channel));
|
||||||
|
|
||||||
if(nameUpdated)
|
|
||||||
ForceChannel(user);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
using SharpChat.Misuzu;
|
using System;
|
||||||
using System;
|
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
|
||||||
namespace SharpChat {
|
namespace SharpChat {
|
||||||
|
@ -8,57 +7,51 @@ namespace SharpChat {
|
||||||
public const int DEFAULT_MINIMUM_DELAY = 10000;
|
public const int DEFAULT_MINIMUM_DELAY = 10000;
|
||||||
public const int DEFAULT_RISKY_OFFSET = 5;
|
public const int DEFAULT_RISKY_OFFSET = 5;
|
||||||
|
|
||||||
private const int RANK_NO_FLOOD = 9;
|
public long UserId { get; }
|
||||||
|
public string UserName { get; set; }
|
||||||
public long UserId { get; set; }
|
|
||||||
public string Username { get; set; }
|
|
||||||
public ChatColour Colour { get; set; }
|
public ChatColour Colour { get; set; }
|
||||||
public int Rank { get; set; }
|
public int Rank { get; set; }
|
||||||
public string Nickname { get; set; }
|
|
||||||
public ChatUserPermissions Permissions { get; set; }
|
public ChatUserPermissions Permissions { get; set; }
|
||||||
public ChatUserStatus Status { get; set; } = ChatUserStatus.Online;
|
public string NickName { get; set; }
|
||||||
public string StatusMessage { get; set; }
|
public ChatUserStatus Status { get; set; }
|
||||||
|
public string StatusText { get; set; }
|
||||||
|
|
||||||
public bool HasFloodProtection
|
public string LegacyName {
|
||||||
=> Rank < RANK_NO_FLOOD;
|
|
||||||
|
|
||||||
// This needs to be a session thing
|
|
||||||
public ChatChannel CurrentChannel { get; set; }
|
|
||||||
|
|
||||||
public string DisplayName {
|
|
||||||
get {
|
get {
|
||||||
StringBuilder sb = new();
|
StringBuilder sb = new();
|
||||||
|
|
||||||
if(Status == ChatUserStatus.Away)
|
if(Status == ChatUserStatus.Away)
|
||||||
sb.AppendFormat("<{0}>_", StatusMessage[..Math.Min(StatusMessage.Length, 5)].ToUpperInvariant());
|
sb.AppendFormat("<{0}>_", StatusText[..Math.Min(StatusText.Length, 5)].ToUpperInvariant());
|
||||||
|
|
||||||
if(string.IsNullOrWhiteSpace(Nickname))
|
if(string.IsNullOrWhiteSpace(NickName))
|
||||||
sb.Append(Username);
|
sb.Append(UserName);
|
||||||
else {
|
else {
|
||||||
sb.Append('~');
|
sb.Append('~');
|
||||||
sb.Append(Nickname);
|
sb.Append(NickName);
|
||||||
}
|
}
|
||||||
|
|
||||||
return sb.ToString();
|
return sb.ToString();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public ChatUser() { }
|
public ChatUser(
|
||||||
|
long userId,
|
||||||
public ChatUser(MisuzuAuthInfo auth) {
|
string userName,
|
||||||
UserId = auth.UserId;
|
ChatColour colour,
|
||||||
ApplyAuth(auth);
|
int rank,
|
||||||
}
|
ChatUserPermissions perms,
|
||||||
|
string nickName = null,
|
||||||
public void ApplyAuth(MisuzuAuthInfo auth) {
|
ChatUserStatus status = ChatUserStatus.Online,
|
||||||
Username = auth.Username;
|
string statusText = null
|
||||||
|
) {
|
||||||
if(Status == ChatUserStatus.Offline)
|
UserId = userId;
|
||||||
Status = ChatUserStatus.Online;
|
UserName = userName ?? throw new ArgumentNullException(nameof(userName));
|
||||||
|
Colour = colour;
|
||||||
Colour = ChatColour.FromMisuzu(auth.ColourRaw);
|
Rank = rank;
|
||||||
Rank = auth.Rank;
|
Permissions = perms;
|
||||||
Permissions = auth.Permissions;
|
NickName = nickName ?? string.Empty;
|
||||||
|
Status = status;
|
||||||
|
StatusText = statusText ?? string.Empty;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool Can(ChatUserPermissions perm, bool strict = false) {
|
public bool Can(ChatUserPermissions perm, bool strict = false) {
|
||||||
|
@ -71,27 +64,29 @@ namespace SharpChat {
|
||||||
|
|
||||||
sb.Append(UserId);
|
sb.Append(UserId);
|
||||||
sb.Append('\t');
|
sb.Append('\t');
|
||||||
sb.Append(DisplayName);
|
sb.Append(LegacyName);
|
||||||
sb.Append('\t');
|
sb.Append('\t');
|
||||||
sb.Append(Colour);
|
sb.Append(Colour);
|
||||||
sb.Append('\t');
|
sb.Append('\t');
|
||||||
sb.Append(Rank);
|
sb.Append(Rank);
|
||||||
sb.Append(' ');
|
sb.Append(' ');
|
||||||
sb.Append(Can(ChatUserPermissions.KickUser) ? '1' : '0');
|
sb.Append(Can(ChatUserPermissions.KickUser) ? '1' : '0');
|
||||||
sb.Append(" 0 "); // view logs
|
sb.Append(' ');
|
||||||
|
sb.Append(Can(ChatUserPermissions.ViewLogs) ? '1' : '0');
|
||||||
|
sb.Append(' ');
|
||||||
sb.Append(Can(ChatUserPermissions.SetOwnNickname) ? '1' : '0');
|
sb.Append(Can(ChatUserPermissions.SetOwnNickname) ? '1' : '0');
|
||||||
sb.Append(' ');
|
sb.Append(' ');
|
||||||
sb.Append(Can(ChatUserPermissions.CreateChannel | ChatUserPermissions.SetChannelPermanent, true) ? 2 : (
|
sb.Append(Can(ChatUserPermissions.CreateChannel | ChatUserPermissions.SetChannelPermanent, true) ? '2' : (
|
||||||
Can(ChatUserPermissions.CreateChannel) ? 1 : 0
|
Can(ChatUserPermissions.CreateChannel) ? '1' : '0'
|
||||||
));
|
));
|
||||||
|
|
||||||
return sb.ToString();
|
return sb.ToString();
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool NameEquals(string name) {
|
public bool NameEquals(string name) {
|
||||||
return string.Equals(name, Username, StringComparison.InvariantCultureIgnoreCase)
|
return string.Equals(name, UserName, StringComparison.InvariantCultureIgnoreCase)
|
||||||
|| string.Equals(name, Nickname, StringComparison.InvariantCultureIgnoreCase)
|
|| string.Equals(name, NickName, StringComparison.InvariantCultureIgnoreCase)
|
||||||
|| string.Equals(name, DisplayName, StringComparison.InvariantCultureIgnoreCase);
|
|| string.Equals(name, LegacyName, StringComparison.InvariantCultureIgnoreCase);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override int GetHashCode() {
|
public override int GetHashCode() {
|
||||||
|
|
|
@ -21,5 +21,6 @@ namespace SharpChat {
|
||||||
EditOwnMessage = 0x00002000,
|
EditOwnMessage = 0x00002000,
|
||||||
EditAnyMessage = 0x00004000,
|
EditAnyMessage = 0x00004000,
|
||||||
SeeIPAddress = 0x00008000,
|
SeeIPAddress = 0x00008000,
|
||||||
|
ViewLogs = 0x00040000,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,9 +20,11 @@ namespace SharpChat.Commands {
|
||||||
statusText = statusText[..MAX_LENGTH].Trim();
|
statusText = statusText[..MAX_LENGTH].Trim();
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.User.Status = ChatUserStatus.Away;
|
ctx.Chat.UpdateUser(
|
||||||
ctx.User.StatusMessage = statusText;
|
ctx.User,
|
||||||
ctx.Chat.SendTo(ctx.Channel, new UserUpdatePacket(ctx.User));
|
status: ChatUserStatus.Away,
|
||||||
|
statusText: statusText
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -43,12 +43,11 @@ namespace SharpChat.Commands {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
ChatChannel createChan = new() {
|
ChatChannel createChan = new(
|
||||||
Name = createChanName,
|
ctx.User, createChanName,
|
||||||
IsTemporary = !ctx.User.Can(ChatUserPermissions.SetChannelPermanent),
|
isTemporary: !ctx.User.Can(ChatUserPermissions.SetChannelPermanent),
|
||||||
Rank = createChanHierarchy,
|
rank: createChanHierarchy
|
||||||
Owner = ctx.User,
|
);
|
||||||
};
|
|
||||||
|
|
||||||
ctx.Chat.Channels.Add(createChan);
|
ctx.Chat.Channels.Add(createChan);
|
||||||
foreach(ChatUser ccu in ctx.Chat.Users.Where(u => u.Rank >= ctx.Channel.Rank))
|
foreach(ChatUser ccu in ctx.Chat.Users.Where(u => u.Rank >= ctx.Channel.Rank))
|
||||||
|
|
|
@ -24,7 +24,7 @@ namespace SharpChat.Commands {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!ctx.User.Can(ChatUserPermissions.DeleteChannel) && delChan.Owner != ctx.User) {
|
if(!ctx.User.Can(ChatUserPermissions.DeleteChannel) && delChan.IsOwner(ctx.User)) {
|
||||||
ctx.Chat.SendTo(ctx.User, new LegacyCommandResponse(LCR.CHANNEL_DELETE_FAILED, true, delChan.Name));
|
ctx.Chat.SendTo(ctx.User, new LegacyCommandResponse(LCR.CHANNEL_DELETE_FAILED, true, delChan.Name));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,7 +36,7 @@ namespace SharpChat.Commands {
|
||||||
}
|
}
|
||||||
|
|
||||||
if(banUser == ctx.User || banUser.Rank >= ctx.User.Rank) {
|
if(banUser == ctx.User || banUser.Rank >= ctx.User.Rank) {
|
||||||
ctx.Chat.SendTo(ctx.User, new LegacyCommandResponse(LCR.KICK_NOT_ALLOWED, true, banUser.DisplayName));
|
ctx.Chat.SendTo(ctx.User, new LegacyCommandResponse(LCR.KICK_NOT_ALLOWED, true, banUser.LegacyName));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -66,7 +66,7 @@ namespace SharpChat.Commands {
|
||||||
MisuzuBanInfo fbi = await Misuzu.CheckBanAsync(userId, userIp);
|
MisuzuBanInfo fbi = await Misuzu.CheckBanAsync(userId, userIp);
|
||||||
|
|
||||||
if(fbi.IsBanned && !fbi.HasExpired) {
|
if(fbi.IsBanned && !fbi.HasExpired) {
|
||||||
ctx.Chat.SendTo(ctx.User, new LegacyCommandResponse(LCR.KICK_NOT_ALLOWED, true, banUser.DisplayName));
|
ctx.Chat.SendTo(ctx.User, new LegacyCommandResponse(LCR.KICK_NOT_ALLOWED, true, banUser.LegacyName));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -34,21 +34,20 @@ namespace SharpChat.Commands {
|
||||||
.Replace("\f", string.Empty).Replace("\t", string.Empty)
|
.Replace("\f", string.Empty).Replace("\t", string.Empty)
|
||||||
.Replace(' ', '_').Trim();
|
.Replace(' ', '_').Trim();
|
||||||
|
|
||||||
if(nickStr == targetUser.Username)
|
if(nickStr == targetUser.UserName)
|
||||||
nickStr = null;
|
nickStr = string.Empty;
|
||||||
else if(nickStr.Length > 15)
|
else if(nickStr.Length > 15)
|
||||||
nickStr = nickStr[..15];
|
nickStr = nickStr[..15];
|
||||||
else if(string.IsNullOrEmpty(nickStr))
|
else if(string.IsNullOrEmpty(nickStr))
|
||||||
nickStr = null;
|
nickStr = string.Empty;
|
||||||
|
|
||||||
if(!string.IsNullOrWhiteSpace(nickStr) && ctx.Chat.Users.Any(u => u.NameEquals(nickStr))) {
|
if(!string.IsNullOrWhiteSpace(nickStr) && ctx.Chat.Users.Any(u => u.NameEquals(nickStr))) {
|
||||||
ctx.Chat.SendTo(ctx.User, new LegacyCommandResponse(LCR.NAME_IN_USE, true, nickStr));
|
ctx.Chat.SendTo(ctx.User, new LegacyCommandResponse(LCR.NAME_IN_USE, true, nickStr));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
string previousName = targetUser == ctx.User ? (targetUser.Nickname ?? targetUser.Username) : null;
|
string previousName = targetUser == ctx.User ? (targetUser.NickName ?? targetUser.UserName) : null;
|
||||||
targetUser.Nickname = nickStr;
|
ctx.Chat.UpdateUser(targetUser, nickName: nickStr, silent: previousName == null);
|
||||||
ctx.Chat.SendTo(ctx.Channel, new UserUpdatePacket(targetUser, previousName));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,7 @@ namespace SharpChat.Commands {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Dispatch(ChatCommandContext ctx) {
|
public void Dispatch(ChatCommandContext ctx) {
|
||||||
if(!ctx.User.Can(ChatUserPermissions.SetChannelPassword) || ctx.Channel.Owner != ctx.User) {
|
if(!ctx.User.Can(ChatUserPermissions.SetChannelPassword) || ctx.Channel.IsOwner(ctx.User)) {
|
||||||
ctx.Chat.SendTo(ctx.User, new LegacyCommandResponse(LCR.COMMAND_NOT_ALLOWED, true, $"/{ctx.Name}"));
|
ctx.Chat.SendTo(ctx.User, new LegacyCommandResponse(LCR.COMMAND_NOT_ALLOWED, true, $"/{ctx.Name}"));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,7 +10,7 @@ namespace SharpChat.Commands {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Dispatch(ChatCommandContext ctx) {
|
public void Dispatch(ChatCommandContext ctx) {
|
||||||
if(!ctx.User.Can(ChatUserPermissions.SetChannelHierarchy) || ctx.Channel.Owner != ctx.User) {
|
if(!ctx.User.Can(ChatUserPermissions.SetChannelHierarchy) || ctx.Channel.IsOwner(ctx.User)) {
|
||||||
ctx.Chat.SendTo(ctx.User, new LegacyCommandResponse(LCR.COMMAND_NOT_ALLOWED, true, $"/{ctx.Name}"));
|
ctx.Chat.SendTo(ctx.User, new LegacyCommandResponse(LCR.COMMAND_NOT_ALLOWED, true, $"/{ctx.Name}"));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,7 +24,7 @@ namespace SharpChat.Commands {
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach(IPAddress ip in ctx.Chat.GetRemoteAddresses(ipUser))
|
foreach(IPAddress ip in ctx.Chat.GetRemoteAddresses(ipUser))
|
||||||
ctx.Chat.SendTo(ctx.User, new LegacyCommandResponse(LCR.IP_ADDRESS, false, ipUser.Username, ip));
|
ctx.Chat.SendTo(ctx.User, new LegacyCommandResponse(LCR.IP_ADDRESS, false, ipUser.UserName, ip));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -50,7 +50,7 @@ namespace SharpChat.Commands {
|
||||||
|
|
||||||
//silUser.SilencedUntil = silenceUntil;
|
//silUser.SilencedUntil = silenceUntil;
|
||||||
ctx.Chat.SendTo(silUser, new LegacyCommandResponse(LCR.SILENCED, false));
|
ctx.Chat.SendTo(silUser, new LegacyCommandResponse(LCR.SILENCED, false));
|
||||||
ctx.Chat.SendTo(ctx.User, new LegacyCommandResponse(LCR.TARGET_SILENCED, false, silUser.DisplayName));
|
ctx.Chat.SendTo(ctx.User, new LegacyCommandResponse(LCR.TARGET_SILENCED, false, silUser.LegacyName));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,7 +34,7 @@ namespace SharpChat.Commands {
|
||||||
|
|
||||||
//unsilUser.SilencedUntil = DateTimeOffset.MinValue;
|
//unsilUser.SilencedUntil = DateTimeOffset.MinValue;
|
||||||
ctx.Chat.SendTo(unsilUser, new LegacyCommandResponse(LCR.UNSILENCED, false));
|
ctx.Chat.SendTo(unsilUser, new LegacyCommandResponse(LCR.UNSILENCED, false));
|
||||||
ctx.Chat.SendTo(ctx.User, new LegacyCommandResponse(LCR.TARGET_UNSILENCED, false, unsilUser.DisplayName));
|
ctx.Chat.SendTo(ctx.User, new LegacyCommandResponse(LCR.TARGET_UNSILENCED, false, unsilUser.LegacyName));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -42,7 +42,7 @@ namespace SharpChat.Commands {
|
||||||
DateTime = dateTime,
|
DateTime = dateTime,
|
||||||
ChannelName = whisperChan,
|
ChannelName = whisperChan,
|
||||||
Sender = ctx.User,
|
Sender = ctx.User,
|
||||||
Text = $"{whisperUser.DisplayName} {whisperStr}",
|
Text = $"{whisperUser.LegacyName} {whisperStr}",
|
||||||
Flags = ChatMessageFlags.Private,
|
Flags = ChatMessageFlags.Private,
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,7 +20,7 @@ namespace SharpChat.Commands {
|
||||||
whoChanSB.Append(@" style=""font-weight: bold;""");
|
whoChanSB.Append(@" style=""font-weight: bold;""");
|
||||||
|
|
||||||
whoChanSB.Append('>');
|
whoChanSB.Append('>');
|
||||||
whoChanSB.Append(whoUser.DisplayName);
|
whoChanSB.Append(whoUser.LegacyName);
|
||||||
whoChanSB.Append("</a>, ");
|
whoChanSB.Append("</a>, ");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -48,7 +48,7 @@ namespace SharpChat.Commands {
|
||||||
whoChanSB.Append(@" style=""font-weight: bold;""");
|
whoChanSB.Append(@" style=""font-weight: bold;""");
|
||||||
|
|
||||||
whoChanSB.Append('>');
|
whoChanSB.Append('>');
|
||||||
whoChanSB.Append(whoUser.DisplayName);
|
whoChanSB.Append(whoUser.LegacyName);
|
||||||
whoChanSB.Append("</a>, ");
|
whoChanSB.Append("</a>, ");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -32,10 +32,10 @@ namespace SharpChat.EventStorage {
|
||||||
new MySqlParameter("flags", (byte)evt.Flags),
|
new MySqlParameter("flags", (byte)evt.Flags),
|
||||||
new MySqlParameter("data", JsonSerializer.SerializeToUtf8Bytes(evt, evt.GetType())),
|
new MySqlParameter("data", JsonSerializer.SerializeToUtf8Bytes(evt, evt.GetType())),
|
||||||
new MySqlParameter("sender", evt.Sender?.UserId < 1 ? null : (long?)evt.Sender.UserId),
|
new MySqlParameter("sender", evt.Sender?.UserId < 1 ? null : (long?)evt.Sender.UserId),
|
||||||
new MySqlParameter("sender_name", evt.Sender?.Username),
|
new MySqlParameter("sender_name", evt.Sender?.UserName),
|
||||||
new MySqlParameter("sender_colour", evt.Sender?.Colour.ToMisuzu()),
|
new MySqlParameter("sender_colour", evt.Sender?.Colour.ToMisuzu()),
|
||||||
new MySqlParameter("sender_rank", evt.Sender?.Rank),
|
new MySqlParameter("sender_rank", evt.Sender?.Rank),
|
||||||
new MySqlParameter("sender_nick", evt.Sender?.Nickname),
|
new MySqlParameter("sender_nick", evt.Sender?.NickName),
|
||||||
new MySqlParameter("sender_perms", evt.Sender?.Permissions)
|
new MySqlParameter("sender_perms", evt.Sender?.Permissions)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -72,14 +72,14 @@ namespace SharpChat.EventStorage {
|
||||||
evt.DateTime = DateTimeOffset.FromUnixTimeSeconds(reader.GetInt32("event_created"));
|
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 ChatUser {
|
evt.Sender = new ChatUser(
|
||||||
UserId = reader.GetInt64("event_sender"),
|
reader.GetInt64("event_sender"),
|
||||||
Username = reader.GetString("event_sender_name"),
|
reader.GetString("event_sender_name"),
|
||||||
Colour = ChatColour.FromMisuzu(reader.GetInt32("event_sender_colour")),
|
ChatColour.FromMisuzu(reader.GetInt32("event_sender_colour")),
|
||||||
Rank = reader.GetInt32("event_sender_rank"),
|
reader.GetInt32("event_sender_rank"),
|
||||||
Nickname = reader.IsDBNull(reader.GetOrdinal("event_sender_nick")) ? null : reader.GetString("event_sender_nick"),
|
(ChatUserPermissions)reader.GetInt32("event_sender_perms"),
|
||||||
Permissions = (ChatUserPermissions)reader.GetInt32("event_sender_perms")
|
reader.IsDBNull(reader.GetOrdinal("event_sender_nick")) ? null : reader.GetString("event_sender_nick")
|
||||||
};
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return evt;
|
return evt;
|
||||||
|
|
|
@ -13,11 +13,13 @@ namespace SharpChat.Misuzu {
|
||||||
public long UserId { get; set; }
|
public long UserId { get; set; }
|
||||||
|
|
||||||
[JsonPropertyName("username")]
|
[JsonPropertyName("username")]
|
||||||
public string Username { get; set; }
|
public string UserName { get; set; }
|
||||||
|
|
||||||
[JsonPropertyName("colour_raw")]
|
[JsonPropertyName("colour_raw")]
|
||||||
public int ColourRaw { get; set; }
|
public int ColourRaw { get; set; }
|
||||||
|
|
||||||
|
public ChatColour Colour => ChatColour.FromMisuzu(ColourRaw);
|
||||||
|
|
||||||
[JsonPropertyName("hierarchy")]
|
[JsonPropertyName("hierarchy")]
|
||||||
public int Rank { get; set; }
|
public int Rank { get; set; }
|
||||||
|
|
||||||
|
|
|
@ -41,19 +41,19 @@ namespace SharpChat.Packet {
|
||||||
case UserConnectEvent _:
|
case UserConnectEvent _:
|
||||||
sb.Append(V1_CHATBOT);
|
sb.Append(V1_CHATBOT);
|
||||||
sb.Append("0\fjoin\f");
|
sb.Append("0\fjoin\f");
|
||||||
sb.Append(Event.Sender.Username);
|
sb.Append(Event.Sender.UserName);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case UserChannelJoinEvent _:
|
case UserChannelJoinEvent _:
|
||||||
sb.Append(V1_CHATBOT);
|
sb.Append(V1_CHATBOT);
|
||||||
sb.Append("0\fjchan\f");
|
sb.Append("0\fjchan\f");
|
||||||
sb.Append(Event.Sender.Username);
|
sb.Append(Event.Sender.UserName);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case UserChannelLeaveEvent _:
|
case UserChannelLeaveEvent _:
|
||||||
sb.Append(V1_CHATBOT);
|
sb.Append(V1_CHATBOT);
|
||||||
sb.Append("0\flchan\f");
|
sb.Append("0\flchan\f");
|
||||||
sb.Append(Event.Sender.Username);
|
sb.Append(Event.Sender.UserName);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case UserDisconnectEvent ude:
|
case UserDisconnectEvent ude:
|
||||||
|
@ -77,7 +77,7 @@ namespace SharpChat.Packet {
|
||||||
}
|
}
|
||||||
|
|
||||||
sb.Append('\f');
|
sb.Append('\f');
|
||||||
sb.Append(Event.Sender.Username);
|
sb.Append(Event.Sender.UserName);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,20 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Text;
|
|
||||||
|
|
||||||
namespace SharpChat.Packet {
|
|
||||||
public class FloodWarningPacket : ServerPacket {
|
|
||||||
public override IEnumerable<string> Pack() {
|
|
||||||
StringBuilder sb = new();
|
|
||||||
|
|
||||||
sb.Append('2');
|
|
||||||
sb.Append('\t');
|
|
||||||
sb.Append(DateTimeOffset.Now.ToUnixTimeSeconds());
|
|
||||||
sb.Append("\t-1\t0\fflwarn\t");
|
|
||||||
sb.Append(SequenceId);
|
|
||||||
sb.Append("\t10010");
|
|
||||||
|
|
||||||
yield return sb.ToString();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -104,5 +104,6 @@ namespace SharpChat.Packet {
|
||||||
public const string KICK_NOT_ALLOWED = "kickna";
|
public const string KICK_NOT_ALLOWED = "kickna";
|
||||||
public const string USER_NOT_BANNED = "notban";
|
public const string USER_NOT_BANNED = "notban";
|
||||||
public const string USER_UNBANNED = "unban";
|
public const string USER_UNBANNED = "unban";
|
||||||
|
public const string FLOOD_WARN = "flwarn";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,7 +28,7 @@ namespace SharpChat.Packet {
|
||||||
sb.Append('\t');
|
sb.Append('\t');
|
||||||
sb.Append(User.UserId);
|
sb.Append(User.UserId);
|
||||||
sb.Append('\t');
|
sb.Append('\t');
|
||||||
sb.Append(User.DisplayName);
|
sb.Append(User.LegacyName);
|
||||||
sb.Append('\t');
|
sb.Append('\t');
|
||||||
|
|
||||||
switch(Reason) {
|
switch(Reason) {
|
||||||
|
|
|
@ -24,7 +24,7 @@ namespace SharpChat.Packet {
|
||||||
sb.Append("\t-1\t0\fnick\f");
|
sb.Append("\t-1\t0\fnick\f");
|
||||||
sb.Append(PreviousName);
|
sb.Append(PreviousName);
|
||||||
sb.Append('\f');
|
sb.Append('\f');
|
||||||
sb.Append(User.DisplayName);
|
sb.Append(User.LegacyName);
|
||||||
sb.Append('\t');
|
sb.Append('\t');
|
||||||
sb.Append(SequenceId);
|
sb.Append(SequenceId);
|
||||||
sb.Append("\t10010");
|
sb.Append("\t10010");
|
||||||
|
|
|
@ -103,12 +103,22 @@ namespace SharpChat.PacketHandlers {
|
||||||
ChatUser user = ctx.Chat.Users.FirstOrDefault(u => u.UserId == fai.UserId);
|
ChatUser user = ctx.Chat.Users.FirstOrDefault(u => u.UserId == fai.UserId);
|
||||||
|
|
||||||
if(user == null)
|
if(user == null)
|
||||||
user = new ChatUser(fai);
|
user = new ChatUser(
|
||||||
else {
|
fai.UserId,
|
||||||
user.ApplyAuth(fai);
|
fai.UserName,
|
||||||
if(user.CurrentChannel != null)
|
fai.Colour,
|
||||||
ctx.Chat.SendTo(user.CurrentChannel, new UserUpdatePacket(user));
|
fai.Rank,
|
||||||
}
|
fai.Permissions
|
||||||
|
);
|
||||||
|
else
|
||||||
|
ctx.Chat.UpdateUser(
|
||||||
|
user,
|
||||||
|
userName: fai.UserName,
|
||||||
|
status: ChatUserStatus.Online,
|
||||||
|
colour: fai.Colour,
|
||||||
|
rank: fai.Rank,
|
||||||
|
perms: fai.Permissions
|
||||||
|
);
|
||||||
|
|
||||||
// Enforce a maximum amount of connections per user
|
// Enforce a maximum amount of connections per user
|
||||||
if(ctx.Chat.Connections.Count(conn => conn.User == user) >= MaxConnections) {
|
if(ctx.Chat.Connections.Count(conn => conn.User == user) >= MaxConnections) {
|
||||||
|
@ -119,7 +129,7 @@ namespace SharpChat.PacketHandlers {
|
||||||
|
|
||||||
ctx.Connection.BumpPing();
|
ctx.Connection.BumpPing();
|
||||||
ctx.Connection.User = user;
|
ctx.Connection.User = user;
|
||||||
ctx.Connection.Send(new LegacyCommandResponse(LCR.WELCOME, false, $"Welcome to Flashii Chat, {user.Username}!"));
|
ctx.Connection.Send(new LegacyCommandResponse(LCR.WELCOME, false, $"Welcome to Flashii Chat, {user.UserName}!"));
|
||||||
|
|
||||||
if(File.Exists("welcome.txt")) {
|
if(File.Exists("welcome.txt")) {
|
||||||
IEnumerable<string> lines = File.ReadAllLines("welcome.txt").Where(x => !string.IsNullOrWhiteSpace(x));
|
IEnumerable<string> lines = File.ReadAllLines("welcome.txt").Where(x => !string.IsNullOrWhiteSpace(x));
|
||||||
|
|
|
@ -45,17 +45,13 @@ namespace SharpChat.PacketHandlers {
|
||||||
|
|
||||||
ctx.Chat.ContextAccess.Wait();
|
ctx.Chat.ContextAccess.Wait();
|
||||||
try {
|
try {
|
||||||
ChatChannel channel = user.CurrentChannel;
|
if(!ctx.Chat.UserLastChannel.TryGetValue(user.UserId, out ChatChannel channel)
|
||||||
|
&& !ctx.Chat.IsInChannel(user, channel)
|
||||||
if(channel == null
|
|
||||||
|| !ctx.Chat.IsInChannel(user, channel)
|
|
||||||
/*|| (user.IsSilenced && !user.Can(ChatUserPermissions.SilenceUser))*/)
|
/*|| (user.IsSilenced && !user.Can(ChatUserPermissions.SilenceUser))*/)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if(user.Status != ChatUserStatus.Online) {
|
if(user.Status != ChatUserStatus.Online)
|
||||||
user.Status = ChatUserStatus.Online;
|
ctx.Chat.UpdateUser(user, status: ChatUserStatus.Online);
|
||||||
ctx.Chat.SendTo(channel, new UserUpdatePacket(user));
|
|
||||||
}
|
|
||||||
|
|
||||||
int maxMsgLength = MaxMessageLength;
|
int maxMsgLength = MaxMessageLength;
|
||||||
if(messageText.Length > maxMsgLength)
|
if(messageText.Length > maxMsgLength)
|
||||||
|
@ -64,7 +60,7 @@ namespace SharpChat.PacketHandlers {
|
||||||
messageText = messageText.Trim();
|
messageText = messageText.Trim();
|
||||||
|
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
Logger.Write($"<{ctx.Connection.Id} {user.Username}> {messageText}");
|
Logger.Write($"<{ctx.Connection.Id} {user.UserName}> {messageText}");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
IChatMessage message = null;
|
IChatMessage message = null;
|
||||||
|
|
|
@ -17,6 +17,7 @@ namespace SharpChat {
|
||||||
public const int DEFAULT_MSG_LENGTH_MAX = 5000;
|
public const int DEFAULT_MSG_LENGTH_MAX = 5000;
|
||||||
public const int DEFAULT_MAX_CONNECTIONS = 5;
|
public const int DEFAULT_MAX_CONNECTIONS = 5;
|
||||||
public const int DEFAULT_FLOOD_KICK_LENGTH = 30;
|
public const int DEFAULT_FLOOD_KICK_LENGTH = 30;
|
||||||
|
public const int DEFAULT_FLOOD_KICK_EXEMPT_RANK = 9;
|
||||||
|
|
||||||
public IWebSocketServer Server { get; }
|
public IWebSocketServer Server { get; }
|
||||||
public ChatContext Context { get; }
|
public ChatContext Context { get; }
|
||||||
|
@ -27,6 +28,7 @@ namespace SharpChat {
|
||||||
private readonly CachedValue<int> MaxMessageLength;
|
private readonly CachedValue<int> MaxMessageLength;
|
||||||
private readonly CachedValue<int> MaxConnections;
|
private readonly CachedValue<int> MaxConnections;
|
||||||
private readonly CachedValue<int> FloodKickLength;
|
private readonly CachedValue<int> FloodKickLength;
|
||||||
|
private readonly CachedValue<int> FloodKickExemptRank;
|
||||||
|
|
||||||
private readonly List<IChatPacketHandler> GuestHandlers = new();
|
private readonly List<IChatPacketHandler> GuestHandlers = new();
|
||||||
private readonly List<IChatPacketHandler> AuthedHandlers = new();
|
private readonly List<IChatPacketHandler> AuthedHandlers = new();
|
||||||
|
@ -45,25 +47,26 @@ namespace SharpChat {
|
||||||
MaxMessageLength = config.ReadCached("msgMaxLength", DEFAULT_MSG_LENGTH_MAX);
|
MaxMessageLength = config.ReadCached("msgMaxLength", DEFAULT_MSG_LENGTH_MAX);
|
||||||
MaxConnections = config.ReadCached("connMaxCount", DEFAULT_MAX_CONNECTIONS);
|
MaxConnections = config.ReadCached("connMaxCount", DEFAULT_MAX_CONNECTIONS);
|
||||||
FloodKickLength = config.ReadCached("floodKickLength", DEFAULT_FLOOD_KICK_LENGTH);
|
FloodKickLength = config.ReadCached("floodKickLength", DEFAULT_FLOOD_KICK_LENGTH);
|
||||||
|
FloodKickExemptRank = config.ReadCached("floodKickExemptRank", DEFAULT_FLOOD_KICK_EXEMPT_RANK);
|
||||||
|
|
||||||
Context = new ChatContext(evtStore);
|
Context = new ChatContext(evtStore);
|
||||||
|
|
||||||
string[] channelNames = config.ReadValue("channels", new[] { "lounge" });
|
string[] channelNames = config.ReadValue("channels", new[] { "lounge" });
|
||||||
|
|
||||||
foreach(string channelName in channelNames) {
|
foreach(string channelName in channelNames) {
|
||||||
ChatChannel channelInfo = new(channelName);
|
|
||||||
IConfig channelCfg = config.ScopeTo($"channels:{channelName}");
|
IConfig channelCfg = config.ScopeTo($"channels:{channelName}");
|
||||||
|
|
||||||
string tmp;
|
string name = channelCfg.SafeReadValue("name", string.Empty);
|
||||||
tmp = channelCfg.SafeReadValue("name", string.Empty);
|
if(string.IsNullOrWhiteSpace(name))
|
||||||
if(!string.IsNullOrWhiteSpace(tmp))
|
name = channelName;
|
||||||
channelInfo.Name = tmp;
|
|
||||||
|
|
||||||
channelInfo.Password = channelCfg.SafeReadValue("password", string.Empty);
|
ChatChannel channelInfo = new(
|
||||||
channelInfo.Rank = channelCfg.SafeReadValue("minRank", 0);
|
name,
|
||||||
|
channelCfg.SafeReadValue("password", string.Empty),
|
||||||
|
rank: channelCfg.SafeReadValue("minRank", 0)
|
||||||
|
);
|
||||||
|
|
||||||
Context.Channels.Add(channelInfo);
|
Context.Channels.Add(channelInfo);
|
||||||
|
|
||||||
DefaultChannel ??= channelInfo;
|
DefaultChannel ??= channelInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -152,7 +155,7 @@ namespace SharpChat {
|
||||||
Context.SafeUpdate();
|
Context.SafeUpdate();
|
||||||
|
|
||||||
// this doesn't affect non-authed connections?????
|
// this doesn't affect non-authed connections?????
|
||||||
if(conn.User is not null && conn.User.HasFloodProtection) {
|
if(conn.User is not null && conn.User.Rank < FloodKickExemptRank) {
|
||||||
ChatUser banUser = null;
|
ChatUser banUser = null;
|
||||||
string banAddr = string.Empty;
|
string banAddr = string.Empty;
|
||||||
TimeSpan banDuration = TimeSpan.MinValue;
|
TimeSpan banDuration = TimeSpan.MinValue;
|
||||||
|
@ -178,7 +181,7 @@ namespace SharpChat {
|
||||||
|
|
||||||
if(banUser is not null) {
|
if(banUser is not null) {
|
||||||
if(banDuration == TimeSpan.MinValue) {
|
if(banDuration == TimeSpan.MinValue) {
|
||||||
Context.SendTo(conn.User, new FloodWarningPacket());
|
Context.SendTo(conn.User, new LegacyCommandResponse(LCR.FLOOD_WARN, false));
|
||||||
} else {
|
} else {
|
||||||
Context.BanUser(conn.User, banDuration, UserDisconnectReason.Flood);
|
Context.BanUser(conn.User, banDuration, UserDisconnectReason.Flood);
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue