using SharpChat.Channels; using SharpChat.Configuration; using SharpChat.Events; using SharpChat.Snowflake; using SharpChat.Users; namespace SharpChat.C2SPacketHandlers; public class SendMessageC2SPacketHandler( RandomSnowflake randomSnowflake, CachedValue<int> maxMsgLength ) : C2SPacketHandler { private readonly CachedValue<int> MaxMessageLength = maxMsgLength ?? throw new ArgumentNullException(nameof(maxMsgLength)); private List<ClientCommand> Commands { get; } = []; public void AddCommand(ClientCommand command) { Commands.Add(command ?? throw new ArgumentNullException(nameof(command))); } public void AddCommands(IEnumerable<ClientCommand> commands) { Commands.AddRange(commands ?? throw new ArgumentNullException(nameof(commands))); } public bool IsMatch(C2SPacketHandlerContext ctx) { return ctx.CheckPacketId("2"); } public async Task Handle(C2SPacketHandlerContext ctx) { if(ctx.Session is null) return; string[] args = ctx.SplitText(3); User? user = ctx.Chat.Users.GetUser(ctx.Session.UserId); string? messageText = args.ElementAtOrDefault(2); if(user?.Permissions.HasFlag(UserPermissions.SendMessage) != true || string.IsNullOrWhiteSpace(messageText)) return; // Extra validation step, not necessary at all but enforces proper formatting in SCv1. if(!long.TryParse(args[1], out long mUserId) || user.UserId != mUserId.ToString()) return; ctx.Chat.ContextAccess.Wait(); try { Channel? channel = ctx.Chat.ChannelsUsers.GetUserLastChannel(user); if(channel is null) return; ctx.Chat.ChannelsUsers.RecordChannelUserActivity(channel, user); if(user.Status != UserStatus.Online) await ctx.Chat.UpdateUser(user, status: UserStatus.Online); int maxMsgLength = MaxMessageLength; messageText = messageText.TruncateIfTooLong(maxMsgLength, maxMsgLength * 10).Trim(); if(messageText.StartsWith('/')) { ClientCommandContext context = new(messageText, ctx.Chat, user, ctx.Session, ctx.Connection, channel); foreach(ClientCommand cmd in Commands) if(cmd.IsMatch(context)) { await cmd.Dispatch(context); return; } } await ctx.Chat.DispatchEvent(new MessageCreateEvent( randomSnowflake.Next(), channel.Name, user.UserId, user.UserName, user.Colour, user.Rank, user.NickName, user.Permissions, DateTimeOffset.Now, messageText, false, false, false )); } finally { ctx.Chat.ContextAccess.Release(); } } }