public static async void EnqueueLogProcessing(DiscordClient client, DiscordChannel channel, DiscordMessage message, DiscordMember requester = null, bool checkExternalLinks = false) { try { if (!QueueLimiter.Wait(0)) { await channel.SendMessageAsync("Log processing is rate limited, try again a bit later").ConfigureAwait(false); return; } bool parsedLog = false; var startTime = Stopwatch.StartNew(); DiscordMessage botMsg = null; try { var possibleHandlers = sourceHandlers.Select(h => h.FindHandlerAsync(message, archiveHandlers).ConfigureAwait(false).GetAwaiter().GetResult()).ToList(); var source = possibleHandlers.FirstOrDefault(h => h.source != null).source; var fail = possibleHandlers.FirstOrDefault(h => !string.IsNullOrEmpty(h.failReason)).failReason; if (source != null) { Config.Log.Debug($">>>>>>> {message.Id % 100} Parsing log '{source.FileName}' from {message.Author.Username}#{message.Author.Discriminator} ({message.Author.Id}) using {source.GetType().Name} ({source.SourceFileSize} bytes)..."); var analyzingProgressEmbed = GetAnalyzingMsgEmbed(client); botMsg = await channel.SendMessageAsync(embed : analyzingProgressEmbed.AddAuthor(client, message, source)).ConfigureAwait(false); parsedLog = true; LogParseState result = null; using (var timeout = new CancellationTokenSource(Config.LogParsingTimeout)) { using var combinedTokenSource = CancellationTokenSource.CreateLinkedTokenSource(timeout.Token, Config.Cts.Token); var tries = 0; do { result = await ParseLogAsync( source, async() => botMsg = await botMsg.UpdateOrCreateMessageAsync(channel, embed : analyzingProgressEmbed.AddAuthor(client, message, source)).ConfigureAwait(false), combinedTokenSource.Token ).ConfigureAwait(false); tries++; } while (result == null && !combinedTokenSource.IsCancellationRequested && tries < 3); } if (result == null) { botMsg = await botMsg.UpdateOrCreateMessageAsync(channel, embed : new DiscordEmbedBuilder { Description = "Log analysis failed, most likely cause is a truncated/invalid log.\n" + "Please run the game again and re-upload a new copy.", Color = Config.Colors.LogResultFailed, } .AddAuthor(client, message, source) .Build() ).ConfigureAwait(false); } else { result.ParsingTime = startTime.Elapsed; try { if (result.Error == LogParseState.ErrorCode.PiracyDetected) { var yarr = client.GetEmoji(":piratethink:", "☠"); result.ReadBytes = 0; if (message.Author.IsWhitelisted(client, channel.Guild)) { var piracyWarning = await result.AsEmbedAsync(client, message, source).ConfigureAwait(false); piracyWarning = piracyWarning.WithDescription("Please remove the log and issue warning to the original author of the log"); botMsg = await botMsg.UpdateOrCreateMessageAsync(channel, embed : piracyWarning).ConfigureAwait(false); await client.ReportAsync(yarr + " Pirated Release (whitelisted by role)", message, result.SelectedFilter?.String, result.SelectedFilterContext, ReportSeverity.Low).ConfigureAwait(false); } else { var severity = ReportSeverity.Low; try { await message.DeleteAsync("Piracy detected in log").ConfigureAwait(false); } catch (Exception e) { severity = ReportSeverity.High; Config.Log.Warn(e, $"Unable to delete message in {channel.Name}"); } try { /* * botMsg = await botMsg.UpdateOrCreateMessageAsync(channel, * $"{message.Author.Mention}, please read carefully:", * embed: await result.AsEmbedAsync(client, message, source).ConfigureAwait(false) * ).ConfigureAwait(false); */ botMsg = await botMsg.UpdateOrCreateMessageAsync(channel, $"{message.Author.Mention}, please read carefully:\n" + "🏴☠️ **Pirated content detected** 🏴☠️\n" + "__You are being denied further support until you legally dump the game__.\n" + "Please note that the RPCS3 community and its developers do not support piracy.\n" + "Most of the issues with pirated dumps occur due to them being modified in some way " + "that prevent them from working on RPCS3.\n" + "If you need help obtaining valid working dump of the game you own, please read the quickstart guide at <https://rpcs3.net/quickstart>" ).ConfigureAwait(false); } catch (Exception e) { Config.Log.Error(e, "Failed to send piracy warning"); } try { await client.ReportAsync(yarr + " Pirated Release", message, result.SelectedFilter?.String, result.SelectedFilterContext, severity).ConfigureAwait(false); } catch (Exception e) { Config.Log.Error(e, "Failed to send piracy report"); } if (!(message.Channel.IsPrivate || (message.Channel.Name?.Contains("spam") ?? true))) { await Warnings.AddAsync(client, message, message.Author.Id, message.Author.Username, client.CurrentUser, "Pirated Release", $"{result.SelectedFilter?.String} - {result.SelectedFilterContext?.Sanitize()}"); } } } else { if (result.SelectedFilter != null) { await ContentFilter.PerformFilterActions(client, message, result.SelectedFilter, FilterAction.IssueWarning | FilterAction.SendMessage, result.SelectedFilterContext).ConfigureAwait(false); } botMsg = await botMsg.UpdateOrCreateMessageAsync(channel, requester == null?null : $"Analyzed log from {client.GetMember(channel.Guild, message.Author)?.GetUsernameWithNickname()} by request from {requester.Mention}:", embed : await result.AsEmbedAsync(client, message, source).ConfigureAwait(false) ).ConfigureAwait(false); } } catch (Exception e) { Config.Log.Error(e, "Sending log results failed"); } } return; } else if (!string.IsNullOrEmpty(fail) && ("help".Equals(channel.Name, StringComparison.InvariantCultureIgnoreCase) || LimitedToSpamChannel.IsSpamChannel(channel))) { await channel.SendMessageAsync($"{message.Author.Mention} {fail}").ConfigureAwait(false); return; } if (!"help".Equals(channel.Name, StringComparison.InvariantCultureIgnoreCase)) { return; } var potentialLogExtension = message.Attachments.Select(a => Path.GetExtension(a.FileName).ToUpperInvariant().TrimStart('.')).FirstOrDefault(); switch (potentialLogExtension) { case "TXT": { await channel.SendMessageAsync($"{message.Author.Mention} Please upload the full RPCS3.log.gz (or RPCS3.log with a zip/rar icon) file after closing the emulator instead of copying the logs from RPCS3's interface, as it doesn't contain all the required information.").ConfigureAwait(false); return; } } if (string.IsNullOrEmpty(message.Content)) { return; } var linkStart = message.Content.IndexOf("http"); if (linkStart > -1) { var link = message.Content[linkStart..].Split(linkSeparator, 2)[0]; if (link.Contains(".log", StringComparison.InvariantCultureIgnoreCase) || link.Contains("rpcs3.zip", StringComparison.CurrentCultureIgnoreCase)) { await channel.SendMessageAsync("If you intended to upload a log file please re-upload it directly to discord").ConfigureAwait(false); } }
public static async void BackgroundProcessor(MessageCreateEventArgs args) { try { var message = args.Message; if (!QueueLimiter.Wait(0)) { await args.Channel.SendMessageAsync("Log processing is rate limited, try again a bit later").ConfigureAwait(false); return; } bool parsedLog = false; var startTime = Stopwatch.StartNew(); try { foreach (var attachment in message.Attachments.Where(a => a.FileSize < Config.AttachmentSizeLimit && !a.FileName.EndsWith("tty.log", StringComparison.InvariantCultureIgnoreCase))) { foreach (var handler in handlers) { if (await handler.CanHandleAsync(attachment).ConfigureAwait(false)) { await args.Channel.TriggerTypingAsync().ConfigureAwait(false); Config.Log.Debug($">>>>>>> {message.Id % 100} Parsing log from attachment {attachment.FileName} ({attachment.FileSize})..."); parsedLog = true; LogParseState result = null; try { var pipe = new Pipe(); var fillPipeTask = handler.FillPipeAsync(attachment, pipe.Writer); result = await LogParser.ReadPipeAsync(pipe.Reader).ConfigureAwait(false); await fillPipeTask.ConfigureAwait(false); } catch (Exception e) { Config.Log.Error(e, "Log parsing failed"); } if (result == null) { await args.Channel.SendMessageAsync("Log analysis failed, most likely cause is a truncated/invalid log. Please run the game again and reupload the new copy.").ConfigureAwait(false); } else { try { if (result.Error == LogParseState.ErrorCode.PiracyDetected) { if (args.Author.IsWhitelisted(args.Client, args.Guild)) { await Task.WhenAll( args.Channel.SendMessageAsync("I see wha' ye did thar ☠"), args.Client.ReportAsync("Pirated Release (whitelisted by role)", args.Message, result.PiracyTrigger, result.PiracyContext, ReportSeverity.Low) ).ConfigureAwait(false); } else { var severity = ReportSeverity.Low; try { await message.DeleteAsync("Piracy detected in log").ConfigureAwait(false); } catch (Exception e) { severity = ReportSeverity.High; Config.Log.Warn(e, $"Unable to delete message in {args.Channel.Name}"); } await args.Channel.SendMessageAsync(embed : await result.AsEmbedAsync(args.Client, args.Message).ConfigureAwait(false)).ConfigureAwait(false); await Task.WhenAll( args.Client.ReportAsync("Pirated Release", args.Message, result.PiracyTrigger, result.PiracyContext, severity), Warnings.AddAsync(args.Client, args.Message, args.Message.Author.Id, args.Message.Author.Username, args.Client.CurrentUser, "Pirated Release", $"{message.Content.Sanitize()} - {result.PiracyTrigger}") ); } } else { await args.Channel.SendMessageAsync(embed : await result.AsEmbedAsync(args.Client, args.Message).ConfigureAwait(false)).ConfigureAwait(false); } } catch (Exception e) { Config.Log.Error(e, "Sending log results failed"); } } return; } } } if (!"help".Equals(args.Channel.Name, StringComparison.InvariantCultureIgnoreCase)) { return; } var potentialLogExtension = message.Attachments.Select(a => Path.GetExtension(a.FileName).ToUpperInvariant().TrimStart('.')).FirstOrDefault(); switch (potentialLogExtension) { case "TXT": { await args.Channel.SendMessageAsync($"{message.Author.Mention} please do not copy/paste logs from UI, they do not contain all the required information; ask if you do not know how to upload full log file").ConfigureAwait(false); return; } } if (string.IsNullOrEmpty(message.Content)) { return; } var linkStart = message.Content.IndexOf("http"); if (linkStart > -1) { var link = message.Content.Substring(linkStart).Split(linkSeparator, 2)[0]; if (link.Contains(".log", StringComparison.InvariantCultureIgnoreCase) || link.Contains("rpcs3.zip", StringComparison.CurrentCultureIgnoreCase)) { await args.Channel.SendMessageAsync("If you intended to upload a log file please re-upload it directly to discord").ConfigureAwait(false); } } } finally { QueueLimiter.Release(); if (parsedLog) { Config.Log.Debug($"<<<<<<< {message.Id % 100} Finished parsing in {startTime.Elapsed}"); } } } catch (Exception e) { Config.Log.Error(e, "Error parsing log"); } }