diff --git a/src/Nullinside.Api.TwitchBot.Tests/ChatRules/AChatRuleUnitTestBase.cs b/src/Nullinside.Api.TwitchBot.Tests/ChatRules/AChatRuleUnitTestBase.cs index 50f73a9..a1c4779 100644 --- a/src/Nullinside.Api.TwitchBot.Tests/ChatRules/AChatRuleUnitTestBase.cs +++ b/src/Nullinside.Api.TwitchBot.Tests/ChatRules/AChatRuleUnitTestBase.cs @@ -25,12 +25,12 @@ public async Task TestItDoesntAlwaysFail(string goodString) { // Process the message and assert that we pass the message. var chat = new TwitchChatMessage(true, goodString, "123", "456"); - bool result = await rule.Handle("123", botProxy.Object, chat, _db); + bool result = await rule.Handle("123", botProxy.Object, chat, _db).ConfigureAwait(false); Assert.That(result, Is.True); // Process the message and assert that we pass the message. chat = new TwitchChatMessage(false, goodString, "123", "456"); - result = await rule.Handle("123", botProxy.Object, chat, _db); + result = await rule.Handle("123", botProxy.Object, chat, _db).ConfigureAwait(false); Assert.That(result, Is.True); } diff --git a/src/Nullinside.Api.TwitchBot.Tests/ChatRules/BestCheapViewersTests.cs b/src/Nullinside.Api.TwitchBot.Tests/ChatRules/BestCheapViewersTests.cs index 2b3fa89..18f3e9e 100644 --- a/src/Nullinside.Api.TwitchBot.Tests/ChatRules/BestCheapViewersTests.cs +++ b/src/Nullinside.Api.TwitchBot.Tests/ChatRules/BestCheapViewersTests.cs @@ -50,7 +50,7 @@ public async Task TestKnownStrings(string badString) { var chat = new TwitchChatMessage(true, badString, "123", "456"); // Process the message and assert that we fail the message. - bool result = await rule.Handle("123", botProxy.Object, chat, _db); + bool result = await rule.Handle("123", botProxy.Object, chat, _db).ConfigureAwait(false); Assert.That(result, Is.False); } } \ No newline at end of file diff --git a/src/Nullinside.Api.TwitchBot.Tests/ChatRules/BotsisterTests.cs b/src/Nullinside.Api.TwitchBot.Tests/ChatRules/BotsisterTests.cs index 2a1d3ad..f87c3fe 100644 --- a/src/Nullinside.Api.TwitchBot.Tests/ChatRules/BotsisterTests.cs +++ b/src/Nullinside.Api.TwitchBot.Tests/ChatRules/BotsisterTests.cs @@ -22,7 +22,7 @@ public async Task TestKnownStrings(string badString) { var chat = new TwitchChatMessage(true, badString, "123", "456"); // Process the message and assert that we fail the message. - bool result = await rule.Handle("123", botProxy.Object, chat, _db); + bool result = await rule.Handle("123", botProxy.Object, chat, _db).ConfigureAwait(false); Assert.That(result, Is.False); } } \ No newline at end of file diff --git a/src/Nullinside.Api.TwitchBot.Tests/ChatRules/DiscordTests.cs b/src/Nullinside.Api.TwitchBot.Tests/ChatRules/DiscordTests.cs index ccfe530..106a69d 100644 --- a/src/Nullinside.Api.TwitchBot.Tests/ChatRules/DiscordTests.cs +++ b/src/Nullinside.Api.TwitchBot.Tests/ChatRules/DiscordTests.cs @@ -35,7 +35,7 @@ public async Task TestKnownStrings(string badString) { var chat = new TwitchChatMessage(true, badString, "123", "456"); // Process the message and assert that we fail the message. - bool result = await rule.Handle("123", botProxy.Object, chat, _db); + bool result = await rule.Handle("123", botProxy.Object, chat, _db).ConfigureAwait(false); Assert.That(result, Is.False); } @@ -52,7 +52,7 @@ public async Task EnsureNoFalsePositives(string message) { var chat = new TwitchChatMessage(true, message, "123", "456"); // Process the message and assert that we do not fail the message. - bool result = await rule.Handle("123", botProxy.Object, chat, _db); + bool result = await rule.Handle("123", botProxy.Object, chat, _db).ConfigureAwait(false); Assert.That(result, Is.True); } } \ No newline at end of file diff --git a/src/Nullinside.Api.TwitchBot.Tests/ChatRules/DoghypeTests.cs b/src/Nullinside.Api.TwitchBot.Tests/ChatRules/DoghypeTests.cs index aa484df..a676be6 100644 --- a/src/Nullinside.Api.TwitchBot.Tests/ChatRules/DoghypeTests.cs +++ b/src/Nullinside.Api.TwitchBot.Tests/ChatRules/DoghypeTests.cs @@ -25,7 +25,7 @@ public async Task TestKnownStrings(string badString) { var chat = new TwitchChatMessage(true, badString, "123", "456"); // Process the message and assert that we fail the message. - bool result = await rule.Handle("123", botProxy.Object, chat, _db); + bool result = await rule.Handle("123", botProxy.Object, chat, _db).ConfigureAwait(false); Assert.That(result, Is.False); } } \ No newline at end of file diff --git a/src/Nullinside.Api.TwitchBot.Tests/ChatRules/NezhnaTests.cs b/src/Nullinside.Api.TwitchBot.Tests/ChatRules/NezhnaTests.cs index e95b559..ec6bbac 100644 --- a/src/Nullinside.Api.TwitchBot.Tests/ChatRules/NezhnaTests.cs +++ b/src/Nullinside.Api.TwitchBot.Tests/ChatRules/NezhnaTests.cs @@ -26,7 +26,7 @@ public async Task TestKnownStrings(string badString) { var chat = new TwitchChatMessage(true, badString, "123", "456"); // Process the message and assert that we fail the message. - bool result = await rule.Handle("123", botProxy.Object, chat, _db); + bool result = await rule.Handle("123", botProxy.Object, chat, _db).ConfigureAwait(false); Assert.That(result, Is.False); } } \ No newline at end of file diff --git a/src/Nullinside.Api.TwitchBot.Tests/ChatRules/StreamBooTests.cs b/src/Nullinside.Api.TwitchBot.Tests/ChatRules/StreamBooTests.cs index 472b219..918d6dd 100644 --- a/src/Nullinside.Api.TwitchBot.Tests/ChatRules/StreamBooTests.cs +++ b/src/Nullinside.Api.TwitchBot.Tests/ChatRules/StreamBooTests.cs @@ -25,7 +25,7 @@ public async Task TestKnownStrings(string badString) { var chat = new TwitchChatMessage(true, badString, "123", "456"); // Process the message and assert that we fail the message. - bool result = await rule.Handle("123", botProxy.Object, chat, _db); + bool result = await rule.Handle("123", botProxy.Object, chat, _db).ConfigureAwait(false); Assert.That(result, Is.False); } } \ No newline at end of file diff --git a/src/Nullinside.Api.TwitchBot.Tests/ChatRules/StreamViewersTests.cs b/src/Nullinside.Api.TwitchBot.Tests/ChatRules/StreamViewersTests.cs index fd6cea7..d0083ad 100644 --- a/src/Nullinside.Api.TwitchBot.Tests/ChatRules/StreamViewersTests.cs +++ b/src/Nullinside.Api.TwitchBot.Tests/ChatRules/StreamViewersTests.cs @@ -28,7 +28,7 @@ public async Task TestKnownStrings(string badString) { var chat = new TwitchChatMessage(true, badString, "123", "456"); // Process the message and assert that we fail the message. - bool result = await rule.Handle("123", botProxy.Object, chat, _db); + bool result = await rule.Handle("123", botProxy.Object, chat, _db).ConfigureAwait(false); Assert.That(result, Is.False); } } \ No newline at end of file diff --git a/src/Nullinside.Api.TwitchBot.Tests/Nullinside.Api.TwitchBot.Tests.csproj b/src/Nullinside.Api.TwitchBot.Tests/Nullinside.Api.TwitchBot.Tests.csproj index 9147740..f3dac08 100644 --- a/src/Nullinside.Api.TwitchBot.Tests/Nullinside.Api.TwitchBot.Tests.csproj +++ b/src/Nullinside.Api.TwitchBot.Tests/Nullinside.Api.TwitchBot.Tests.csproj @@ -15,8 +15,8 @@ all runtime; build; native; contentfiles; analyzers; buildtransitive - - + + diff --git a/src/Nullinside.Api.TwitchBot.Tests/Nullinside.Api.TwitchBot.Tests.csproj.DotSettings b/src/Nullinside.Api.TwitchBot.Tests/Nullinside.Api.TwitchBot.Tests.csproj.DotSettings new file mode 100644 index 0000000..d0d789b --- /dev/null +++ b/src/Nullinside.Api.TwitchBot.Tests/Nullinside.Api.TwitchBot.Tests.csproj.DotSettings @@ -0,0 +1,5 @@ + + Library \ No newline at end of file diff --git a/src/Nullinside.Api.TwitchBot.Tests/UnitTestBase.cs b/src/Nullinside.Api.TwitchBot.Tests/UnitTestBase.cs index d7c7159..8e0077f 100644 --- a/src/Nullinside.Api.TwitchBot.Tests/UnitTestBase.cs +++ b/src/Nullinside.Api.TwitchBot.Tests/UnitTestBase.cs @@ -28,6 +28,6 @@ public virtual void Setup() { [TearDown] public virtual async Task TearDown() { // Dispose since it has one. - await _db.DisposeAsync(); + await _db.DisposeAsync().ConfigureAwait(false); } } \ No newline at end of file diff --git a/src/Nullinside.Api.TwitchBot/Bots/ABotRule.cs b/src/Nullinside.Api.TwitchBot/Bots/ABotRule.cs index 88f9314..5064fd5 100644 --- a/src/Nullinside.Api.TwitchBot/Bots/ABotRule.cs +++ b/src/Nullinside.Api.TwitchBot/Bots/ABotRule.cs @@ -68,9 +68,9 @@ where string.Equals(bannedUsers.ChannelId, channelId) && // Perform the ban and get the list of people actually banned IEnumerable confirmedBans = - await botProxy.BanChannelUsers(channelId, Constants.BOT_ID, bansToTry, reason, stoppingToken); + await botProxy.BanChannelUsers(channelId, Constants.BOT_ID, bansToTry, reason, stoppingToken).ConfigureAwait(false); - await db.SaveTwitchBans(channelId, users, reason, stoppingToken); + await db.SaveTwitchBans(channelId, users, reason, stoppingToken).ConfigureAwait(false); return confirmedBans; } } \ No newline at end of file diff --git a/src/Nullinside.Api.TwitchBot/ChatRules/AChatRule.cs b/src/Nullinside.Api.TwitchBot/ChatRules/AChatRule.cs index fcb080d..9ce52b2 100644 --- a/src/Nullinside.Api.TwitchBot/ChatRules/AChatRule.cs +++ b/src/Nullinside.Api.TwitchBot/ChatRules/AChatRule.cs @@ -29,7 +29,7 @@ public abstract Task Handle(string channelId, ITwitchApiProxy botProxy, Tw public async Task BanAndLog(string channelId, ITwitchApiProxy botProxy, IEnumerable<(string Id, string Username)> users, string reason, INullinsideContext db, CancellationToken stoppingToken = new()) { - await botProxy.BanChannelUsers(channelId, Constants.BOT_ID, users, reason, stoppingToken); - await db.SaveTwitchBans(channelId, users, reason, stoppingToken); + await botProxy.BanChannelUsers(channelId, Constants.BOT_ID, users, reason, stoppingToken).ConfigureAwait(false); + await db.SaveTwitchBans(channelId, users, reason, stoppingToken).ConfigureAwait(false); } } \ No newline at end of file diff --git a/src/Nullinside.Api.TwitchBot/ChatRules/BestCheapViewers.cs b/src/Nullinside.Api.TwitchBot/ChatRules/BestCheapViewers.cs index 934c555..66d4a83 100644 --- a/src/Nullinside.Api.TwitchBot/ChatRules/BestCheapViewers.cs +++ b/src/Nullinside.Api.TwitchBot/ChatRules/BestCheapViewers.cs @@ -59,8 +59,8 @@ public override async Task Handle(string channelId, ITwitchApiProxy botPro // If everything matches except 3 characters, take it. We will assume the 3 characters are "special" characters // used to confuse us. if (matches > expected.Length - 3) { - await BanAndLog(channelId, botProxy, new[] { (message.UserId, message.Username) }, - "[Bot] Spam (Best Cheap Viewers)", db, stoppingToken); + (string UserId, string Username)[] users = new[] { (message.UserId, message.Username) }; + await BanAndLog(channelId, botProxy, users, "[Bot] Spam (Best Cheap Viewers)", db, stoppingToken).ConfigureAwait(false); return false; } } diff --git a/src/Nullinside.Api.TwitchBot/ChatRules/Botsister.cs b/src/Nullinside.Api.TwitchBot/ChatRules/Botsister.cs index 4825059..1ffb69e 100644 --- a/src/Nullinside.Api.TwitchBot/ChatRules/Botsister.cs +++ b/src/Nullinside.Api.TwitchBot/ChatRules/Botsister.cs @@ -25,7 +25,7 @@ public override async Task Handle(string channelId, ITwitchApiProxy botPro // Message will start with any of these variations. if (message.IsFirstMessage && normalized.Contains("botsister")) { await BanAndLog(channelId, botProxy, new[] { (message.UserId, message.Username) }, - "[Bot] Spam (Botsister)", db, stoppingToken); + "[Bot] Spam (Botsister)", db, stoppingToken).ConfigureAwait(false); return false; } diff --git a/src/Nullinside.Api.TwitchBot/ChatRules/Discord.cs b/src/Nullinside.Api.TwitchBot/ChatRules/Discord.cs index 9e89876..9b84a29 100644 --- a/src/Nullinside.Api.TwitchBot/ChatRules/Discord.cs +++ b/src/Nullinside.Api.TwitchBot/ChatRules/Discord.cs @@ -48,7 +48,7 @@ public override async Task Handle(string channelId, ITwitchApiProxy botPro foreach (string phrase in _knownPhrases) { if (normalized.Contains(phrase, StringComparison.InvariantCultureIgnoreCase)) { await BanAndLog(channelId, botProxy, new[] { (message.UserId, message.Username) }, - "[Bot] Spam (Discord Scammers)", db, stoppingToken); + "[Bot] Spam (Discord Scammers)", db, stoppingToken).ConfigureAwait(false); return false; } } diff --git a/src/Nullinside.Api.TwitchBot/ChatRules/Dogehype.cs b/src/Nullinside.Api.TwitchBot/ChatRules/Dogehype.cs index dfe9e66..62b9253 100644 --- a/src/Nullinside.Api.TwitchBot/ChatRules/Dogehype.cs +++ b/src/Nullinside.Api.TwitchBot/ChatRules/Dogehype.cs @@ -25,7 +25,7 @@ public override async Task Handle(string channelId, ITwitchApiProxy botPro // Message will start with any of these variations. if (message.IsFirstMessage && normalized.Contains("dogehype")) { await BanAndLog(channelId, botProxy, new[] { (message.UserId, message.Username) }, - "[Bot] Spam (Dogehype)", db, stoppingToken); + "[Bot] Spam (Dogehype)", db, stoppingToken).ConfigureAwait(false); return false; } diff --git a/src/Nullinside.Api.TwitchBot/ChatRules/HostHub.cs b/src/Nullinside.Api.TwitchBot/ChatRules/HostHub.cs index 04d6b6e..8527e00 100644 --- a/src/Nullinside.Api.TwitchBot/ChatRules/HostHub.cs +++ b/src/Nullinside.Api.TwitchBot/ChatRules/HostHub.cs @@ -25,7 +25,7 @@ public override async Task Handle(string channelId, ITwitchApiProxy botPro // Message will contain the site name with different domains. if (message.IsFirstMessage && normalized.Contains("hosthub.")) { await BanAndLog(channelId, botProxy, new[] { (message.UserId, message.Username) }, - "[Bot] Spam (HostHub)", db, stoppingToken); + "[Bot] Spam (HostHub)", db, stoppingToken).ConfigureAwait(false); return false; } diff --git a/src/Nullinside.Api.TwitchBot/ChatRules/IfYouWantViewers.cs b/src/Nullinside.Api.TwitchBot/ChatRules/IfYouWantViewers.cs index 396d81e..01671c9 100644 --- a/src/Nullinside.Api.TwitchBot/ChatRules/IfYouWantViewers.cs +++ b/src/Nullinside.Api.TwitchBot/ChatRules/IfYouWantViewers.cs @@ -36,7 +36,7 @@ public override async Task Handle(string channelId, ITwitchApiProxy botPro foreach (string expected in Expected) { if (normalized.Contains(expected, StringComparison.InvariantCultureIgnoreCase)) { await BanAndLog(channelId, botProxy, new[] { (message.UserId, message.Username) }, - "[Bot] Spam (If You Want Viewers)", db, stoppingToken); + "[Bot] Spam (If You Want Viewers)", db, stoppingToken).ConfigureAwait(false); return false; } } diff --git a/src/Nullinside.Api.TwitchBot/ChatRules/Naked.cs b/src/Nullinside.Api.TwitchBot/ChatRules/Naked.cs index e33d357..3a589cd 100644 --- a/src/Nullinside.Api.TwitchBot/ChatRules/Naked.cs +++ b/src/Nullinside.Api.TwitchBot/ChatRules/Naked.cs @@ -25,7 +25,7 @@ public override async Task Handle(string channelId, ITwitchApiProxy botPro (message.Message.TrimStart().StartsWith(SPAM, StringComparison.InvariantCultureIgnoreCase) || message.Message.TrimStart().StartsWith(SPAM2, StringComparison.InvariantCultureIgnoreCase))) { await BanAndLog(channelId, botProxy, new[] { (message.UserId, message.Username) }, - "[Bot] Spam (Naked)", db, stoppingToken); + "[Bot] Spam (Naked)", db, stoppingToken).ConfigureAwait(false); return false; } diff --git a/src/Nullinside.Api.TwitchBot/ChatRules/Nezhna.cs b/src/Nullinside.Api.TwitchBot/ChatRules/Nezhna.cs index ffb3a46..72492a5 100644 --- a/src/Nullinside.Api.TwitchBot/ChatRules/Nezhna.cs +++ b/src/Nullinside.Api.TwitchBot/ChatRules/Nezhna.cs @@ -26,7 +26,7 @@ public override async Task Handle(string channelId, ITwitchApiProxy botPro if (message.Message.Contains(SPAM, StringComparison.InvariantCultureIgnoreCase)) { await BanAndLog(channelId, botProxy, new[] { (message.UserId, message.Username) }, - "[Bot] Spam (Nezhna)", db, stoppingToken); + "[Bot] Spam (Nezhna)", db, stoppingToken).ConfigureAwait(false); return false; } diff --git a/src/Nullinside.Api.TwitchBot/ChatRules/StreamRise.cs b/src/Nullinside.Api.TwitchBot/ChatRules/StreamRise.cs index 1f70b32..15b529b 100644 --- a/src/Nullinside.Api.TwitchBot/ChatRules/StreamRise.cs +++ b/src/Nullinside.Api.TwitchBot/ChatRules/StreamRise.cs @@ -26,7 +26,7 @@ public override async Task Handle(string channelId, ITwitchApiProxy botPro INullinsideContext db, CancellationToken stoppingToken = new()) { if (message.IsFirstMessage && SPAM.Equals(message.Message, StringComparison.InvariantCultureIgnoreCase)) { await BanAndLog(channelId, botProxy, new[] { (message.UserId, message.Username) }, - "[Bot] Spam (StreamRise)", db, stoppingToken); + "[Bot] Spam (StreamRise)", db, stoppingToken).ConfigureAwait(false); return false; } diff --git a/src/Nullinside.Api.TwitchBot/ChatRules/StreamViewers.cs b/src/Nullinside.Api.TwitchBot/ChatRules/StreamViewers.cs index c4bd2a6..d2de0a8 100644 --- a/src/Nullinside.Api.TwitchBot/ChatRules/StreamViewers.cs +++ b/src/Nullinside.Api.TwitchBot/ChatRules/StreamViewers.cs @@ -84,7 +84,7 @@ public override async Task Handle(string channelId, ITwitchApiProxy botPro // 3. In places where the characters didn't match, they only didn't match because the message used a non-english keyboard character. It was never because a different letter was in the position. // 4. It was probably an @ mention to another user where the @ was the first thing in the message. await BanAndLog(channelId, botProxy, new[] { (message.UserId, message.Username) }, - "[Bot] Spam (StreamViewers)", db, stoppingToken); + "[Bot] Spam (StreamViewers)", db, stoppingToken).ConfigureAwait(false); return false; } } \ No newline at end of file diff --git a/src/Nullinside.Api.TwitchBot/ChatRules/Streamboo.cs b/src/Nullinside.Api.TwitchBot/ChatRules/Streamboo.cs index 159c370..a4a441e 100644 --- a/src/Nullinside.Api.TwitchBot/ChatRules/Streamboo.cs +++ b/src/Nullinside.Api.TwitchBot/ChatRules/Streamboo.cs @@ -25,7 +25,7 @@ public override async Task Handle(string channelId, ITwitchApiProxy botPro // Message will start with any of these variations. if (message.IsFirstMessage && normalized.Contains("streamboo")) { await BanAndLog(channelId, botProxy, new[] { (message.UserId, message.Username) }, - "[Bot] Spam (Streamboo)", db, stoppingToken); + "[Bot] Spam (Streamboo)", db, stoppingToken).ConfigureAwait(false); return false; } diff --git a/src/Nullinside.Api.TwitchBot/ChatRules/TwitchChatMessageMonitorConsumer.cs b/src/Nullinside.Api.TwitchBot/ChatRules/TwitchChatMessageMonitorConsumer.cs index 2676dfd..efda372 100644 --- a/src/Nullinside.Api.TwitchBot/ChatRules/TwitchChatMessageMonitorConsumer.cs +++ b/src/Nullinside.Api.TwitchBot/ChatRules/TwitchChatMessageMonitorConsumer.cs @@ -145,7 +145,7 @@ private async void MainLoop() { } // Get the bot proxy - ITwitchApiProxy? botProxy = await _db.ConfigureBotApiAndRefreshToken(_api); + ITwitchApiProxy? botProxy = await _db.ConfigureBotApiAndRefreshToken(_api).ConfigureAwait(false); if (null == botProxy) { continue; } @@ -154,7 +154,7 @@ private async void MainLoop() { foreach (IChatRule rule in rules) { try { if (rule.ShouldRun(user.TwitchConfig)) { - if (!await rule.Handle(user.TwitchId, botProxy, new TwitchChatMessage(message), _db)) { + if (!await rule.Handle(user.TwitchId, botProxy, new TwitchChatMessage(message), _db).ConfigureAwait(false)) { break; } } diff --git a/src/Nullinside.Api.TwitchBot/Controllers/BotController.cs b/src/Nullinside.Api.TwitchBot/Controllers/BotController.cs index 6383755..14baf58 100644 --- a/src/Nullinside.Api.TwitchBot/Controllers/BotController.cs +++ b/src/Nullinside.Api.TwitchBot/Controllers/BotController.cs @@ -69,7 +69,7 @@ public BotController(INullinsideContext dbContext, IConfiguration configuration) } api.Configure(user); - IEnumerable mods = await api.GetChannelMods(user.TwitchId, token); + IEnumerable mods = await api.GetChannelMods(user.TwitchId, token).ConfigureAwait(false); return Ok(new { isMod = null != mods.FirstOrDefault(m => string.Equals(m.UserId, Constants.BOT_ID, StringComparison.InvariantCultureIgnoreCase)) @@ -97,7 +97,7 @@ public async Task ModBotAccount([FromServices] ITwitchApiProxy ap } api.Configure(user); - bool success = await api.AddChannelMod(user.TwitchId, Constants.BOT_ID, token); + bool success = await api.AddChannelMod(user.TwitchId, Constants.BOT_ID, token).ConfigureAwait(false); return Ok(success); } @@ -114,13 +114,13 @@ public async Task GetConfig(CancellationToken token) { return Unauthorized(); } - User? user = await _dbContext.Users.FirstOrDefaultAsync(u => u.Id == int.Parse(userId.Value) && !u.IsBanned, token); + User? user = await _dbContext.Users.FirstOrDefaultAsync(u => u.Id == int.Parse(userId.Value) && !u.IsBanned, token).ConfigureAwait(false); if (null == user) { return Unauthorized(); } Api.Model.Ddl.TwitchUserConfig? config = - await _dbContext.TwitchUserConfig.FirstOrDefaultAsync(c => c.UserId == user.Id, token); + await _dbContext.TwitchUserConfig.FirstOrDefaultAsync(c => c.UserId == user.Id, token).ConfigureAwait(false); if (null == config) { return Ok(new TwitchUserConfig { IsEnabled = true, @@ -144,7 +144,7 @@ public async Task GetConfig(CancellationToken token) { [Route("chat/timestamp")] public async Task GetLastChatTimestamp(CancellationToken token) { TwitchUserChatLogs? message = - await _dbContext.TwitchUserChatLogs.OrderByDescending(c => c.Timestamp).FirstOrDefaultAsync(token); + await _dbContext.TwitchUserChatLogs.OrderByDescending(c => c.Timestamp).FirstOrDefaultAsync(token).ConfigureAwait(false); if (null == message) { return StatusCode(500); } @@ -168,14 +168,14 @@ public async Task SetConfig(TwitchUserConfig config, Cancellation int userId = int.Parse(userIdClaim.Value); Api.Model.Ddl.TwitchUserConfig? configDb = - await _dbContext.TwitchUserConfig.FirstOrDefaultAsync(c => c.UserId == userId, token); + await _dbContext.TwitchUserConfig.FirstOrDefaultAsync(c => c.UserId == userId, token).ConfigureAwait(false); if (null == configDb) { await _dbContext.TwitchUserConfig.AddAsync(new Api.Model.Ddl.TwitchUserConfig { BanKnownBots = config.BanKnownBots, Enabled = config.IsEnabled, UserId = userId, UpdatedOn = DateTime.UtcNow - }, token); + }, token).ConfigureAwait(false); } else { configDb.Enabled = config.IsEnabled; @@ -183,7 +183,7 @@ await _dbContext.TwitchUserConfig.AddAsync(new Api.Model.Ddl.TwitchUserConfig { configDb.UpdatedOn = DateTime.UtcNow; } - await _dbContext.SaveChangesAsync(token); + await _dbContext.SaveChangesAsync(token).ConfigureAwait(false); return Ok(config); } } \ No newline at end of file diff --git a/src/Nullinside.Api.TwitchBot/Controllers/LoginController.cs b/src/Nullinside.Api.TwitchBot/Controllers/LoginController.cs index ccbee72..2c9c26f 100644 --- a/src/Nullinside.Api.TwitchBot/Controllers/LoginController.cs +++ b/src/Nullinside.Api.TwitchBot/Controllers/LoginController.cs @@ -61,22 +61,22 @@ public LoginController(INullinsideContext dbContext, IConfiguration configuratio [HttpGet] public async Task TwitchLogin([FromQuery] string code, [FromServices] ITwitchApiProxy api, CancellationToken token) { string? siteUrl = _configuration.GetValue("Api:SiteUrl"); - if (null == await api.CreateAccessToken(code, token)) { + if (null == await api.CreateAccessToken(code, token).ConfigureAwait(false)) { return Redirect($"{siteUrl}/twitch-bot/config?error={TwitchBotLoginErrors.TWITCH_ERROR_WITH_TOKEN}"); } - string? email = await api.GetUserEmail(token); + string? email = await api.GetUserEmail(token).ConfigureAwait(false); if (string.IsNullOrWhiteSpace(email)) { return Redirect($"{siteUrl}/twitch-bot/config?error={TwitchBotLoginErrors.TWITCH_ACCOUNT_HAS_NO_EMAIL}"); } - User? user = await api.GetUser(token); + User? user = await api.GetUser(token).ConfigureAwait(false); if (string.IsNullOrWhiteSpace(user?.Login) || string.IsNullOrWhiteSpace(user.Id)) { return Redirect($"{siteUrl}/twitch-bot/config?error={TwitchBotLoginErrors.INTERNAL_ERROR}"); } string? bearerToken = await UserHelpers.GenerateTokenAndSaveToDatabase(_dbContext, email, token, api.OAuth?.AccessToken, - api.OAuth?.RefreshToken, api.OAuth?.ExpiresUtc, user.Login, user.Id); + api.OAuth?.RefreshToken, api.OAuth?.ExpiresUtc, user.Login, user.Id).ConfigureAwait(false); if (string.IsNullOrWhiteSpace(bearerToken)) { return Redirect($"{siteUrl}/twitch-bot/config?error={TwitchBotLoginErrors.INTERNAL_ERROR}"); } diff --git a/src/Nullinside.Api.TwitchBot/Model/NullinsideContextExtensions.cs b/src/Nullinside.Api.TwitchBot/Model/NullinsideContextExtensions.cs index f516b36..ed58919 100644 --- a/src/Nullinside.Api.TwitchBot/Model/NullinsideContextExtensions.cs +++ b/src/Nullinside.Api.TwitchBot/Model/NullinsideContextExtensions.cs @@ -1,4 +1,5 @@ using System.Diagnostics; +using System.Runtime.CompilerServices; using log4net; @@ -63,19 +64,20 @@ public static void Configure(this ITwitchApiProxy api, User user) { bool failed = false; // Database locking requires transaction scope - await using IDbContextTransaction scope = await db.Database.BeginTransactionAsync(stoppingToken); + IDbContextTransaction scope = await db.Database.BeginTransactionAsync(stoppingToken).ConfigureAwait(false); + await using ConfiguredAsyncDisposable scope1 = scope.ConfigureAwait(false); // Perform the database lock using var dbLock = new DatabaseLock(db); var sw = new Stopwatch(); sw.Start(); - await dbLock.GetLock(BOT_REFRESH_TOKEN_LOCK_NAME, stoppingToken); + await dbLock.GetLock(BOT_REFRESH_TOKEN_LOCK_NAME, stoppingToken).ConfigureAwait(false); LOG.Info($"bot_refresh_token: {sw.Elapsed}"); sw.Stop(); try { // Get the user with the database lock acquired. - User? updatedUser = await db.Users.AsNoTracking().FirstOrDefaultAsync(u => u.Id == user.Id, stoppingToken); + User? updatedUser = await db.Users.AsNoTracking().FirstOrDefaultAsync(u => u.Id == user.Id, stoppingToken).ConfigureAwait(false); if (null == updatedUser) { return null; } @@ -87,20 +89,20 @@ public static void Configure(this ITwitchApiProxy api, User user) { } // Refresh the token with the Twitch API. - TwitchAccessToken? newToken = await api.RefreshAccessToken(stoppingToken); + TwitchAccessToken? newToken = await api.RefreshAccessToken(stoppingToken).ConfigureAwait(false); if (null == newToken) { return null; } // Update the credentials in the database. - await db.UpdateOAuthInDatabase(user.Id, newToken, stoppingToken); + await db.UpdateOAuthInDatabase(user.Id, newToken, stoppingToken).ConfigureAwait(false); return api; } catch { failed = true; } finally { - await dbLock.ReleaseLock(BOT_REFRESH_TOKEN_LOCK_NAME, stoppingToken); + await dbLock.ReleaseLock(BOT_REFRESH_TOKEN_LOCK_NAME, stoppingToken).ConfigureAwait(false); if (!failed) { scope.Commit(); @@ -108,7 +110,7 @@ public static void Configure(this ITwitchApiProxy api, User user) { } return null; - }); + }).ConfigureAwait(false); } /// @@ -121,7 +123,7 @@ public static void Configure(this ITwitchApiProxy api, User user) { /// The number of state entries written to the database. private static async Task UpdateOAuthInDatabase(this INullinsideContext db, int userId, TwitchAccessToken oAuth, CancellationToken stoppingToken = new()) { - User? row = await db.Users.FirstOrDefaultAsync(u => u.Id == userId && !u.IsBanned, stoppingToken); + User? row = await db.Users.FirstOrDefaultAsync(u => u.Id == userId && !u.IsBanned, stoppingToken).ConfigureAwait(false); if (null == row) { return -1; } @@ -129,7 +131,7 @@ private static async Task UpdateOAuthInDatabase(this INullinsideContext db, row.TwitchToken = oAuth.AccessToken; row.TwitchRefreshToken = oAuth.RefreshToken; row.TwitchTokenExpiration = oAuth.ExpiresUtc; - return await db.SaveChangesAsync(stoppingToken); + return await db.SaveChangesAsync(stoppingToken).ConfigureAwait(false); } /// @@ -143,12 +145,12 @@ private static async Task UpdateOAuthInDatabase(this INullinsideContext db, ITwitchApiProxy api, CancellationToken stoppingToken = new()) { // Get the bot user's information. User? botUser = await db.Users.AsNoTracking() - .FirstOrDefaultAsync(u => u.TwitchId == Constants.BOT_ID, stoppingToken); + .FirstOrDefaultAsync(u => u.TwitchId == Constants.BOT_ID, stoppingToken).ConfigureAwait(false); if (null == botUser) { throw new Exception("No bot user in database"); } - return await ConfigureApiAndRefreshToken(db, botUser, api, stoppingToken); + return await ConfigureApiAndRefreshToken(db, botUser, api, stoppingToken).ConfigureAwait(false); } /// @@ -166,7 +168,7 @@ await db.TwitchUser.UpsertRange( .ToList() ) .On(v => new { v.TwitchId }) - .RunAsync(stoppingToken); + .RunAsync(stoppingToken).ConfigureAwait(false); await db.TwitchBan.UpsertRange( bannedUsers.Select(i => new TwitchBan { @@ -177,6 +179,6 @@ await db.TwitchBan.UpsertRange( }).ToList() ) .On(v => new { v.ChannelId, v.BannedUserTwitchId, v.Timestamp }) - .RunAsync(stoppingToken); + .RunAsync(stoppingToken).ConfigureAwait(false); } } \ No newline at end of file diff --git a/src/Nullinside.Api.TwitchBot/Nullinside.Api.TwitchBot.csproj.DotSettings b/src/Nullinside.Api.TwitchBot/Nullinside.Api.TwitchBot.csproj.DotSettings new file mode 100644 index 0000000..d0d789b --- /dev/null +++ b/src/Nullinside.Api.TwitchBot/Nullinside.Api.TwitchBot.csproj.DotSettings @@ -0,0 +1,5 @@ + + Library \ No newline at end of file diff --git a/src/Nullinside.Api.TwitchBot/Services/MainService.cs b/src/Nullinside.Api.TwitchBot/Services/MainService.cs index 80eee9a..1323327 100644 --- a/src/Nullinside.Api.TwitchBot/Services/MainService.cs +++ b/src/Nullinside.Api.TwitchBot/Services/MainService.cs @@ -119,8 +119,8 @@ protected override Task ExecuteAsync(CancellationToken stoppingToken) { return Task.Run(async () => { while (!stoppingToken.IsCancellationRequested) { try { - ITwitchApiProxy? botApi = await _db.ConfigureBotApiAndRefreshToken(_api, stoppingToken); - if (null == botApi || !await botApi.GetAccessTokenIsValid(stoppingToken)) { + ITwitchApiProxy? botApi = await _db.ConfigureBotApiAndRefreshToken(_api, stoppingToken).ConfigureAwait(false); + if (null == botApi || !await botApi.GetAccessTokenIsValid(stoppingToken).ConfigureAwait(false)) { throw new Exception("Unable to log in as bot user"); } @@ -134,11 +134,11 @@ protected override Task ExecuteAsync(CancellationToken stoppingToken) { .Where(o => null != o) .ToArray()!; - await Main(stoppingToken); + await Main(stoppingToken).ConfigureAwait(false); } catch (Exception ex) { _log.Error("Main Failed", ex); - await Task.Delay(TimeSpan.FromSeconds(10), stoppingToken); + await Task.Delay(TimeSpan.FromSeconds(10), stoppingToken).ConfigureAwait(false); } } }, stoppingToken); @@ -152,24 +152,25 @@ protected override Task ExecuteAsync(CancellationToken stoppingToken) { try { while (!stoppingToken.IsCancellationRequested) { using (IServiceScope scope = _serviceScopeFactory.CreateAsyncScope()) { - await using (var db = scope.ServiceProvider.GetRequiredService()) { + var db = scope.ServiceProvider.GetRequiredService(); + await using (db.ConfigureAwait(false)) { // Send logs to database DumpLogsToDatabase(db); // Get the list of users with the bot enabled. - List? usersWithBotEnabled = await GetUsersWithBotEnabled(db, stoppingToken); + List? usersWithBotEnabled = await GetUsersWithBotEnabled(db, stoppingToken).ConfigureAwait(false); if (null == usersWithBotEnabled) { continue; } // Get the bot user's information. User? botUser = await db.Users.AsNoTracking() - .FirstOrDefaultAsync(u => u.TwitchId == Constants.BOT_ID, stoppingToken); + .FirstOrDefaultAsync(u => u.TwitchId == Constants.BOT_ID, stoppingToken).ConfigureAwait(false); if (null == botUser) { throw new Exception("No bot user in database"); } - ITwitchApiProxy? botApi = await db.ConfigureApiAndRefreshToken(botUser, _api, stoppingToken); + ITwitchApiProxy? botApi = await db.ConfigureApiAndRefreshToken(botUser, _api, stoppingToken).ConfigureAwait(false); if (null != botApi) { // Ensure the twitch client has the most up-to-date password _client.TwitchOAuthToken = botApi.OAuth?.AccessToken; @@ -177,11 +178,11 @@ protected override Task ExecuteAsync(CancellationToken stoppingToken) { // Trim channels that aren't live IEnumerable liveUsers = await botApi.GetChannelsLive(usersWithBotEnabled .Where(u => null != u.TwitchId) - .Select(u => u.TwitchId)!); + .Select(u => u.TwitchId)!).ConfigureAwait(false); usersWithBotEnabled = usersWithBotEnabled.Where(u => liveUsers.Contains(u.TwitchId)).ToList(); // Trim channels we aren't a mod in - IEnumerable moddedChannels = await botApi.GetUserModChannels(Constants.BOT_ID); + IEnumerable moddedChannels = await botApi.GetUserModChannels(Constants.BOT_ID).ConfigureAwait(false); usersWithBotEnabled = usersWithBotEnabled .Where(u => moddedChannels.Select(m => m.broadcaster_id).Contains(u.TwitchId)) .ToList(); @@ -194,15 +195,15 @@ protected override Task ExecuteAsync(CancellationToken stoppingToken) { continue; } - await _client.AddMessageCallback(channel.TwitchUsername, OnTwitchMessageReceived); - await _client.AddBannedCallback(channel.TwitchUsername, OnTwitchBanReceived); + await _client.AddMessageCallback(channel.TwitchUsername, OnTwitchMessageReceived).ConfigureAwait(false); + await _client.AddBannedCallback(channel.TwitchUsername, OnTwitchBanReceived).ConfigureAwait(false); } } // Spawn 5 workers to process all the live user's channels. Parallel.ForEach(usersWithBotEnabled, new ParallelOptions { MaxDegreeOfParallelism = 5 }, async user => { try { - await DoScan(user, botUser, stoppingToken); + await DoScan(user, botUser, stoppingToken).ConfigureAwait(false); } catch (Exception ex) { _log.Error($"Scan failed for {user.TwitchUsername}", ex); @@ -212,7 +213,7 @@ protected override Task ExecuteAsync(CancellationToken stoppingToken) { } // Wait between scans. We don't want to spam the API too much. - await Task.Delay(SCAN_LOOP_DELAY_MILLISECONDS, stoppingToken); + await Task.Delay(SCAN_LOOP_DELAY_MILLISECONDS, stoppingToken).ConfigureAwait(false); } } catch (Exception ex) { @@ -290,7 +291,7 @@ orderby user.TwitchLastScanned .Include(u => u.TwitchConfig) .Where(u => null != u.TwitchConfig && u.TwitchConfig.Enabled) .AsNoTracking() - .ToListAsync(stoppingToken); + .ToListAsync(stoppingToken).ConfigureAwait(false); } /// @@ -307,7 +308,7 @@ orderby user.TwitchLastScanned user.IsBanned select user) .AsNoTracking() - .ToListAsync(stoppingToken); + .ToListAsync(stoppingToken).ConfigureAwait(false); } /// @@ -325,7 +326,8 @@ private async Task DoScan(User user, User botUser, CancellationToken stoppingTok // Since each scan will happen on a separate thread, we need an individual scope and database reference // per invocation, allowing them to release each loop. using (IServiceScope scope = _serviceScopeFactory.CreateAsyncScope()) { - await using (var db = scope.ServiceProvider.GetRequiredService()) { + var db = scope.ServiceProvider.GetRequiredService(); + await using (db.ConfigureAwait(false)) { // Get the API _api.Configure(botUser); if (null == s_botRules || null == user.TwitchConfig) { @@ -336,7 +338,7 @@ private async Task DoScan(User user, User botUser, CancellationToken stoppingTok foreach (IBotRule rule in s_botRules) { try { if (rule.ShouldRun(user.TwitchConfig)) { - await rule.Handle(user, user.TwitchConfig, _api, db, stoppingToken); + await rule.Handle(user, user.TwitchConfig, _api, db, stoppingToken).ConfigureAwait(false); } } catch (Exception e) { @@ -345,13 +347,13 @@ private async Task DoScan(User user, User botUser, CancellationToken stoppingTok } // Log that we performed a scan to completion. - User? dbUser = await db.Users.FirstOrDefaultAsync(u => u.Id == user.Id, stoppingToken); + User? dbUser = await db.Users.FirstOrDefaultAsync(u => u.Id == user.Id, stoppingToken).ConfigureAwait(false); if (null == dbUser) { return; } dbUser.TwitchLastScanned = DateTime.UtcNow; - await db.SaveChangesAsync(stoppingToken); + await db.SaveChangesAsync(stoppingToken).ConfigureAwait(false); } } } diff --git a/src/nullinside-api b/src/nullinside-api index 6962fe9..30bc54a 160000 --- a/src/nullinside-api +++ b/src/nullinside-api @@ -1 +1 @@ -Subproject commit 6962fe933e6bfffb71a91293c522214491392980 +Subproject commit 30bc54a97a175b9626b8911a1070700c00ddd153