From 65b4c1fab7ef6f65d35a0a963252d147c92d99fe Mon Sep 17 00:00:00 2001 From: Kwoth Date: Fri, 2 Jul 2021 23:49:03 +0200 Subject: [PATCH] - Owner only attributes will now use fresh creds every time (no need for restart for owner only commands to start working once creds are changed) - setgame/setstream use the new pubsub (also setstream will actually apply to all shards now) - setgame/setstream moved to SelfService - small cleanup --- src/NadekoBot/Bot.cs | 61 +------------------ .../Common/Attributes/OwnerOnlyAttribute.cs | 4 +- .../Modules/Administration/SelfCommands.cs | 4 +- .../Services/PlayingRotateService.cs | 6 +- .../Administration/Services/SelfService.cs | 42 ++++++++++++- src/NadekoBot/Services/IStatsService.cs | 1 - src/NadekoBot/Services/Impl/StatsService.cs | 20 +++--- 7 files changed, 63 insertions(+), 75 deletions(-) diff --git a/src/NadekoBot/Bot.cs b/src/NadekoBot/Bot.cs index f472cdd8f..e7f41f664 100644 --- a/src/NadekoBot/Bot.cs +++ b/src/NadekoBot/Bot.cs @@ -6,8 +6,6 @@ using NadekoBot.Common; using NadekoBot.Services; using NadekoBot.Services.Database.Models; using NadekoBot.Extensions; -using Newtonsoft.Json; -using StackExchange.Redis; using System; using System.Collections.Generic; using System.Collections.Immutable; @@ -103,6 +101,7 @@ namespace NadekoBot var svcs = new ServiceCollection() .AddTransient(_ => _creds) // bot creds + .AddSingleton(_credsProvider) .AddSingleton(_db) // database .AddRedis(_creds.RedisOptions) // redis .AddSingleton(Client) // discord socket client @@ -282,7 +281,6 @@ namespace NadekoBot return Task.CompletedTask; } - // todo cleanup public async Task RunAsync() { var sw = Stopwatch.StartNew(); @@ -303,18 +301,13 @@ namespace NadekoBot sw.Stop(); Log.Information("Shard {ShardId} connected in {Elapsed:F2}s", Client.ShardId, sw.Elapsed.TotalSeconds); - - var stats = Services.GetRequiredService(); - stats.Initialize(); var commandHandler = Services.GetRequiredService(); // start handling messages received in commandhandler await commandHandler.StartHandling().ConfigureAwait(false); - _ = await _commandService.AddModulesAsync(this.GetType().GetTypeInfo().Assembly, Services) - .ConfigureAwait(false); - - HandleStatusChanges(); + await _commandService.AddModulesAsync(typeof(Bot).Assembly, Services); + IsReady = true; _ = Task.Run(ExecuteReadySubscriptions); Log.Information("Shard {ShardId} ready", Client.ShardId); @@ -356,53 +349,5 @@ namespace NadekoBot await RunAsync().ConfigureAwait(false); await Task.Delay(-1).ConfigureAwait(false); } - - - // todo status changes don't belong here - private void HandleStatusChanges() - { - var sub = Services.GetService().Redis.GetSubscriber(); - sub.Subscribe(Client.CurrentUser.Id + "_status.game_set", async (ch, game) => - { - try - { - var obj = new { Name = default(string), Activity = ActivityType.Playing }; - obj = JsonConvert.DeserializeAnonymousType(game, obj); - await Client.SetGameAsync(obj.Name, type: obj.Activity).ConfigureAwait(false); - } - catch (Exception ex) - { - Log.Warning(ex, "Error setting game"); - } - }, CommandFlags.FireAndForget); - - sub.Subscribe(Client.CurrentUser.Id + "_status.stream_set", async (ch, streamData) => - { - try - { - var obj = new { Name = "", Url = "" }; - obj = JsonConvert.DeserializeAnonymousType(streamData, obj); - await Client.SetGameAsync(obj.Name, obj.Url, ActivityType.Streaming).ConfigureAwait(false); - } - catch (Exception ex) - { - Log.Warning(ex, "Error setting stream"); - } - }, CommandFlags.FireAndForget); - } - - public Task SetGameAsync(string game, ActivityType type) - { - var obj = new { Name = game, Activity = type }; - var sub = Services.GetService().Redis.GetSubscriber(); - return sub.PublishAsync(Client.CurrentUser.Id + "_status.game_set", JsonConvert.SerializeObject(obj)); - } - - public Task SetStreamAsync(string name, string link) - { - var obj = new { Name = name, Url = link }; - var sub = Services.GetService().Redis.GetSubscriber(); - return sub.PublishAsync(Client.CurrentUser.Id + "_status.stream_set", JsonConvert.SerializeObject(obj)); - } } } diff --git a/src/NadekoBot/Common/Attributes/OwnerOnlyAttribute.cs b/src/NadekoBot/Common/Attributes/OwnerOnlyAttribute.cs index dc6c9f147..10da125b9 100644 --- a/src/NadekoBot/Common/Attributes/OwnerOnlyAttribute.cs +++ b/src/NadekoBot/Common/Attributes/OwnerOnlyAttribute.cs @@ -3,15 +3,17 @@ using System.Threading.Tasks; using Discord.Commands; using Microsoft.Extensions.DependencyInjection; using NadekoBot.Extensions; +using NadekoBot.Services; namespace NadekoBot.Common.Attributes { + // todo all getservice to getrequiredservice [AttributeUsage(AttributeTargets.Method | AttributeTargets.Class)] public sealed class OwnerOnlyAttribute : PreconditionAttribute { public override Task CheckPermissionsAsync(ICommandContext context, CommandInfo executingCommand, IServiceProvider services) { - var creds = services.GetService(); + var creds = services.GetRequiredService().GetCreds(); return Task.FromResult((creds.IsOwner(context.User) || context.Client.CurrentUser.Id == context.User.Id ? PreconditionResult.FromSuccess() : PreconditionResult.FromError("Not owner"))); } diff --git a/src/NadekoBot/Modules/Administration/SelfCommands.cs b/src/NadekoBot/Modules/Administration/SelfCommands.cs index b2f992cfa..6a7131605 100644 --- a/src/NadekoBot/Modules/Administration/SelfCommands.cs +++ b/src/NadekoBot/Modules/Administration/SelfCommands.cs @@ -432,7 +432,7 @@ namespace NadekoBot.Modules.Administration .WithDefault(Context) .Build(); - await _bot.SetGameAsync(game is null ? game : rep.Replace(game), type).ConfigureAwait(false); + await _service.SetGameAsync(game is null ? game : rep.Replace(game), type).ConfigureAwait(false); await ReplyConfirmLocalizedAsync("set_game").ConfigureAwait(false); } @@ -443,7 +443,7 @@ namespace NadekoBot.Modules.Administration { name = name ?? ""; - await _client.SetGameAsync(name, url, ActivityType.Streaming).ConfigureAwait(false); + await _service.SetStreamAsync(name, url).ConfigureAwait(false); await ReplyConfirmLocalizedAsync("set_stream").ConfigureAwait(false); } diff --git a/src/NadekoBot/Modules/Administration/Services/PlayingRotateService.cs b/src/NadekoBot/Modules/Administration/Services/PlayingRotateService.cs index bf662bff6..1e6e40a45 100644 --- a/src/NadekoBot/Modules/Administration/Services/PlayingRotateService.cs +++ b/src/NadekoBot/Modules/Administration/Services/PlayingRotateService.cs @@ -18,6 +18,7 @@ namespace NadekoBot.Modules.Administration.Services { private readonly Timer _t; private readonly BotConfigService _bss; + private readonly SelfService _selfService; private readonly Replacer _rep; private readonly DbService _db; private readonly Bot _bot; @@ -28,11 +29,12 @@ namespace NadekoBot.Modules.Administration.Services } public PlayingRotateService(DiscordSocketClient client, DbService db, Bot bot, - BotConfigService bss, IEnumerable phProviders) + BotConfigService bss, IEnumerable phProviders, SelfService selfService) { _db = db; _bot = bot; _bss = bss; + _selfService = selfService; if (client.ShardId == 0) { @@ -70,7 +72,7 @@ namespace NadekoBot.Modules.Administration.Services : rotatingStatuses[state.Index++]; var statusText = _rep.Replace(playingStatus.Status); - await _bot.SetGameAsync(statusText, playingStatus.Type); + await _selfService.SetGameAsync(statusText, playingStatus.Type); } catch (Exception ex) { diff --git a/src/NadekoBot/Modules/Administration/Services/SelfService.cs b/src/NadekoBot/Modules/Administration/Services/SelfService.cs index 0a5fcb7c8..cd5eeffad 100644 --- a/src/NadekoBot/Modules/Administration/Services/SelfService.cs +++ b/src/NadekoBot/Modules/Administration/Services/SelfService.cs @@ -14,6 +14,7 @@ using System.Threading; using System.Collections.Concurrent; using System; using System.Net.Http; +using NadekoBot.Common; using Serilog; namespace NadekoBot.Modules.Administration.Services @@ -38,10 +39,14 @@ namespace NadekoBot.Modules.Administration.Services private readonly IImageCache _imgs; private readonly IHttpClientFactory _httpFactory; private readonly BotConfigService _bss; + private readonly IPubSub _pubSub; + + //keys + private readonly TypedKey _activitySetKey; public SelfService(DiscordSocketClient client, CommandHandler cmdHandler, DbService db, IBotStrings strings, IBotCredentials creds, IDataCache cache, IHttpClientFactory factory, - BotConfigService bss) + BotConfigService bss, IPubSub pubSub) { _redis = cache.Redis; _cmdHandler = cmdHandler; @@ -53,7 +58,11 @@ namespace NadekoBot.Modules.Administration.Services _imgs = cache.LocalImages; _httpFactory = factory; _bss = bss; - + _pubSub = pubSub; + _activitySetKey = new("activity.set"); + + HandleStatusChanges(); + var sub = _redis.GetSubscriber(); if (_client.ShardId == 0) { @@ -384,5 +393,34 @@ namespace NadekoBot.Modules.Administration.Services _bss.ModifyConfig(config => { isToAll = config.ForwardToAllOwners = !config.ForwardToAllOwners; }); return isToAll; } + + // todo pubsub via IPubSub + private void HandleStatusChanges() + { + _pubSub.Sub(_activitySetKey, async data => + { + try + { + await _client.SetGameAsync(data.Name, data.Link, type: data.Type); + } + catch (Exception ex) + { + Log.Warning(ex, "Error setting activity"); + } + }); + } + + public Task SetGameAsync(string game, ActivityType type) + => _pubSub.Pub(_activitySetKey, new() {Name = game, Link = null, Type = type}); + + public Task SetStreamAsync(string name, string link) + => _pubSub.Pub(_activitySetKey, new() { Name = name, Link = link, Type = ActivityType.Streaming }); + + private class ActivityPubData + { + public string Name { get; init; } + public string Link { get; init; } + public ActivityType Type { get; init; } + } } } \ No newline at end of file diff --git a/src/NadekoBot/Services/IStatsService.cs b/src/NadekoBot/Services/IStatsService.cs index 797505274..f068c88fb 100644 --- a/src/NadekoBot/Services/IStatsService.cs +++ b/src/NadekoBot/Services/IStatsService.cs @@ -15,6 +15,5 @@ namespace NadekoBot.Services TimeSpan GetUptime(); string GetUptimeString(string separator = ", "); - void Initialize(); } } diff --git a/src/NadekoBot/Services/Impl/StatsService.cs b/src/NadekoBot/Services/Impl/StatsService.cs index 715aac1bb..3749705a9 100644 --- a/src/NadekoBot/Services/Impl/StatsService.cs +++ b/src/NadekoBot/Services/Impl/StatsService.cs @@ -8,17 +8,18 @@ using System.Linq; using System.Net.Http; using System.Threading; using System.Threading.Tasks; +using NadekoBot.Common.ModuleBehaviors; using Serilog; namespace NadekoBot.Services { - public class StatsService : IStatsService, INService + public class StatsService : IStatsService, IReadyExecutor, INService { private readonly DiscordSocketClient _client; private readonly IBotCredentials _creds; private readonly DateTime _started; - public const string BotVersion = "3.0.0-alpha1"; + public const string BotVersion = "3.0.0-beta1"; public string Author => "Kwoth#2452"; public string Library => "Discord.Net"; @@ -156,13 +157,6 @@ namespace NadekoBot.Services }, null, TimeSpan.FromMinutes(5), TimeSpan.FromHours(1)); } - public void Initialize() - { - var guilds = _client.Guilds.ToArray(); - _textChannels = guilds.Sum(g => g.Channels.Count(cx => cx is ITextChannel)); - _voiceChannels = guilds.Sum(g => g.Channels.Count(cx => cx is IVoiceChannel)); - } - public TimeSpan GetUptime() => DateTime.UtcNow - _started; @@ -171,5 +165,13 @@ namespace NadekoBot.Services var time = GetUptime(); return $"{time.Days} days{separator}{time.Hours} hours{separator}{time.Minutes} minutes"; } + + public Task OnReadyAsync() + { + var guilds = _client.Guilds; + _textChannels = guilds.Sum(g => g.Channels.Count(cx => cx is ITextChannel)); + _voiceChannels = guilds.Sum(g => g.Channels.Count(cx => cx is IVoiceChannel)); + return Task.CompletedTask; + } } }