sharp-chat/SharpChat.Protocol.SockChat/PacketHandlers/MessageSendPacketHandler.cs

114 lines
4.7 KiB
C#

using SharpChat.Channels;
using SharpChat.Events;
using SharpChat.Messages;
using SharpChat.Protocol.SockChat.Commands;
using SharpChat.Protocol.SockChat.Packets;
using SharpChat.Sessions;
using SharpChat.Users;
using System;
using System.Collections.Generic;
using System.Linq;
namespace SharpChat.Protocol.SockChat.PacketHandlers {
public class MessageSendPacketHandler : IPacketHandler {
public ClientPacketId PacketId => ClientPacketId.MessageSend;
private IEventDispatcher Dispatcher { get; }
private MessageManager Messages { get; }
private UserManager Users { get; }
private ChannelManager Channels { get; }
private ChannelUserRelations ChannelUsers { get; }
private ChatBot Bot { get; }
private IEnumerable<ICommand> Commands { get; }
public MessageSendPacketHandler(
UserManager users,
ChannelManager channels,
ChannelUserRelations channelUsers,
MessageManager messages,
ChatBot bot,
IEnumerable<ICommand> commands
) {
Users = users ?? throw new ArgumentNullException(nameof(users));
Channels = channels ?? throw new ArgumentNullException(nameof(channels));
ChannelUsers = channelUsers ?? throw new ArgumentNullException(nameof(channelUsers));
Messages = messages ?? throw new ArgumentNullException(nameof(messages));
Bot = bot ?? throw new ArgumentNullException(nameof(bot));
Commands = commands ?? throw new ArgumentNullException(nameof(commands));
}
public void HandlePacket(PacketHandlerContext ctx) {
if(ctx.Args.Count() < 3 || !ctx.HasUser || !ctx.User.Can(UserPermissions.SendMessage))
return;
if(!long.TryParse(ctx.Args.ElementAtOrDefault(1), out long userId) || ctx.User.UserId != userId)
return;
// No longer concats everything after index 1 with \t, no previous implementation did that either
string text = ctx.Args.ElementAtOrDefault(2);
if(string.IsNullOrWhiteSpace(text))
return;
string channelName = ctx.Args.ElementAtOrDefault(3)?.ToLowerInvariant();
if(string.IsNullOrWhiteSpace(channelName))
ChannelContinue(ctx, ctx.Connection.LastChannel, text); // this should grab from the user, not the context wtf
else
Channels.GetChannelByName(channelName, channel => ChannelContinue(ctx, channel, text)); // this also doesn't check if we're actually in the channel
}
private void ChannelContinue(PacketHandlerContext ctx, IChannel channel, string text) {
if(channel == null
// || !ChannelUsers.HasUser(channel, ctx.User) look below
// || (ctx.User.IsSilenced && !ctx.User.Can(UserPermissions.SilenceUser)) TODO: readd silencing
)
return;
ChannelUsers.HasSession(channel, ctx.Session, hasSession => {
if(!hasSession)
return;
if(ctx.User.Status != UserStatus.Online) {
Users.Update(ctx.User, status: UserStatus.Online);
// ChannelUsers?
//channel.SendPacket(new UserUpdatePacket(ctx.User));
}
// there's a very miniscule chance that this will return a different value on second read
int maxLength = Messages.TextMaxLength;
if(text.Length > maxLength)
text = text.Substring(0, maxLength);
text = text.Trim();
#if DEBUG
Logger.Write($@"<{ctx.Session.SessionId} {ctx.User.UserName}> {text}");
#endif
bool handled = false;
if(text[0] == '/')
handled = HandleCommand(text, ctx.User, channel, ctx.Session, ctx.Connection);
if(!handled)
Messages.Create(ctx.Session, channel, text);
});
}
public bool HandleCommand(string message, ILocalUser user, IChannel channel, ISession session, SockChatConnection connection) {
string[] parts = message[1..].Split(' ');
string commandName = parts[0].CleanCommandName();
for(int i = 1; i < parts.Length; i++)
parts[i] = parts[i].CleanTextForCommand();
ICommand command = Commands.FirstOrDefault(x => x.IsCommandMatch(commandName, parts));
if(command == null) {
connection.SendPacket(new CommandNotFoundErrorPacket(Bot, commandName));
return true;
}
return command.DispatchCommand(new CommandContext(parts, user, channel, session, connection));
}
}
}