try a queue approach
This commit is contained in:
		| @@ -30,8 +30,9 @@ namespace MareSynchronosServer.Discord | ||||
|         DiscordSocketClient discordClient; | ||||
|         ConcurrentDictionary<ulong, string> DiscordLodestoneMapping = new(); | ||||
|         private Timer _timer; | ||||
|         private Timer _queueTimer; | ||||
|         private readonly string[] LodestoneServers = new[] { "eu", "na", "jp", "fr", "de" }; | ||||
|         private DateTime lastVerifyCall = DateTime.Now; | ||||
|         private ConcurrentQueue<(Func<Task<Embed>>, SocketUser)> verificationQueue; | ||||
|         public DiscordBot(IServiceProvider services, IConfiguration configuration, ILogger<DiscordBot> logger) | ||||
|         { | ||||
|             this.services = services; | ||||
| @@ -52,12 +53,6 @@ namespace MareSynchronosServer.Discord | ||||
|         { | ||||
|             if (arg.Data.Name == "register") | ||||
|             { | ||||
|                 if (DiscordLodestoneMapping.Count > 10) | ||||
|                 { | ||||
|                     await arg.RespondAsync("The bot registrations are currently overloaded. Please wait a few minutes and try again.", ephemeral: true); | ||||
|                     return; | ||||
|                 } | ||||
|  | ||||
|                 if (arg.Data.Options.FirstOrDefault(f => f.Name == "overwrite_old_account") != null) | ||||
|                 { | ||||
|                     await DeletePreviousUserAccount(arg.User.Id); | ||||
| @@ -71,15 +66,17 @@ namespace MareSynchronosServer.Discord | ||||
|             } | ||||
|             else if (arg.Data.Name == "verify") | ||||
|             { | ||||
|                 if (lastVerifyCall > DateTime.Now.Subtract(TimeSpan.FromSeconds(5))) | ||||
|                 EmbedBuilder eb = new EmbedBuilder(); | ||||
|                 if (!DiscordLodestoneMapping.ContainsKey(arg.User.Id)) | ||||
|                 { | ||||
|                     await arg.RespondAsync("The verification is a rate limited process. Under heavy load it might take a while until you get your turn. Please wait a few seconds and try again."); | ||||
|                     eb.WithTitle("Cannot verify registration"); | ||||
|                     eb.WithDescription("You need to **/register** first before you can **/verify**"); | ||||
|                     await arg.RespondAsync(embeds: new[] { eb.Build() }, ephemeral: true); | ||||
|                 } | ||||
|                 else | ||||
|                 { | ||||
|                     lastVerifyCall = DateTime.Now; | ||||
|                     Embed response = await HandleVerifyAsync(arg.User.Id); | ||||
|                     await arg.RespondAsync(embeds: new[] { response }, ephemeral: true); | ||||
|                     await arg.RespondAsync("The verification is a rate limited process. Under heavy load it might take a while until you get your secret key reply. The bot will get back to you as soon as it can.", ephemeral: true); | ||||
|                     verificationQueue.Enqueue((async () => await HandleVerifyAsync(arg.User.Id), arg.User)); | ||||
|                 } | ||||
|             } | ||||
|             else | ||||
| @@ -115,13 +112,7 @@ namespace MareSynchronosServer.Discord | ||||
|         private async Task<Embed> HandleVerifyAsync(ulong id) | ||||
|         { | ||||
|             var embedBuilder = new EmbedBuilder(); | ||||
|             if (!DiscordLodestoneMapping.ContainsKey(id)) | ||||
|             { | ||||
|                 embedBuilder.WithTitle("Cannot verify registration"); | ||||
|                 embedBuilder.WithDescription("You need to **/register** first before you can **/verify**"); | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|  | ||||
|             using var scope = services.CreateScope(); | ||||
|             var req = new HttpClient(); | ||||
|             using var db = scope.ServiceProvider.GetService<MareDbContext>(); | ||||
| @@ -131,11 +122,7 @@ namespace MareSynchronosServer.Discord | ||||
|             { | ||||
|                 Random rand = new(); | ||||
|                 var randomServer = LodestoneServers[rand.Next(LodestoneServers.Length)]; | ||||
|                     CancellationTokenSource cts = new CancellationTokenSource(); | ||||
|                     cts.CancelAfter(TimeSpan.FromSeconds(2)); | ||||
|                     try | ||||
|                     { | ||||
|                         var response = await req.GetAsync($"https://{randomServer}.finalfantasyxiv.com/lodestone/character/{DiscordLodestoneMapping[id]}", cts.Token); | ||||
|                 var response = await req.GetAsync($"https://{randomServer}.finalfantasyxiv.com/lodestone/character/{DiscordLodestoneMapping[id]}"); | ||||
|                 if (response.IsSuccessStatusCode) | ||||
|                 { | ||||
|                     var content = await response.Content.ReadAsStringAsync(); | ||||
| @@ -201,15 +188,9 @@ namespace MareSynchronosServer.Discord | ||||
|                     { | ||||
|                         embedBuilder.WithTitle("Failed to verify your character"); | ||||
|                         embedBuilder.WithDescription("Did not find requested authentication key on your profile. Make sure you have saved *twice*, then do **/verify** again."); | ||||
|                             } | ||||
|                         } | ||||
|                     } | ||||
|                     catch | ||||
|                     { | ||||
|                         embedBuilder.WithTitle("Failed to get response from Lodestone"); | ||||
|                         embedBuilder.WithDescription("Wait a few seconds and try again."); | ||||
|                         lodestoneAuth.StartedAt = DateTime.UtcNow; | ||||
|                     } | ||||
|                 } | ||||
|  | ||||
|                 await db.SaveChangesAsync(); | ||||
|             } | ||||
| @@ -219,7 +200,6 @@ namespace MareSynchronosServer.Discord | ||||
|                 embedBuilder.WithDescription("Start again with **/register**"); | ||||
|                 DiscordLodestoneMapping.TryRemove(id, out _); | ||||
|             } | ||||
|             } | ||||
|  | ||||
|             return embedBuilder.Build(); | ||||
|         } | ||||
| @@ -360,6 +340,7 @@ namespace MareSynchronosServer.Discord | ||||
|                 discordClient.Disconnected += DiscordClient_Disconnected; | ||||
|  | ||||
|                 _timer = new Timer(UpdateStatus, null, TimeSpan.Zero, TimeSpan.FromSeconds(15)); | ||||
|                 _queueTimer = new Timer(ProcessQueue, null, TimeSpan.Zero, TimeSpan.FromSeconds(5)); | ||||
|             } | ||||
|         } | ||||
|  | ||||
| @@ -371,6 +352,22 @@ namespace MareSynchronosServer.Discord | ||||
|             await discordClient.StartAsync(); | ||||
|         } | ||||
|  | ||||
|         private void ProcessQueue(object state) | ||||
|         { | ||||
|             if (verificationQueue.TryDequeue(out var queueitem)) | ||||
|             { | ||||
|                 var runningTask = queueitem.Item1.Invoke(); | ||||
|                 while (!runningTask.IsCompleted) | ||||
|                 { | ||||
|                     Thread.Sleep(250); | ||||
|                 } | ||||
|  | ||||
|                 var dataEmbed = runningTask.Result; | ||||
|                 queueitem.Item2.SendMessageAsync(embed: dataEmbed); | ||||
|                 logger.LogInformation("Sent login information to user"); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         private void UpdateStatus(object state) | ||||
|         { | ||||
|             using var scope = services.CreateScope(); | ||||
| @@ -384,6 +381,7 @@ namespace MareSynchronosServer.Discord | ||||
|         public async Task StopAsync(CancellationToken cancellationToken) | ||||
|         { | ||||
|             _timer?.Change(Timeout.Infinite, 0); | ||||
|             _queueTimer?.Change(Timeout.Infinite, 0); | ||||
|  | ||||
|             await discordClient.LogoutAsync(); | ||||
|             await discordClient.StopAsync(); | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Stanley Dimant
					Stanley Dimant